UDT - UDP-based Data Transfer Protocol

Share your advanced PureBasic knowledge/code with the community.
ToniPB
User
User
Posts: 13
Joined: Tue Dec 16, 2014 3:44 am

UDT - UDP-based Data Transfer Protocol

Post by ToniPB »

Wikipedia - http://en.wikipedia.org/wiki/UDP-based_Data_Transfer_Protocol wrote:UDP-based Data Transfer Protocol (UDT), is a high performance data transfer protocol designed for transferring large volumetric datasets over high speed wide area networks.
Such settings are typically disadvantageous for the more common TCP protocol.

Initial versions were developed and tested on very high speed networks (1Gbit/s, 10Gbit/s, etc.),
however, recent versions of the protocol have been updated to support the commodity Internet as well.
For example, the protocol now supports rendezvous connection setup, which is a desirable feature for traversing NAT firewalls using UDP.

UDT has an open source implementation which can be found on SourceForge. It is one of the most popular solutions for supporting high speed data transfer and is part of many research projects and commercial products.
Website: http://udt.sourceforge.net/index.html
http://udt.sourceforge.net wrote: Key Features

Fast.
UDT is designed for extremely high speed networks and it has been used to support global data transfer of terabyte sized data sets. UDT is the core technology in many commercial WAN acceleration products.

Fair and Friendly.
Concurrent UDT flows can share the available bandwidth fairly, while UDT also leaves enough bandwidth for TCP.

Easy to Use.
UDT resides completely at the application level. Users can simply download the software and start to use it. No kernel reconfiguration is needed. In addition, UDT's API is very similar to the traditional socket API so that existing applications can be easily modified.

Highly Configurable.
UDT supports user defined congestion control algorithms with a simple configuration. Users may also modify UDT to suit various situations. This feature can also be used by students and researchers to investigate new control algorithms.

Firewall Friendly.
UDT is completely based on UDP, which makes it easier to traverse the firewall. In addition, multiple UDT flows can share a single UDP port, thus a firewall can open only one UDP port for all UDT connections. UDT also supports rendezvous connection setup.

UDT is a protocol and library; it does not provide a tool/application for end users directly. If you need a system software to support wide area data storage and distribution, please try Sector.
Before you can use this library you must change the header file.

add/replace the following code to this file: udt.h, Line 70

Code: Select all

#ifdef WIN32
   #ifndef __MINGW__
      // Explicitly define 32-bit and 64-bit numbers
      typedef __int32 int32_t;
      typedef __int64 int64_t;
      typedef unsigned __int32 uint32_t;
      #ifndef LEGACY_WIN32
         typedef unsigned __int64 uint64_t;
      #else
         // VC 6.0 does not support unsigned __int64: may cause potential problems.
         typedef __int64 uint64_t;
      #endif

#ifdef UDT_EXPORTS
	#define UDT_API __declspec(dllexport)
#else

	#ifdef UDT_CEXPORTS
		#define UDT_API
	#else
		#define UDT_API __declspec(dllimport)
	#endif
#endif

#ifdef UDT_CEXPORTS
	#define UDT_CAPI extern "C" __declspec(dllexport)
#endif

#else
#define UDT_API
#endif
#else
   #define UDT_API __attribute__ ((visibility("default")))
#endif
Add the following code to this file: udt.h, Line 366

Code: Select all

#ifdef UDT_CEXPORTS

UDT_CAPI int udt_startup();
UDT_CAPI int udt_cleanup();
UDT_CAPI UDTSOCKET udt_socket(int af, int type, int protocol);
UDT_CAPI int udt_bind(UDTSOCKET u, const struct sockaddr* name, int namelen);
UDT_CAPI int udt_bind2(UDTSOCKET u, UDPSOCKET udpsock);
UDT_CAPI int udt_listen(UDTSOCKET u, int backlog);
UDT_CAPI UDTSOCKET udt_accept(UDTSOCKET u, struct sockaddr* addr, int* addrlen);
UDT_CAPI int udt_connect(UDTSOCKET u, const struct sockaddr* name, int namelen);
UDT_CAPI int udt_close(UDTSOCKET u);
UDT_CAPI int udt_getpeername(UDTSOCKET u, struct sockaddr* name, int* namelen);
UDT_CAPI int udt_getsockname(UDTSOCKET u, struct sockaddr* name, int* namelen);
UDT_CAPI int udt_getsockopt(UDTSOCKET u, int level, SOCKOPT optname, void* optval, int* optlen);
UDT_CAPI int udt_setsockopt(UDTSOCKET u, int level, SOCKOPT optname, const void* optval, int optlen);
UDT_CAPI int udt_send(UDTSOCKET u, const char* buf, int len, int flags);
UDT_CAPI int udt_recv(UDTSOCKET u, char* buf, int len, int flags);
UDT_CAPI int udt_sendmsg(UDTSOCKET u, const char* buf, int len, int ttl = -1, bool inorder = false);
UDT_CAPI int udt_recvmsg(UDTSOCKET u, char* buf, int len);
UDT_CAPI int64_t udt_sendfile(UDTSOCKET u, const char* path, int64_t* offset, int64_t size, int block = 364000);
UDT_CAPI int64_t udt_recvfile(UDTSOCKET u, const char* path, int64_t* offset, int64_t size, int block = 7280000);

