4 SDL_net: An example cross-platform network library for use with SDL
5 Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
6 Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com>
8 This software is provided 'as-is', without any express or implied
9 warranty. In no event will the authors be held liable for any damages
10 arising from the use of this software.
12 Permission is granted to anyone to use this software for any purpose,
13 including commercial applications, and to alter it and redistribute it
14 freely, subject to the following restrictions:
16 1. The origin of this software must not be misrepresented; you must not
17 claim that you wrote the original software. If you use this software
18 in a product, an acknowledgment in the product documentation would be
19 appreciated but is not required.
20 2. Altered source versions must be plainly marked as such, and must not be
21 misrepresented as being the original software.
22 3. This notice may not be removed or altered from any source distribution.
40 PSDLNet_version = ^TSDLNet_version;
41 TSDLNet_version = record
47 {$ELSE} {* WITHOUT_SDL *}
53 PSDLNet_version = ^TSDLNet_version;
54 TSDLNet_version = TSDL_Version;
56 {$ENDIF} {* WITHOUT_SDL *}
58 {* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL *}
61 NET_LibName = 'SDL2_net.dll';
64 NET_LibName = 'SDL2_net.dll';
70 NET_LibName = 'libSDL2_net.dylib';
73 NET_LibName = 'libSDL2_net.so';
75 NET_LibName = 'libSDL2_net.so.0';
81 NET_LibName = 'SDL2_net';
83 {$linklib libSDL2_net}
87 SDL_NET_MAJOR_VERSION = 2;
88 SDL_NET_MINOR_VERSION = 0;
89 SDL_NET_PATCHLEVEL = 0;
91 {* This macro can be used to fill a version structure with the compile-time
92 * version of the SDL_net library.
94 procedure SDL_NET_VERSION(var x: TSDLNet_Version);
96 {* This function gets the version of the dynamically linked SDL_net library.
97 it should NOT be used to fill a version structure, instead you should
98 use the SDL_NET_VERSION() macro.
100 function SDLNet_Linked_Version(): TSDLNET_Version cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_Linked_Version' {$ENDIF} {$ENDIF};
102 {* Initialize/Cleanup the network API
103 SDL must be initialized before calls to functions in this library,
104 because this library uses utility functions from the SDL library.
106 function SDLNet_Init(): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_Init' {$ENDIF} {$ENDIF};
107 procedure SDLNet_Quit() cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_Quit' {$ENDIF} {$ENDIF};
109 {***********************************************************************}
110 {* IPv4 hostname resolution API *}
111 {***********************************************************************}
113 PIPAdress = ^TIPAdress;
115 host: UInt32; {* 32-bit IPv4 host address *}
116 port: UInt16; {* 16-bit protocol port *}
119 {* Resolve a host name and port to an IP address in network form.
120 If the function succeeds, it will return 0.
121 If the host couldn't be resolved, the host portion of the returned
122 address will be INADDR_NONE, and the function will return -1.
123 If 'host' is NULL, the resolved host will be set to INADDR_ANY.
126 INADDR_ANY = $00000000;
127 INADDR_NONE = $FFFFFFFF;
128 INADDR_LOOPBACK = $7f000001;
129 INADDR_BROADCAST = $FFFFFFFF;
131 function SDLNet_ResolveHost(address: PIPAdress; host: PAnsiChar; port: UInt16): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_ResolveHost' {$ENDIF} {$ENDIF};
133 {* Resolve an ip address to a host name in canonical form.
134 If the ip couldn't be resolved, this function returns NULL,
135 otherwise a pointer to a static buffer containing the hostname
136 is returned. Note that this function is not thread-safe.
138 function SDLNet_ResolveIP(const ip: PIPAdress): PAnsiChar cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_ResolveIP' {$ENDIF} {$ENDIF};
140 {* Get the addresses of network interfaces on this system.
141 This returns the number of addresses saved in 'addresses'
143 function SDLNet_GetLocalAddresses(addresses: PIPAdress; maxcount: Integer): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_GetLocalAddresses' {$ENDIF} {$ENDIF};
145 {***********************************************************************}
146 {* TCP network API *}
147 {***********************************************************************}
149 PTCPsocket = ^TTCPsocket;
150 TTCPsocket = Pointer; //todo
152 {* Open a TCP network socket
153 If ip.host is INADDR_NONE or INADDR_ANY, this creates a local server
154 socket on the given port, otherwise a TCP connection to the remote
155 host and port is attempted. The address passed in should already be
156 swapped to network byte order (addresses returned from
157 SDLNet_ResolveHost() are already in the correct form).
158 The newly created socket is returned, or NULL if there was an error.
160 function SDLNet_TCP_Open(ip: PIPAdress): TTCPsocket cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_TCP_Open' {$ENDIF} {$ENDIF};
162 {* Accept an incoming connection on the given server socket.
163 The newly created socket is returned, or NULL if there was an error.
165 function SDLNet_TCP_Accept(server: TTCPsocket): TTCPsocket cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_TCP_Accept' {$ENDIF} {$ENDIF};
167 {* Get the IP address of the remote system associated with the socket.
168 If the socket is a server socket, this function returns NULL.
170 function SDLNet_TCP_GetPeerAddress(sock: TTCPsocket): PIPAdress cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_TCP_GetPeerAddress' {$ENDIF} {$ENDIF};
172 {* Send 'len' bytes of 'data' over the non-server socket 'sock'
173 This function returns the actual amount of data sent. If the return value
174 is less than the amount of data sent, then either the remote connection was
175 closed, or an unknown socket error occurred.
177 function SDLNet_TCP_Send(sock: TTCPsocket; data: Pointer; len: Integer): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_TCP_Send' {$ENDIF} {$ENDIF};
179 {* Receive up to 'maxlen' bytes of data over the non-server socket 'sock',
180 and store them in the buffer pointed to by 'data'.
181 This function returns the actual amount of data received. If the return
182 value is less than or equal to zero, then either the remote connection was
183 closed, or an unknown socket error occurred.
185 function SDLNet_TCP_Recv(sock: TTCPsocket; data: Pointer; maxlen: Integer): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_TCP_Recv' {$ENDIF} {$ENDIF};
187 {* Close a TCP network socket *}
188 procedure SDLNet_TCP_Close(sock: TTCPsocket) cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_TCP_Close' {$ENDIF} {$ENDIF};
191 {***********************************************************************}
192 {* UDP network API *}
193 {***********************************************************************}
196 {* The maximum channels on a a UDP socket *}
197 SDLNET_MAX_UDPCHANNELS = 32;
198 {* The maximum addresses bound to a single UDP socket channel *}
199 SDLNET_MAX_UDPADDRESSES = 4;
202 PUDPsocket = ^TUDPsocket;
203 TUDPsocket = Pointer; //todo
205 PPUDPpacket = ^PUDPpacket;
206 PUDPpacket = ^TUDPpacket;
208 channel: Integer; {* The src/dst channel of the packet *}
209 data: PUInt8; {* The packet data *}
210 len: Integer; {* The length of the packet data *}
211 maxlen: Integer; {* The size of the data buffer *}
212 status: Integer; {* packet status after sending *}
213 address: TIPadress; {* The source/dest address of an incoming/outgoing packet *}
216 {* Allocate/resize/free a single UDP packet 'size' bytes long.
217 The new packet is returned, or NULL if the function ran out of memory.
219 function SDLNet_AllocPacket(size: Integer): PUDPpacket cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_AllocPacket' {$ENDIF} {$ENDIF};
220 function SDLNet_ResizePacket(packet: PUDPpacket; newsize: Integer): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_ResizePacket' {$ENDIF} {$ENDIF};
221 procedure SDLNet_FreePacket(packet: PUDPpacket) cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_FreePacket' {$ENDIF} {$ENDIF};
223 {* Allocate/Free a UDP packet vector (array of packets) of 'howmany' packets,
224 each 'size' bytes long.
225 A pointer to the first packet in the array is returned, or NULL if the
226 function ran out of memory.
228 function SDLNet_AllocPacketV(howmany: Integer; size: Integer): PPUDPpacket cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_AllocPacketV' {$ENDIF} {$ENDIF};
229 procedure SDLNet_FreePacketV(packetV: PPUDPpacket) cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_FreePacketV' {$ENDIF} {$ENDIF};
231 {* Open a UDP network socket
232 If 'port' is non-zero, the UDP socket is bound to a local port.
233 The 'port' should be given in native byte order, but is used
234 internally in network (big endian) byte order, in addresses, etc.
235 This allows other systems to send to this socket via a known port.
237 function SDLNet_UDP_Open(port: UInt16): TUDPsocket cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_UDP_Open' {$ENDIF} {$ENDIF};
239 {* Set the percentage of simulated packet loss for packets sent on the socket.
241 procedure SDLNet_UDP_SetPacketLoss(sock: TUDPsocket; percent: Integer) cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_UDP_SetPacketLoss' {$ENDIF} {$ENDIF};
243 {* Bind the address 'address' to the requested channel on the UDP socket.
244 If the channel is -1, then the first unbound channel that has not yet
245 been bound to the maximum number of addresses will be bound with
246 the given address as it's primary address.
247 If the channel is already bound, this new address will be added to the
248 list of valid source addresses for packets arriving on the channel.
249 If the channel is not already bound, then the address becomes the primary
250 address, to which all outbound packets on the channel are sent.
251 This function returns the channel which was bound, or -1 on error.
253 function SDLNet_UDP_Bind(sock: TUDPsocket; channel: Integer; address: PIPadress): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_UDP_Bind' {$ENDIF} {$ENDIF};
255 {* Unbind all addresses from the given channel *}
256 procedure SDLNet_UDP_Unbind(sock: TUDPsocket; channel: Integer) cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_UDP_Unbind' {$ENDIF} {$ENDIF};
258 {* Get the primary IP address of the remote system associated with the
259 socket and channel. If the channel is -1, then the primary IP port
260 of the UDP socket is returned -- this is only meaningful for sockets
261 opened with a specific port.
262 If the channel is not bound and not -1, this function returns NULL.
264 function SDLNet_UDP_GetPeerAddress(sock: TUDPsocket; channel: Integer): PIPadress cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_GetPeerAddress' {$ENDIF} {$ENDIF};
266 {* Send a vector of packets to the the channels specified within the packet.
267 If the channel specified in the packet is -1, the packet will be sent to
268 the address in the 'src' member of the packet.
269 Each packet will be updated with the status of the packet after it has
270 been sent, -1 if the packet send failed.
271 This function returns the number of packets sent.
273 function SDLNet_UDP_SendV(sock: TUDPsocket; packets: PPUDPpacket; npackets: Integer): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_UDP_SendV' {$ENDIF} {$ENDIF};
275 {* Send a single packet to the specified channel.
276 If the channel specified in the packet is -1, the packet will be sent to
277 the address in the 'src' member of the packet.
278 The packet will be updated with the status of the packet after it has
280 This function returns 1 if the packet was sent, or 0 on error.
283 The maximum size of the packet is limited by the MTU (Maximum Transfer Unit)
284 of the transport medium. It can be as low as 250 bytes for some PPP links,
285 and as high as 1500 bytes for ethernet.
287 function SDLNet_UDP_Send(sock: TUDPsocket; channel: Integer; packet: PUDPpacket): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_UDP_Send' {$ENDIF} {$ENDIF};
289 {* Receive a vector of pending packets from the UDP socket.
290 The returned packets contain the source address and the channel they arrived
291 on. If they did not arrive on a bound channel, the the channel will be set
293 The channels are checked in highest to lowest order, so if an address is
294 bound to multiple channels, the highest channel with the source address
295 bound will be returned.
296 This function returns the number of packets read from the network, or -1
297 on error. This function does not block, so can return 0 packets pending.
299 function SDLNet_UDP_RecvV(sock: TUDPsocket; packets: PPUDPpacket): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_UDP_RecvV' {$ENDIF} {$ENDIF};
301 {* Receive a single packet from the UDP socket.
302 The returned packet contains the source address and the channel it arrived
303 on. If it did not arrive on a bound channel, the the channel will be set
305 The channels are checked in highest to lowest order, so if an address is
306 bound to multiple channels, the highest channel with the source address
307 bound will be returned.
308 This function returns the number of packets read from the network, or -1
309 on error. This function does not block, so can return 0 packets pending.
311 function SDLNet_UDP_Recv(sock: TUDPsocket; packet: PUDPpacket): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_UDP_Recv' {$ENDIF} {$ENDIF};
313 {* Close a UDP network socket *}
314 procedure SDLNet_UDP_Close(sock: TUDPsocket) cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_UDP_Close' {$ENDIF} {$ENDIF};
317 {***********************************************************************}
318 {* Hooks for checking sockets for available data *}
319 {***********************************************************************}
322 PSDLNet_SocketSet = ^TSDLNet_SocketSet;
323 TSDLNet_SocketSet = Pointer; //todo
325 {* Any network socket can be safely cast to this socket type *}
326 PSDLNet_GenericSocket = ^TSDLNet_GenericSocket;
327 TSDLNet_GenericSocket = record
331 {* Allocate a socket set for use with SDLNet_CheckSockets()
332 This returns a socket set for up to 'maxsockets' sockets, or NULL if
333 the function ran out of memory.
335 function SDLNet_AllocSocketSet(maxsockets: Integer): TSDLNet_SocketSet cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_AllocSocketSet' {$ENDIF} {$ENDIF};
337 {* Add a socket to a set of sockets to be checked for available data *}
338 function SDLNet_AddSocket(_set: TSDLNet_SocketSet; sock: TSDLNet_GenericSocket): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_AddSocket' {$ENDIF} {$ENDIF};
340 function SDLNet_TCP_AddSocket(_set: TSDLNet_SocketSet; sock: TTCPsocket): Integer;
341 function SDLNet_UDP_AddSocket(_set: TSDLNet_SocketSet; sock: TUDPsocket): Integer;
344 {* Remove a socket from a set of sockets to be checked for available data *}
345 function SDLNet_DelSocket(_set: TSDLNet_SocketSet; sock: TSDLNet_GenericSocket): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_DelSocket' {$ENDIF} {$ENDIF};
347 function SDLNet_TCP_DelSocket(_set: TSDLNet_SocketSet; sock: TTCPsocket): Integer;
348 function SDLNet_UDP_DelSocket(_set: TSDLNet_SocketSet; sock: TUDPsocket): Integer;
350 {* This function checks to see if data is available for reading on the
351 given set of sockets. If 'timeout' is 0, it performs a quick poll,
352 otherwise the function returns when either data is available for
353 reading, or the timeout in milliseconds has elapsed, which ever occurs
354 first. This function returns the number of sockets ready for reading,
355 or -1 if there was an error with the select() system call.
357 function SDLNet_CheckSockets(_set: TSDLNet_SocketSet; timeout: UInt32): Integer cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_CheckSockets' {$ENDIF} {$ENDIF};
359 {* After calling SDLNet_CheckSockets(), you can use this function on a
360 socket that was in the socket set, to find out if data is available
363 function SDLNet_SocketReady(sock: TSDLNet_GenericSocket): Boolean;
365 {* Free a set of sockets allocated by SDL_NetAllocSocketSet() *}
366 procedure SDLNet_FreeSocketSet(_set: TSDLNet_SocketSet) cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_FreeSocketSet' {$ENDIF} {$ENDIF};
368 {***********************************************************************}
369 {* Error reporting functions *}
370 {***********************************************************************}
372 procedure SDLNet_SetError(fmt: PAnsiChar) cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_SetError' {$ENDIF} {$ENDIF};
373 function SDLNet_GetError(): PAnsiChar cdecl; external NET_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDLNet_GetError' {$ENDIF} {$ENDIF};
375 {***********************************************************************}
376 {* Inline functions to read/write network data *}
377 {***********************************************************************}
379 {* Warning, some systems have data access alignment restrictions *} {
380 #if defined(sparc) || defined(mips) || defined(__arm__)
381 #define SDL_DATA_ALIGNED 1
383 #ifndef SDL_DATA_ALIGNED
384 #define SDL_DATA_ALIGNED 0
387 {* Write a 16/32-bit value to network packet buffer *} {
388 #define SDLNet_Write16(value, areap) _SDLNet_Write16(value, areap)
389 #define SDLNet_Write32(value, areap) _SDLNet_Write32(value, areap)
391 {* Read a 16/32-bit value from network packet buffer *} {
392 #define SDLNet_Read16(areap) _SDLNet_Read16(areap)
393 #define SDLNet_Read32(areap) _SDLNet_Read32(areap) }
395 #if !defined(WITHOUT_SDL) && !SDL_DATA_ALIGNED
397 SDL_FORCE_INLINE void _SDLNet_Write16(Uint16 value, void *areap)
399 *(Uint16 *)areap = SDL_SwapBE16(value);
402 SDL_FORCE_INLINE void _SDLNet_Write32(Uint32 value, void *areap)
404 *(Uint32 *)areap = SDL_SwapBE32(value);
407 SDL_FORCE_INLINE Uint16 _SDLNet_Read16(const void *areap)
409 return SDL_SwapBE16(*(const Uint16 *)areap);
412 SDL_FORCE_INLINE Uint32 _SDLNet_Read32(const void *areap)
414 return SDL_SwapBE32(*(const Uint32 *)areap);
417 #else {* !defined(WITHOUT_SDL) && !SDL_DATA_ALIGNED *}
419 SDL_FORCE_INLINE void _SDLNet_Write16(Uint16 value, void *areap)
421 Uint8 *area = (Uint8*)areap;
422 area[0] = (value >> 8) & 0xFF;
423 area[1] = value & 0xFF;
426 SDL_FORCE_INLINE void _SDLNet_Write32(Uint32 value, void *areap)
428 Uint8 *area = (Uint8*)areap;
429 area[0] = (value >> 24) & 0xFF;
430 area[1] = (value >> 16) & 0xFF;
431 area[2] = (value >> 8) & 0xFF;
432 area[3] = value & 0xFF;
435 SDL_FORCE_INLINE Uint16 _SDLNet_Read16(void *areap)
437 Uint8 *area = (Uint8*)areap;
438 return ((Uint16)area[0]) << 8 | ((Uint16)area[1]);
441 SDL_FORCE_INLINE Uint32 _SDLNet_Read32(const void *areap)
443 const Uint8 *area = (const Uint8*)areap;
444 return ((Uint32)area[0]) << 24 | ((Uint32)area[1]) << 16 | ((Uint32)area[2]) << 8 | ((Uint32)area[3]);
449 procedure SDL_NET_VERSION(var x: TSDLNet_Version);
451 x.major := SDL_NET_MAJOR_VERSION;
452 x.minor := SDL_NET_MINOR_VERSION;
453 x.patch := SDL_NET_PATCHLEVEL;
456 function SDLNet_TCP_AddSocket(_set: TSDLNet_SocketSet; sock: TTCPsocket): Integer;
458 Result := SDLNet_AddSocket(_set, TSDLNet_GenericSocket(sock));
461 function SDLNet_UDP_AddSocket(_set: TSDLNet_SocketSet; sock: TUDPsocket): Integer;
463 Result := SDLNet_AddSocket(_set, TSDLNet_GenericSocket(sock));
466 function SDLNet_TCP_DelSocket(_set: TSDLNet_SocketSet; sock: TTCPsocket): Integer;
468 Result := SDLNet_DelSocket(_set, TSDLNet_GenericSocket(sock));
471 function SDLNet_UDP_DelSocket(_set: TSDLNet_SocketSet; sock: TUDPsocket): Integer;
473 Result := SDLNet_DelSocket(_set, TSDLNet_GenericSocket(sock));
476 function SDLNet_SocketReady(sock: TSDLNet_GenericSocket): Boolean;
478 Result := Boolean(sock.ready);