// select and selectEX are DEPRECATED; please use epoll. 
UDT_CAPI int udt_select(int nfds, UDSET* readfds, UDSET* writefds, UDSET* exceptfds, const struct timeval* timeout);

UDT_CAPI int udt_epoll_create();
UDT_CAPI int udt_epoll_add_usock(int eid, UDTSOCKET u, const int* events = NULL);
UDT_CAPI int udt_epoll_add_ssock(int eid, SYSSOCKET s, const int* events = NULL);
UDT_CAPI int udt_epoll_remove_usock(int eid, UDTSOCKET u);
UDT_CAPI int udt_epoll_remove_ssock(int eid, SYSSOCKET s);
UDT_CAPI int udt_epoll_wait(int eid, UDTSOCKET* readfds, int* rnum, UDTSOCKET* writefds, int* wnum, int64_t msTimeOut,
	SYSSOCKET* lrfds = NULL, int* lrnum = NULL, SYSSOCKET* lwfds = NULL, int* lwnum = NULL);
UDT_CAPI int udt_epoll_release(int eid);

UDT_CAPI ERRORINFO& udt_getlasterror();
UDT_CAPI int udt_getlasterror_code();
UDT_CAPI const char* udt_getlasterror_desc();

UDT_CAPI int udt_perfmon(UDTSOCKET u, TRACEINFO* perf, bool clear = true);
UDT_CAPI UDTSTATUS udt_getsockstate(UDTSOCKET u);

#endif
Add the following code to this file: api.cpp, Line 2392

Code: Select all

#ifdef UDT_CEXPORTS

int udt_startup()
{
	return CUDT::startup();
}

int udt_cleanup()
{
	return CUDT::cleanup();
}

UDTSOCKET udt_socket(int af, int type, int protocol)
{
	return CUDT::socket(af, type, protocol);
}

int udt_bind(UDTSOCKET u, const struct sockaddr* name, int namelen)
{
	return CUDT::bind(u, name, namelen);
}

int udt_bind2(UDTSOCKET u, UDPSOCKET udpsock)
{
	return CUDT::bind(u, udpsock);
}

int udt_listen(UDTSOCKET u, int backlog)
{
	return CUDT::listen(u, backlog);
}

UDTSOCKET udt_accept(UDTSOCKET u, struct sockaddr* addr, int* addrlen)
{
	return CUDT::accept(u, addr, addrlen);
}

int udt_connect(UDTSOCKET u, const struct sockaddr* name, int namelen)
{
	return CUDT::connect(u, name, namelen);
}

int udt_close(UDTSOCKET u)
{
	return CUDT::close(u);
}

int udt_getpeername(UDTSOCKET u, struct sockaddr* name, int* namelen)
{
	return CUDT::getpeername(u, name, namelen);
}

int udt_getsockname(UDTSOCKET u, struct sockaddr* name, int* namelen)
{
	return CUDT::getsockname(u, name, namelen);
}

int udt_getsockopt(UDTSOCKET u, int level, SOCKOPT optname, void* optval, int* optlen)
{
	return CUDT::getsockopt(u, level, optname, optval, optlen);
}

int udt_setsockopt(UDTSOCKET u, int level, SOCKOPT optname, const void* optval, int optlen)
{
	return CUDT::setsockopt(u, level, optname, optval, optlen);
}

int udt_send(UDTSOCKET u, const char* buf, int len, int flags)
{
	return CUDT::send(u, buf, len, flags);
}

int udt_recv(UDTSOCKET u, char* buf, int len, int flags)
{
	return CUDT::recv(u, buf, len, flags);
}

int udt_sendmsg(UDTSOCKET u, const char* buf, int len, int ttl, bool inorder)
{
	return CUDT::sendmsg(u, buf, len, ttl, inorder);
}

int udt_recvmsg(UDTSOCKET u, char* buf, int len)
{
	return CUDT::recvmsg(u, buf, len);
}

int64_t udt_sendfile(UDTSOCKET u, const char* path, int64_t* offset, int64_t size, int block)
{
	fstream ifs(path, ios::binary | ios::in);
	int64_t ret = CUDT::sendfile(u, ifs, *offset, size, block);
	ifs.close();
	return ret;
}

int64_t udt_recvfile(UDTSOCKET u, const char* path, int64_t* offset, int64_t size, int block)
{
	fstream ofs(path, ios::binary | ios::out);
	int64_t ret = CUDT::recvfile(u, ofs, *offset, size, block);
	ofs.close();
	return ret;
}

int udt_select(int nfds, UDSET* readfds, UDSET* writefds, UDSET* exceptfds, const struct timeval* timeout)
{
	return CUDT::select(nfds, readfds, writefds, exceptfds, timeout);
}

int udt_epoll_create()
{
	return CUDT::epoll_create();
}

int udt_epoll_add_usock(int eid, UDTSOCKET u, const int* events)
{
	return CUDT::epoll_add_usock(eid, u, events);
}

int udt_epoll_add_ssock(int eid, SYSSOCKET s, const int* events)
{
	return CUDT::epoll_add_ssock(eid, s, events);
}

int udt_epoll_remove_usock(int eid, UDTSOCKET u)
{
	return CUDT::epoll_remove_usock(eid, u);
}

int udt_epoll_remove_ssock(int eid, SYSSOCKET s)
{
	return CUDT::epoll_remove_ssock(eid, s);
}

int udt_epoll_wait(int eid, UDTSOCKET* readfds, int* rnum, UDTSOCKET* writefds, int* wnum, int64_t msTimeOut,
	SYSSOCKET* lrfds, int* lrnum, SYSSOCKET* lwfds, int* lwnum)
{
	// This API is an alternative format for epoll_wait, created for compatability with other languages.
	// Users need to pass in an array for holding the returned sockets, with the maximum array length
	// stored in *rnum, etc., which will be updated with returned number of sockets.

	set<UDTSOCKET> readset;
	set<UDTSOCKET> writeset;
	set<SYSSOCKET> lrset;
	set<SYSSOCKET> lwset;
	set<UDTSOCKET>* rval = NULL;
	set<UDTSOCKET>* wval = NULL;
	set<SYSSOCKET>* lrval = NULL;
	set<SYSSOCKET>* lwval = NULL;
	if ((readfds != NULL) && (rnum != NULL))
		rval = &readset;
	if ((writefds != NULL) && (wnum != NULL))
		wval = &writeset;
	if ((lrfds != NULL) && (lrnum != NULL))
		lrval = &lrset;
	if ((lwfds != NULL) && (lwnum != NULL))
		lwval = &lwset;

	int ret = CUDT::epoll_wait(eid, rval, wval, msTimeOut, lrval, lwval);
	if (ret > 0)
	{
		set<UDTSOCKET>::const_iterator i;
		SET_RESULT(rval, rnum, readfds, i);
		SET_RESULT(wval, wnum, writefds, i);
		set<SYSSOCKET>::const_iterator j;
		SET_RESULT(lrval, lrnum, lrfds, j);
		SET_RESULT(lwval, lwnum, lwfds, j);
	}
	return ret;
}

int udt_epoll_release(int eid)
{
	return CUDT::epoll_release(eid);
}

ERRORINFO& udt_getlasterror()
{
	return CUDT::getlasterror();
}

int udt_getlasterror_code()
{
	return CUDT::getlasterror().getErrorCode();
}

const char* udt_getlasterror_desc()
{
	return CUDT::getlasterror().getErrorMessage();
}

int udt_perfmon(UDTSOCKET u, TRACEINFO* perf, bool clear)
{
	return CUDT::perfmon(u, perf, clear);
}

UDTSTATUS udt_getsockstate(UDTSOCKET u)
{
	return CUDT::getsockstate(u);
}

#endif
You can now compile the library and use it in PureBasic.

udt pb header file: udt4.pbi

Code: Select all

EnableExplicit

; define some missing api constants
CompilerIf Defined(ADDRINFO, #PB_Structure) = 0
  
  Structure ADDRINFO Align #PB_Structure_AlignC
    ai_flags.l
    ai_family.l
    ai_socktype.l
    ai_protocol.l
    ai_addrlen.i
    *ai_canonname ; char * or PWSTR in unicode
    *ai_addr.SOCKADDR
    *ai_next.ADDRINFO
  EndStructure
  
  #AI_PASSIVE                = $00000001
  #AI_CANONNAME              = $00000002
  #AI_NUMERICHOST            = $00000004
  #AI_NUMERICSERV            = $00000008
  
  #AI_ALL                    = $00000100
  #AI_ADDRCONFIG             = $00000400
  #AI_V4MAPPED               = $00000800
  
  #AI_NON_AUTHORITATIVE      = $00004000
  #AI_SECURE                 = $00008000
  #AI_RETURN_PREFERRED_NAMES = $00010000
  
  #AI_FQDN                   = $00020000
  #AI_FILESERVER             = $00040000
  
  ; Flags for getnameinfo()
  
  #NI_NOFQDN        = $01  ; Only Return nodename portion For local hosts
  #NI_NUMERICHOST   = $02  ; Return numeric form of the host's address
  #NI_NAMEREQD      = $04  ; Error If the host's name not in DNS
  #NI_NUMERICSERV   = $08  ; Return numeric form of the service (port #)
  #NI_DGRAM         = $10  ; Service is a datagram service

  #NI_MAXHOST       = 1025  ;Max size of a fully-qualified domain name
  #NI_MAXSERV       = 32    ;Max size of a service name
  
CompilerEndIf

; UDTSOCKET = .l
; SOCKADDR
; UDPSOCKET = .l
; SOCKOPT = .l

#UDT_INVALID_SOCK = -1
#UDT_ERROR = -1

#UDT_SUCCESS = 0
#UDT_ECONNSETUP = 1000
#UDT_ENOSERVER = 1001
#UDT_ECONNREJ = 1002
#UDT_ESOCKFAIL = 1003
#UDT_ESECFAIL = 1004
#UDT_ECONNFAIL = 2000
#UDT_ECONNLOST = 2001
#UDT_ENOCONN = 2002
#UDT_ERESOURCE = 3000
#UDT_ETHREAD = 3001
#UDT_ENOBUF = 3002
#UDT_EFILE = 4000
#UDT_EINVRDOFF = 4001
#UDT_ERDPERM = 4002
#UDT_EINVWROFF = 4003
#UDT_EWRPERM = 4004
#UDT_EINVOP = 5000
#UDT_EBOUNDSOCK = 5001
#UDT_ECONNSOCK = 5002
#UDT_EINVPARAM = 5003
#UDT_EINVSOCK = 5004
#UDT_EUNBOUNDSOCK = 5005
#UDT_ENOLISTEN = 5006
#UDT_ERDVNOSERV = 5007
#UDT_ERDVUNBOUND = 5008
#UDT_ESTREAMILL = 5009
#UDT_EDGRAMILL = 5010
#UDT_EDUPLISTEN = 5011
#UDT_ELARGEMSG = 5012
#UDT_EINVPOLLID = 5013
#UDT_EASYNCFAIL = 6000
#UDT_EASYNCSND = 6001
#UDT_EASYNCRCV = 6002
#UDT_ETIMEOUT = 6003
#UDT_EPEERERR = 7000
#UDT_EUNKNOWN = -1

; UDTOpt
Enumeration
  #UDT_MSS             ; the Maximum Transfer Unit
  #UDT_SNDSYN          ; if sending is blocking
  #UDT_RCVSYN          ; if receiving is blocking
  #UDT_CC              ; custom congestion control algorithm
  #UDT_FC              ; Flight flag size (window size)
  #UDT_SNDBUF          ; maximum buffer in sending queue
  #UDT_RCVBUF          ; UDT receiving buffer size
  #UDT_LINGER          ; waiting for unsent data when closing
  #UDP_SNDBUF          ; UDP sending buffer size
  #UDP_RCVBUF          ; UDP receiving buffer size
  #UDT_MAXMSG          ; maximum datagram message size
  #UDT_MSGTTL          ; time-to-live of a datagram message
  #UDT_RENDEZVOUS      ; rendezvous connection mode
  #UDT_SNDTIMEO        ; send() timeout
  #UDT_RCVTIMEO        ; recv() timeout
  #UDT_REUSEADDR       ; reuse an existing port or create a new one
  #UDT_MAXBW           ; maximum bandwidth (bytes per second) that the connection can use
  #UDT_STATE           ; current socket state, see UDTSTATUS, read only
  #UDT_EVENT           ; current avalable events associated with the socket
  #UDT_SNDDATA         ; size of data in the sending buffer
  #UDT_RCVDATA         ; size of data available for recv
EndEnumeration

; EPOLLOpt
Enumeration
  ; this values are defined same As linux epoll.h
  ; so that If system values are used by mistake, they should have the same effect
  #UDT_EPOLL_IN = $1
  #UDT_EPOLL_OUT = $4
  #UDT_EPOLL_ERR = $8
EndEnumeration

; UDTSTATUS
Enumeration
  #UDTSTATUS_INIT = 1
  #UDTSTATUS_OPENED
  #UDTSTATUS_LISTENING
  #UDTSTATUS_CONNECTING
  #UDTSTATUS_CONNECTED
  #UDTSTATUS_BROKEN
  #UDTSTATUS_CLOSING
  #UDTSTATUS_CLOSED
  #UDTSTATUS_NONEXIST
EndEnumeration

Structure UDT_PERFMON_TRACEINFO Align #PB_Structure_AlignC
  ; global measurements
  msTimeStamp.q                   ; time since the UDT entity is started, in milliseconds
  pktSentTotal.q                  ; total number of sent data packets, including retransmissions
  pktRecvTotal.q                  ; total number of received packets
  pktSndLossTotal.l               ; total number of lost packets (sender side)
  pktRcvLossTotal.l               ; total number of lost packets (receiver side)
  pktRetransTotal.l               ; total number of retransmitted packets
  pktSentACKTotal.l               ; total number of sent ACK packets
  pktRecvACKTotal.l               ; total number of received ACK packets
  pktSentNAKTotal.l               ; total number of sent NAK packets
  pktRecvNAKTotal.l               ; total number of received NAK packets
  usSndDurationTotal.q            ; total time duration when UDT is sending data (idle time exclusive)
  
  ; local measurements
  pktSent.q                       ; number of sent data packets, including retransmissions
  pktRecv.q                       ; number of received packets
  pktSndLoss.l                    ; number of lost packets (sender side)
  pktRcvLoss.l                    ; number of lost packets (receiver side)
  pktRetrans.l                    ; number of retransmitted packets
  pktSentACK.l                    ; number of sent ACK packets
  pktRecvACK.l                    ; number of received ACK packets
  pktSentNAK.l                    ; number of sent NAK packets
  pktRecvNAK.l                    ; number of received NAK packets
  mbpsSendRate.d                  ; sending rate in Mb/s
  mbpsRecvRate.d                  ; receiving rate in Mb/s
  usSndDuration.q                 ; busy sending time (i.e., idle time exclusive)
  
  ; instant measurements
  usPktSndPeriod.d                ; packet sending period, in microseconds
  pktFlowWindow.l                 ; flow window size, in number of packets
  pktCongestionWindow.l           ; congestion window size, in number of packets
  pktFlightSize.l                 ; number of packets on flight
  msRTT.d                         ; RTT, in milliseconds
  mbpsBandwidth.d                 ; estimated bandwidth, in Mb/s
  byteAvailSndBuf.l               ; available UDT sender buffer size
  byteAvailRcvBuf.l               ; available UDT receiver buffer size
EndStructure

Prototype.l udt_startup()
Prototype.l udt_cleanup()
Prototype.l udt_socket(af.l, type.l, protocol.l)
Prototype.l udt_bind(u.l, *name.SOCKADDR, namelen.l)
Prototype.l udt_bind2(u.l, udpsock.i)
Prototype.l udt_listen(u.l, backlog.l)
Prototype.l udt_accept(u.l, *addr.SOCKADDR, *addrlen.LONG)
Prototype.l udt_connect(u.l, *name.SOCKADDR, namelen.l)
Prototype.l udt_close(u.l)
Prototype.l udt_getpeername(u.l, *name.SOCKADDR, *namelen.LONG)
Prototype.l udt_getsockname(u.l, *name.SOCKADDR, *namelen.LONG)
Prototype.l udt_getsockopt(u.l, level.l, optname.l, *optval, *optlen.LONG)
Prototype.l udt_setsockopt(u.l, level.l, optname.l, *optval, optlen.l)
Prototype.l udt_send(u.l, *buf, len.l, flags.l)
Prototype.l udt_recv(u.l, *buf, len.l, flags.l)
Prototype.l udt_sendmsg(u.l, *buf, len.l, ttl.l = -1, inorder.b = #False)
Prototype.l udt_recvmsg(u.l, *buf, len.l)
Prototype.q udt_sendfile(u.l, path.p-ascii, *offset.QUAD, size.q, block.l = 364000)
Prototype.q udt_recvfile(u.l, path.p-ascii, *offset.QUAD, size.q, block.l = 7280000)

; select and selectEX are DEPRECATED; please use epoll. 
Prototype.l udt_select(nfds.l, *readfds, *writefds, *exceptfds, *timeout.TIMEVAL)

Prototype.l udt_epoll_create()
Prototype.l udt_epoll_add_usock(eid.l, u.l, *events.LONG = 0)
Prototype.l udt_epoll_add_ssock(eid.l, s.i, *events.LONG = 0)
Prototype.l udt_epoll_remove_usock(eid.l, u.l)
Prototype.l udt_epoll_remove_ssock(eid.l, s.i)
Prototype.l udt_epoll_wait(eid.l, *readfds.LONG, *rnum.LONG, *writefds.LONG, *wnum.LONG, msTimeOut.q, *lrfds.INTEGER = 0, *lrnum.LONG = 0, *lwfds.INTEGER = 0, *lwnum.LONG = 0)
Prototype.l udt_epoll_release(eid.l)

Prototype.i udt_getlasterror()        ; returns ERRORINFO&
Prototype.l udt_getlasterror_code()
Prototype.i udt_getlasterror_desc()   ; returns const char*

Prototype.l udt_perfmon(u.l, *perf.UDT_PERFMON_TRACEINFO, clear.b = #True)

Prototype.l udt_getsockstate(u.l)

Global udt_accept.udt_accept
Global udt_bind2.udt_bind2
Global udt_bind.udt_bind
Global udt_cleanup.udt_cleanup
Global udt_close.udt_close
Global udt_connect.udt_connect
Global udt_epoll_add_ssock.udt_epoll_add_ssock
Global udt_epoll_add_usock.udt_epoll_add_usock
Global udt_epoll_create.udt_epoll_create
Global udt_epoll_release.udt_epoll_release
Global udt_epoll_remove_ssock.udt_epoll_remove_ssock
Global udt_epoll_remove_usock.udt_epoll_remove_usock
Global udt_epoll_wait.udt_epoll_wait
Global udt_getlasterror.udt_getlasterror
Global udt_getlasterror_code.udt_getlasterror_code
Global udt_getlasterror_desc.udt_getlasterror_desc
Global udt_getpeername.udt_getpeername
Global udt_getsockname.udt_getsockname
Global udt_getsockopt.udt_getsockopt
Global udt_getsockstate.udt_getsockstate
Global udt_listen.udt_listen
Global udt_perfmon.udt_perfmon
Global udt_recv.udt_recv
Global udt_recvfile.udt_recvfile
Global udt_recvmsg.udt_recvmsg
Global udt_select.udt_select
Global udt_send.udt_send
Global udt_sendfile.udt_sendfile
Global udt_sendmsg.udt_sendmsg
Global udt_setsockopt.udt_setsockopt
Global udt_socket.udt_socket
Global udt_startup.udt_startup

Procedure.i LoadUDT4DLL(Dll.s)
  Protected hDLL.i
  
  hDLL = OpenLibrary(#PB_Any, Dll)
  If hDLL <> 0
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
      udt_accept = GetFunction(hDLL, "_udt_accept@12")
      udt_bind2 = GetFunction(hDLL, "_udt_bind2@8")
      udt_bind = GetFunction(hDLL, "_udt_bind@12")
      udt_cleanup = GetFunction(hDLL, "_udt_cleanup@0")
      udt_close = GetFunction(hDLL, "_udt_close@4")
      udt_connect = GetFunction(hDLL, "_udt_connect@12")
      udt_epoll_add_ssock = GetFunction(hDLL, "_udt_epoll_add_ssock@12")
      udt_epoll_add_usock = GetFunction(hDLL, "_udt_epoll_add_usock@12")
      udt_epoll_create = GetFunction(hDLL, "_udt_epoll_create@0")
      udt_epoll_release = GetFunction(hDLL, "_udt_epoll_release@4")
      udt_epoll_remove_ssock = GetFunction(hDLL, "_udt_epoll_remove_ssock@8")
      udt_epoll_remove_usock = GetFunction(hDLL, "_udt_epoll_remove_usock@8")
      udt_epoll_wait = GetFunction(hDLL, "_udt_epoll_wait@44")
      udt_getlasterror = GetFunction(hDLL, "_udt_getlasterror@0")
      udt_getlasterror_code = GetFunction(hDLL, "_udt_getlasterror_code@0")
      udt_getlasterror_desc = GetFunction(hDLL, "_udt_getlasterror_desc@0")
      udt_getpeername = GetFunction(hDLL, "_udt_getpeername@12")
      udt_getsockname = GetFunction(hDLL, "_udt_getsockname@12")
      udt_getsockopt = GetFunction(hDLL, "_udt_getsockopt@20")
      udt_getsockstate = GetFunction(hDLL, "_udt_getsockstate@4")
      udt_listen = GetFunction(hDLL, "_udt_listen@8")
      udt_perfmon = GetFunction(hDLL, "_udt_perfmon@12")
      udt_recv = GetFunction(hDLL, "_udt_recv@16")
      udt_recvfile = GetFunction(hDLL, "_udt_recvfile@24")
      udt_recvmsg = GetFunction(hDLL, "_udt_recvmsg@12")
      udt_select = GetFunction(hDLL, "_udt_select@20")
      udt_send = GetFunction(hDLL, "_udt_send@16")
      udt_sendfile = GetFunction(hDLL, "_udt_sendfile@24")
      udt_sendmsg = GetFunction(hDLL, "_udt_sendmsg@20")
      udt_setsockopt = GetFunction(hDLL, "_udt_setsockopt@20")
      udt_socket = GetFunction(hDLL, "_udt_socket@12")
      udt_startup = GetFunction(hDLL, "_udt_startup@0")

    CompilerElse
      udt_accept = GetFunction(hDLL, "udt_accept")
      udt_bind = GetFunction(hDLL, "udt_bind")
      udt_bind2 = GetFunction(hDLL, "udt_bind2")
      udt_cleanup = GetFunction(hDLL, "udt_cleanup")
      udt_close = GetFunction(hDLL, "udt_close")
      udt_connect = GetFunction(hDLL, "udt_connect")
      udt_epoll_add_ssock = GetFunction(hDLL, "udt_epoll_add_ssock")
      udt_epoll_add_usock = GetFunction(hDLL, "udt_epoll_add_usock")
      udt_epoll_create = GetFunction(hDLL, "udt_epoll_create")
      udt_epoll_release = GetFunction(hDLL, "udt_epoll_release")
      udt_epoll_remove_ssock = GetFunction(hDLL, "udt_epoll_remove_ssock")
      udt_epoll_remove_usock = GetFunction(hDLL, "udt_epoll_remove_usock")
      udt_epoll_wait = GetFunction(hDLL, "udt_epoll_wait")
      udt_getlasterror = GetFunction(hDLL, "udt_getlasterror")
      udt_getlasterror_code = GetFunction(hDLL, "udt_getlasterror_code")
      udt_getlasterror_desc = GetFunction(hDLL, "udt_getlasterror_desc")
      udt_getpeername = GetFunction(hDLL, "udt_getpeername")
      udt_getsockname = GetFunction(hDLL, "udt_getsockname")
      udt_getsockopt = GetFunction(hDLL, "udt_getsockopt")
      udt_getsockstate = GetFunction(hDLL, "udt_getsockstate")
      udt_listen = GetFunction(hDLL, "udt_listen")
      udt_perfmon = GetFunction(hDLL, "udt_perfmon")
      udt_recv = GetFunction(hDLL, "udt_recv")
      udt_recvfile = GetFunction(hDLL, "udt_recvfile")
      udt_recvmsg = GetFunction(hDLL, "udt_recvmsg")
      udt_select = GetFunction(hDLL, "udt_select")
      udt_send = GetFunction(hDLL, "udt_send")
      udt_sendfile = GetFunction(hDLL, "udt_sendfile")
      udt_sendmsg = GetFunction(hDLL, "udt_sendmsg")
      udt_setsockopt = GetFunction(hDLL, "udt_setsockopt")
      udt_socket = GetFunction(hDLL, "udt_socket")
      udt_startup = GetFunction(hDLL, "udt_startup")
    CompilerEndIf
    
    ProcedureReturn hDLL
  EndIf
  
  ProcedureReturn #False
EndProcedure

Procedure.s udt_helper_GetLastErrorMessage()
  Protected result.s
  
  If udt_getlasterror_desc
    Protected *p = udt_getlasterror_desc()
    If *p
      result = PeekS(*p, -1, #PB_Ascii)
    EndIf
  EndIf
  
  ProcedureReturn  result
EndProcedure
Examples

appclient.pb

Code: Select all

XIncludeFile "ud4.pbi"

EnableExplicit

CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
  #UDT_DLL = "..\udt\udt_rl_x86_md_c.dll"
CompilerElse
  #UDT_DLL = "..\udt\udt_rl_amd64_md_c.dll"
CompilerEndIf

Macro _Cleanup()
  
  If udt_cleanup
    udt_cleanup()
  EndIf
  
EndMacro

Macro _ConsoleEnd()
  PrintN("")
  PrintN("Press enter to exit...")
  Input()
  _Cleanup()
  End
EndMacro

Procedure monitor(s.l)
  Protected u.l = s
  
  Protected perf.UDT_PERFMON_TRACEINFO
  
  PrintN("SendRate(Mb/s)"+#TAB$+"RTT(ms)"+#TAB$+"CWnd"+#TAB$+"PktSndPeriod(us)"+#TAB$+"RecvACK"+#TAB$+"RecvNAK")
  
  While 1
    Delay(1000)
    
    If udt_perfmon(u, @perf) = #UDT_ERROR
      PrintN("perfmon: "+udt_helper_GetLastErrorMessage())
      Break
    EndIf
    
    PrintN(StrD(perf\mbpsSendRate,3)+#TAB$+#TAB$+StrD(perf\msRTT,3)+#TAB$+Str(perf\pktCongestionWindow)+#TAB$+StrD(perf\usPktSndPeriod,3)+#TAB$+#TAB$+#TAB$+Str(perf\pktRecvACK)+#TAB$+Str(perf\pktRecvNAK))
  Wend
  
  ProcedureReturn 0
EndProcedure

If LoadUDT4DLL(#UDT_DLL) = #False
  MessageRequester("Error", "Failed to load udt dll!", #MB_ICONERROR)
  End
EndIf

udt_startup()

If OpenConsole()
  Define ServerIP.s = "127.0.0.1"
  Define ServerPort.l = 9000
  Define strServerPort.s = Str(ServerPort)
  
  Define hints.ADDRINFO
  Define *local.ADDRINFO
  Define *peer.ADDRINFO
  
  hints\ai_flags = #AI_PASSIVE
  hints\ai_family = #AF_INET
  hints\ai_socktype = #SOCK_STREAM
  
  If getaddrinfo_(0, strServerPort, @hints, @*local) <> 0
    PrintN("incorrect network address.")
    _ConsoleEnd()
  EndIf
  
  Define client.l = udt_socket(*local\ai_family, *local\ai_socktype, *local\ai_protocol)
  
  ;Windows UDP issue
  ; For better performance, modify HKLM\System\CurrentControlSet\Services\Afd\Parameters\FastSendDatagramThreshold
  Define opval_mss.l = 1052
  udt_setsockopt(client, 0, #UDT_MSS, @opval_mss, 4)
  
  FreeAddrInfo_(*local)
  
  
  If getaddrinfo_(ServerIP, strServerPort, @hints, @*peer) <> 0
    PrintN("incorrect server/peer address. "+ServerIP+":"+strServerPort)
    _ConsoleEnd()
  EndIf
  
  ; connect to the server, implict bind
  If udt_connect(client, *peer\ai_addr, *peer\ai_addrlen) = #UDT_ERROR
    PrintN("connect: "+udt_helper_GetLastErrorMessage())
    _ConsoleEnd()
  EndIf
  
  FreeAddrInfo_(*peer)
  
  Define size.l = 100000
  Define *data = AllocateMemory(size)
  
  CreateThread(@monitor(), client)
  
  Define i.l = 0
  
  For i = 0 To 1000000-1
    Define ssize.l = 0
    Define ss.l
    
    While ssize < size
      ss = udt_send(client, *data + ssize, size - ssize, 0)
      
      If ss = #UDT_ERROR
        PrintN("send: "+udt_helper_GetLastErrorMessage())
        Break
      EndIf
      
      ssize + ss
    Wend
    
    If ssize < size
      Break
    EndIf
    
  Next i
  
  udt_close(client)
  
  FreeMemory(*data)
  
EndIf

_ConsoleEnd()
appserver.pb

Code: Select all

XIncludeFile "ud4.pbi"

EnableExplicit

CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
  #UDT_DLL = "..\udt\udt_rl_x86_md_c.dll"
CompilerElse
  #UDT_DLL = "..\udt\udt_rl_amd64_md_c.dll"
CompilerEndIf

Macro _Cleanup()
  
  If udt_cleanup
    udt_cleanup()
  EndIf
  
EndMacro

Macro _ConsoleEnd()
  PrintN("")
  PrintN("Press enter to exit...")
  Input()
  _Cleanup()
  End
EndMacro

Procedure recvdata(usocket.l)
  
  Protected recver.l = usocket
  
  Protected *data
  Protected size = 100000
  *data = AllocateMemory(size)
  
  While 1
    Protected rsize.l = 0
    Protected rs.l
    
    While rsize < size
      Protected rcv_size.l
      Protected var_size.l = 4
      
      udt_getsockopt(recver, 0, #UDT_RCVDATA, @rcv_size, @var_size)
      rs = udt_recv(recver, *data + rsize, size - rsize, 0)
      
      If rs = #UDT_ERROR
        PrintN("recv: "+udt_helper_GetLastErrorMessage())
        Break
      EndIf
      
      rsize + rs
    Wend
    
    If rsize < size
      Break
    EndIf
    
  Wend
  
  FreeMemory(*data)
  
  udt_close(recver)
  
  ProcedureReturn 0
EndProcedure

If LoadUDT4DLL(#UDT_DLL) = #False
  MessageRequester("Error", "Failed to load udt dll!", #MB_ICONERROR)
  End
EndIf

udt_startup()

If OpenConsole()
  Define ServerPort.l = 9000
  Define strServerPort.s = Str(ServerPort)
  
  Define hints.ADDRINFO
  Define *res.ADDRINFO
  
  hints\ai_flags = #AI_PASSIVE
  hints\ai_family = #AF_INET
  hints\ai_socktype = #SOCK_STREAM
  
  If getaddrinfo_(0, strServerPort, @hints, @*res) <> 0
    PrintN("illegal port number or port is busy.")
    _ConsoleEnd()
  EndIf
  
  Define serv.l = udt_socket(*res\ai_family, *res\ai_socktype, *res\ai_protocol)
  
  If udt_bind(serv, *res\ai_addr, *res\ai_addrlen) <> #UDT_SUCCESS
    PrintN("bind : "+udt_helper_GetLastErrorMessage())
    _ConsoleEnd()
  EndIf
  
  FreeAddrInfo_(*res)
  
  PrintN("server is ready at port: "+strServerPort)
  
  If udt_listen(serv, 10) <> #UDT_SUCCESS
    PrintN("listen: " +udt_helper_GetLastErrorMessage())
    _ConsoleEnd()
  EndIf
  
  Define clientaddr.SOCKADDR
  Define addrlen.l = SizeOf(clientaddr)
  Define recver.l
  
  Define clienthost.s = Space(#NI_MAXHOST)
  Define clientservice.s = Space(#NI_MAXSERV)
  
  While 1
    recver = udt_accept(serv, @clientaddr, @addrlen)
    
    If recver = #UDT_INVALID_SOCK
      PrintN("accept: " +udt_helper_GetLastErrorMessage())
      _ConsoleEnd()
    EndIf
    
    getnameinfo_(@clientaddr, addrlen, @clienthost, #NI_MAXHOST, @clientservice, #NI_MAXSERV, #NI_NUMERICHOST|#NI_NUMERICSERV)
    PrintN("new connection: "+clienthost+":"+clientservice)
    
    CreateThread(@recvdata(), recver)
  Wend
  
  udt_close(serv)
  
EndIf

_ConsoleEnd()