zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Net.cpp
Go to the documentation of this file.
1 /* This file is part of the Zenipex Library (zenilib).
2  * Copyright (C) 2011 Mitchell Keith Bloch (bazald).
3  *
4  * zenilib is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * zenilib is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with zenilib. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <zeni_net.h>
19 
20 #include <SDL/SDL.h>
21 #include <vector>
22 #include <list>
23 #include <sstream>
24 
25 #if defined(_DEBUG) && defined(_WINDOWS)
26 #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
27 #define new DEBUG_NEW
28 #endif
29 
30 #include <Zeni/Singleton.hxx>
31 
32 namespace Zeni {
33 
34  template class ZENI_NET_DLL Singleton<Net>;
35 
36  Net * Net::create() {
37  return new Net;
38  }
39 
40  Singleton<Net>::Uninit Net::g_uninit;
41  Singleton<Net>::Reinit Net::g_reinit;
42 
43  Net::Net() {
44  Core::remove_post_reinit(&g_reinit);
45 
46  // Ensure Core is initialized
47  Core &cr = get_Core();
48 
49  if(SDLNet_Init())
50  throw Net_Init_Failure();
51 
52  cr.lend_pre_uninit(&g_uninit);
53  cr.lend_post_reinit(&g_reinit);
54  }
55 
56  Net::~Net() {
57  Core::remove_pre_uninit(&g_uninit);
58 
59  SDLNet_Quit();
60  }
61 
62  IPaddress Net::resolve_host(const String &host, const Uint16 &port) {
63  IPaddress ip;
64  SDLNet_ResolveHost(&ip, host.c_str(), port);
65  return ip;
66  }
67 
69  return SDLNet_ResolveIP(&ip);
70  }
71 
72  Net & get_Net() {
73  return Net::get();
74  }
75 
76  TCP_Socket::TCP_Socket(IPaddress ip)
77  : sock(0),
78  sockset(0),
79 #ifdef _WINDOWS
80 #pragma warning( push )
81 #pragma warning( disable : 4355 )
82 #endif
83  m_uninit(*this)
84 #ifdef _WINDOWS
85 #pragma warning( pop )
86 #endif
87  {
88  Net &nr = get_Net();
89 
90  if(!ip.host)
92 
93  sock = SDLNet_TCP_Open(&ip);
94  sockset = SDLNet_AllocSocketSet(1);
95 
96  if(!sock ||
97  !sockset ||
98  SDLNet_TCP_AddSocket(sockset, sock) == -1)
99  {
100  SDLNet_TCP_Close(sock);
101  SDLNet_FreeSocketSet(sockset);
102  throw TCP_Socket_Init_Failure();
103  }
104 
105  nr.lend_pre_uninit(&m_uninit);
106  }
107 
108  TCP_Socket::TCP_Socket(TCPsocket socket)
109  : sock(socket),
110  sockset(0),
111 #ifdef _WINDOWS
112 #pragma warning( push )
113 #pragma warning( disable : 4355 )
114 #endif
115  m_uninit(*this)
116 #ifdef _WINDOWS
117 #pragma warning( pop )
118 #endif
119  {
120  if(!sock)
121  throw TCP_Socket_Init_Failure();
122 
123  sockset = SDLNet_AllocSocketSet(1);
124 
125  if(!sockset ||
126  SDLNet_TCP_AddSocket(sockset, sock) == -1)
127  {
128  SDLNet_TCP_Close(sock);
129  throw TCP_Socket_Init_Failure();
130  }
131 
132  get_Net().lend_pre_uninit(&m_uninit);
133  }
134 
136  Net::remove_pre_uninit(&m_uninit);
137 
138  if(sock && sockset) {
139  SDLNet_TCP_DelSocket(sockset, sock);
140  SDLNet_FreeSocketSet(sockset);
141  SDLNet_TCP_Close(sock);
142  }
143  }
144 
146  return *SDLNet_TCP_GetPeerAddress(sock);
147  }
148 
150  return SDLNet_CheckSockets(sockset, 0);
151  }
152 
154  int rv = try_check_socket();
155 
156  if(rv == -1)
157  throw Socket_Closed();
158 
159  return rv;
160  }
161 
162  int TCP_Socket::try_send(const void * const &data, const Uint16 &num_bytes) {
163  return SDLNet_TCP_Send(sock, const_cast<void *>(data), num_bytes) < num_bytes ? -1 : 0;
164  }
165 
167  return try_send(data.c_str(), Uint16(data.size()));
168  }
169 
170  void TCP_Socket::send(const void * const &data, const Uint16 &num_bytes) {
171  if(try_send(data, num_bytes) == -1)
172  throw Socket_Closed();
173  }
174 
175  void TCP_Socket::send(const String &data) {
176  if(try_send(data) == -1)
177  throw Socket_Closed();
178  }
179 
180  int TCP_Socket::try_receive(void * const &data, const Uint16 &num_bytes) {
181  int retval = check_socket();
182 
183  if(retval) {
184  retval = SDLNet_TCP_Recv(sock, data, num_bytes);
185  if(retval <= 0)
186  return -1;
187  }
188 
189  return retval;
190  }
191 
192  int TCP_Socket::try_receive(String &data, const Uint16 &num_bytes) {
193  data.resize(size_t(num_bytes));
194 
195  const int retval = receive(const_cast<char *>(data.c_str()), num_bytes);
196  if(retval == -1)
197  return -1;
198 
199  data.resize(size_t(retval));
200  return retval;
201  }
202 
203  int TCP_Socket::receive(void * const &data, const Uint16 &num_bytes) {
204  const int rv = try_receive(data, num_bytes);
205 
206  if(rv == -1)
207  throw Socket_Closed();
208 
209  return rv;
210  }
211 
212  int TCP_Socket::receive(String &data, const Uint16 &num_bytes) {
213  const int rv = try_receive(data, num_bytes);
214 
215  if(rv == -1)
216  throw Socket_Closed();
217 
218  return rv;
219  }
220 
221  void TCP_Socket::Uninit::operator()() {
222  SDLNet_TCP_DelSocket(m_sock.sockset, m_sock.sock);
223  SDLNet_FreeSocketSet(m_sock.sockset);
224  SDLNet_TCP_Close(m_sock.sock);
225 
226  m_sock.sock = 0;
227  m_sock.sockset = 0;
228 
229  get_Core().remove_pre_uninit(this);
230  }
231 
232  TCP_Listener::TCP_Listener(const Uint16 &port)
233  : sock(0),
234 #ifdef _WINDOWS
235 #pragma warning( push )
236 #pragma warning( disable : 4355 )
237 #endif
238  m_uninit(*this)
239 #ifdef _WINDOWS
240 #pragma warning( pop )
241 #endif
242  {
243  Net &nr = get_Net();
244 
245  IPaddress ip = {0, 0};
246  SDLNet_Write16(port, &ip.port);
247 
248  sock = SDLNet_TCP_Open(&ip);
249  if(!sock)
250  throw TCP_Socket_Init_Failure();
251 
252  nr.lend_pre_uninit(&m_uninit);
253  }
254 
256  get_Net().remove_pre_uninit(&m_uninit);
257 
258  if(sock)
259  SDLNet_TCP_Close(sock);
260  }
261 
262  void TCP_Listener::Uninit::operator()() {
263  SDLNet_TCP_Close(m_sock.sock);
264 
265  m_sock.sock = 0;
266 
267  get_Core().remove_pre_uninit(this);
268  }
269 
271  return SDLNet_TCP_Accept(sock);
272  }
273 
274  UDP_Socket::UDP_Socket(const Uint16 &port)
275  : sock(0),
276 #ifdef _WINDOWS
277 #pragma warning( push )
278 #pragma warning( disable : 4355 )
279 #endif
280  m_uninit(*this)
281 #ifdef _WINDOWS
282 #pragma warning( pop )
283 #endif
284  {
285  Net &nr = get_Net();
286 
287  sock = SDLNet_UDP_Open(port);
288  if(!sock)
289  throw UDP_Socket_Init_Failure();
290 
291  nr.lend_pre_uninit(&m_uninit);
292  }
293 
295  Net::remove_pre_uninit(&m_uninit);
296 
297  if(sock)
298  SDLNet_UDP_Close(sock);
299  }
300 
302  return *SDLNet_UDP_GetPeerAddress(sock, -1);
303  }
304 
305  void UDP_Socket::send(const IPaddress &ip, const void * const &data, const Uint16 &num_bytes) {
306  if(num_bytes < 8167u) {
307  UDPpacket packet =
308  {
309  -1,
310  reinterpret_cast<Uint8 *>(const_cast<void *>(data)),
311  num_bytes,
312  num_bytes,
313  0, // Will == -1 on error after UDP_Send, otherwise == # of bytes sent
314  ip
315  };
316 
317  if(SDLNet_UDP_Send(sock, -1, &packet))
318  return;
319 
320  throw Socket_Closed();
321  }
322 
323  throw UDP_Packet_Overflow();
324  }
325 
326  void UDP_Socket::send(const IPaddress &ip, const String &data) {
327  UDP_Socket::send(ip, data.c_str(), Uint16(data.size()));
328  }
329 
330  int UDP_Socket::receive(IPaddress &ip, const void * const &data, const Uint16 &num_bytes) {
331  IPaddress ipaddress = {0, 0};
332 
333  UDPpacket packet =
334  {
335  -1,
336  reinterpret_cast<Uint8 *>(const_cast<void *>(data)),
337  0,
338  num_bytes,
339  0,
340  ipaddress
341  };
342 
343  int retval = SDLNet_UDP_Recv(sock, &packet);
344  if(retval == -1)
345  throw Socket_Closed();
346  else if(!retval) {
347  packet.address.host = 0;
348  packet.address.port = 0;
349  }
350 
351  ip = packet.address;
352 
353  return packet.len;
354  }
355 
357  int retval = UDP_Socket::receive(ip, data.c_str(), Uint16(data.size()));
358 
359  if(int(data.size()) > retval) {
360  data[static_cast<unsigned int>(retval)] = '\0';
361  data.resize(size_t(retval));
362  }
363 
364  return retval;
365  }
366 
367  void UDP_Socket::Uninit::operator()() {
368  SDLNet_UDP_Close(m_sock.sock);
369 
370  m_sock.sock = 0;
371 
372  get_Core().remove_pre_uninit(this);
373  }
374 
375  Split_UDP_Socket::Chunk_Set::Chunk_Set(const IPaddress &sender,
376  const Nonce &incoming,
377  const Uint16 &num_chunks,
378  const Uint16 &which,
379  Chunk &chunk)
380  : ip(sender),
381  nonce(incoming),
382  chunks(num_chunks),
383  chunks_arrived(1u)
384  {
385  assert(num_chunks > which);
386 
387  if(num_chunks > which)
388  chunks[which] = chunk;
389  }
390 
391  bool Split_UDP_Socket::Chunk_Set::add_chunk(const IPaddress &sender,
392  const Nonce &incoming,
393  const Uint16 &num_chunks,
394  const Uint16 &which,
395  Chunk &chunk) {
396  if(ip == sender &&
397  nonce == incoming &&
398  chunks.size() == num_chunks &&
399  chunks.size() > which)
400  {
401  if(!chunks[which].data)
402  chunks[which] = chunk;
403  ++chunks_arrived;
404  return true;
405  }
406 
407  return false;
408  }
409 
410  bool Split_UDP_Socket::Chunk_Set::complete() const {
411  return chunks_arrived == chunks.size();
412 
413  //for(std::vector<Chunk>::const_iterator it = chunks.begin(); it != chunks.end(); ++it)
414  // if(!it->data)
415  // return false;
416  //
417  //return true;
418  }
419 
420  Split_UDP_Socket::Chunk Split_UDP_Socket::Chunk_Set::receive() const {
421  Chunk packet;
422 
423  for(std::vector<Chunk>::const_iterator it = chunks.begin(); it != chunks.end(); ++it)
424  packet.size += it->size;
425 
426  char * dst = new char [packet.size];
427  packet.data = dst;
428 
429  for(std::vector<Chunk>::const_iterator it = chunks.begin(); it != chunks.end(); ++it) {
430  memcpy(dst, it->data, it->size);
431  dst += it->size;
432  }
433 
434  return packet;
435  }
436 
437  const Split_UDP_Socket::Chunk_Set * Split_UDP_Socket::Chunk_Collector::add_chunk(const IPaddress &sender,
438  const Nonce &incoming,
439  const Uint16 &num_chunks,
440  const Uint16 &which,
441  Chunk &chunk) {
442  // Attempt to complete an existing partial packet
443  for(std::list<Chunk_Set *>::iterator it = chunk_sets.begin(); it != chunk_sets.end(); ++it) {
444  if((*it)->add_chunk(sender, incoming, num_chunks, which, chunk)) {
445  if((*it)->complete())
446  return *it;
447  else
448  return 0;
449  }
450  }
451 
452  if(int(chunk_sets.size()) == m_size) // LRU Eviction
453  chunk_sets.pop_back();
454 
455  {// Receive fresh chunk
456  Chunk_Set *cs = new Chunk_Set(sender, incoming, num_chunks, which, chunk);
457  chunk_sets.push_front(cs);
458  if(cs->complete())
459  return cs;
460  }
461 
462  return 0;
463  }
464 
465  Split_UDP_Socket::Split_UDP_Socket(const Uint16 &port, const Uint16 &chunk_sets, const Uint16 &chunk_size)
466  : UDP_Socket(port),
467  m_chunk_size(chunk_size),
468  m_chunk_collector(chunk_sets)
469  {
470  assert(chunk_size);
471  }
472 
473  void Split_UDP_Socket::send(const IPaddress &ip, const void * const &data, const Uint16 &num_bytes) {
474  ++m_nonce_send;
475 
476  const Uint16 offset = static_cast<Uint16>(m_nonce_send.size()) + 2u * sizeof(Uint16);
477  const Uint16 split_size = Uint16(m_chunk_size - offset);
478  const Uint16 num_full_chunks = Uint16(num_bytes / split_size);
479  const Uint16 partial_chunk = Uint16(num_bytes % split_size);
480  const Uint16 num_chunks = num_full_chunks + (partial_chunk ? 1u : 0u);
481 
482  const char *ptr = reinterpret_cast<const char *>(data);
483  for(Uint16 chunk = 0; chunk < num_full_chunks; ++chunk, ptr += split_size) {
484  String s;
485 
486  {
487  std::ostringstream os;
488  serialize(serialize(m_nonce_send.serialize(os), num_chunks), chunk);
489  s = os.str();
490  }
491 
492  s.resize(m_chunk_size);
493  memcpy(const_cast<char *>(s.c_str()) + offset, ptr, split_size);
494 
495  UDP_Socket::send(ip, s);
496  }
497 
498  if(partial_chunk) {
499  String s;
500 
501  {
502  std::ostringstream os;
503  serialize(serialize(m_nonce_send.serialize(os), num_chunks), num_full_chunks);
504  s = os.str();
505  }
506 
507  s.resize(size_t(offset + partial_chunk));
508  memcpy(const_cast<char *>(s.c_str()) + offset, ptr, partial_chunk);
509 
510  UDP_Socket::send(ip, s);
511  }
512  }
513 
514  void Split_UDP_Socket::send(const IPaddress &ip, const String &data) {
515  send(ip, data.c_str(), Uint16(data.size()));
516  }
517 
518  int Split_UDP_Socket::receive(IPaddress &ip, const void * const &data, const Uint16 &num_bytes) {
519  for(int retval = -1; retval;) {
520  String s;
521  s.resize(m_chunk_size);
522 
523  retval = UDP_Socket::receive(ip, s);
524  if(retval) {
525  Nonce nonce;
526  Uint16 num_chunks;
527  Uint16 which;
528  Chunk chunk;
529 
530  {
531  std::istringstream is(s.std_str());
532  unserialize(unserialize(nonce.unserialize(is), num_chunks), which);
533 
534  if(!is)
535  continue;
536 
537  const Uint16 offset = static_cast<Uint16>(nonce.size()) + 2u * sizeof(Uint16);
538 
539  chunk.size = s.size() - offset;
540  chunk.data = new char [chunk.size];
541  memcpy(chunk.data, s.c_str() + offset, chunk.size);
542  }
543 
544  const Chunk_Set * cs = m_chunk_collector.add_chunk(ip, nonce, num_chunks, which, chunk);
545  if(!cs)
546  continue;
547 
548  Chunk packet = cs->receive();
549  if(num_bytes >= Uint16(packet.size)) {
550  memcpy(const_cast<void *>(data), packet.data, packet.size);
551  return int(packet.size);
552  }
553 
554  return 0;
555  }
556  }
557 
558  return 0;
559  }
560 
562  int retval = receive(ip, data.c_str(), Uint16(data.size()));
563 
564  if(int(data.size()) > retval) {
565  data[static_cast<unsigned int>(retval)] = '\0';
566  data.resize(size_t(retval));
567  }
568 
569  return retval;
570  }
571 
572 }
DECLSPEC int SDLCALL SDLNet_TCP_Send(TCPsocket sock, const void *data, int len)
Definition: SDLnetTCP.c:236
virtual ~UDP_Socket()
Definition: Net.cpp:294
String reverse_lookup(IPaddress ip)
If you want to find a URL associated with an IP address.
Definition: Net.cpp:68
DECLSPEC int SDLCALL SDLNet_CheckSockets(SDLNet_SocketSet set, Uint32 timeout)
Definition: SDLnetselect.c:110
#define SDLNet_Write16(value, areap)
Definition: SDL_net.h:376
GLdouble s
Definition: glew.h:1376
else Out of place iCCP chunk
Definition: pngrutil.c:1260
struct Chunk Chunk
Uint32 host
Definition: SDL_net.h:91
DECLSPEC UDPsocket SDLCALL SDLNet_UDP_Open(Uint16 port)
Definition: SDLnetUDP.c:139
Definition: SDL_wave.h:58
int check_socket()
Definition: Net.cpp:153
DECLSPEC void SDLCALL SDLNet_FreeSocketSet(SDLNet_SocketSet set)
Definition: SDLnetselect.c:156
DECLSPEC int SDLCALL SDLNet_Init(void)
Definition: SDLnet.c:86
virtual std::istream & unserialize(std::istream &is)
Definition: VLUID.cpp:73
const char * c_str() const
Definition: String.cpp:467
std::istream & unserialize(std::istream &is, Color &value)
Definition: Color.cpp:72
IPaddress resolve_host(const String &host, const Uint16 &port=0)
Default port 0 indicates a pure lookup with no intention of connecting.
Definition: Net.cpp:62
std::ostream & serialize(std::ostream &os, const Color &value)
Definition: Color.cpp:68
#define assert(x)
Definition: SDL_malloc.c:1234
void resize(size_t n, char c)
Definition: String.cpp:316
static void remove_post_reinit(Event::Handler *const &handler)
DECLSPEC TCPsocket SDLCALL SDLNet_TCP_Accept(TCPsocket server)
Definition: SDLnetTCP.c:166
Net & get_Net()
Get access to the singleton.
Definition: Net.cpp:72
void lend_pre_uninit(Event::Handler *const &handler)
Definition: Singleton.hxx:56
int len
Definition: SDL_net.h:186
IPaddress address
Definition: SDL_net.h:189
DECLSPEC IPaddress *SDLCALL SDLNet_TCP_GetPeerAddress(TCPsocket sock)
Definition: SDLnetTCP.c:223
IPaddress peer_address() const
Definition: Net.cpp:145
The Net Singleton.
Definition: Net.h:120
static __inline__ int SDLNet_TCP_AddSocket(SDLNet_SocketSet set, TCPsocket sock)
Definition: SDL_net.h:313
VLUID Nonce
Definition: VLUID.h:78
ALuint u
Definition: alMain.h:58
static void remove_pre_uninit(Event::Handler *const &handler)
GLenum GLenum dst
Definition: glew.h:2396
virtual int receive(IPaddress &ip, const void *const &data, const Uint16 &num_bytes)
Receive data of up to data.size() from the returned IPaddress; Will error if num_bytes/data.size() is too low.
Definition: Net.cpp:518
A UDP Socket for sending and receiving data.
Definition: Net.h:237
int
Definition: SDL_systhread.c:37
IPaddress peer_address() const
Apparently only works if the port was explicitly specified.
Definition: Net.cpp:301
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
#define pop
Definition: SDL_qsort.c:125
TCPsocket accept()
Returns 0 if no listener.
Definition: Net.cpp:270
static Net & get()
DECLSPEC TCPsocket SDLCALL SDLNet_TCP_Open(IPaddress *ip)
Definition: SDLnetTCP.c:46
int try_check_socket()
Definition: Net.cpp:149
virtual int receive(IPaddress &ip, const void *const &data, const Uint16 &num_bytes)
Receive data of up to data.size() from the returned IPaddress; Will error if num_bytes/data.size() is too low.
Definition: Net.cpp:330
void send(const void *const &data, const Uint16 &num_bytes)
Definition: Net.cpp:170
Uint16 port
Definition: SDL_net.h:92
virtual void send(const IPaddress &ip, const void *const &data, const Uint16 &num_bytes)
Send data to an IPaddress.
Definition: Net.cpp:473
DECLSPEC const char *SDLCALL SDLNet_ResolveIP(const IPaddress *ip)
Definition: SDLnet.c:173
virtual void send(const IPaddress &ip, const void *const &data, const Uint16 &num_bytes)
Send data to an IPaddress.
Definition: Net.cpp:305
DECLSPEC void SDLCALL SDLNet_Quit(void)
Definition: SDLnet.c:110
DECLSPEC int SDLCALL SDLNet_UDP_Send(UDPsocket sock, int channel, UDPpacket *packet)
Definition: SDLnetUDP.c:399
int receive(void *const &data, const Uint16 &num_bytes)
Definition: Net.cpp:203
Uint8 * data
Definition: SDL_wave.h:62
Variable Length Unique IDentifier.
Definition: VLUID.h:47
DECLSPEC int SDLCALL SDLNet_ResolveHost(IPaddress *address, const char *host, Uint16 port)
Definition: SDLnet.c:138
GLintptr offset
Definition: glew.h:1668
struct _TCPsocket * TCPsocket
Definition: SDL_net.h:131
#define memcpy
Definition: SDL_malloc.c:634
TCPsocket sock
Definition: chatd.c:41
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
static __inline__ int SDLNet_TCP_DelSocket(SDLNet_SocketSet set, TCPsocket sock)
Definition: SDL_net.h:325
virtual std::ostream & serialize(std::ostream &os) const
Definition: VLUID.cpp:67
size_t size() const
Definition: String.cpp:310
Core & get_Core()
Get access to the singleton.
Definition: Core.cpp:71
DECLSPEC void SDLCALL SDLNet_UDP_Close(UDPsocket sock)
Definition: SDLnetUDP.c:515
DECLSPEC IPaddress *SDLCALL SDLNet_UDP_GetPeerAddress(UDPsocket sock, int channel)
Definition: SDLnetUDP.c:298
int try_send(const void *const &data, const Uint16 &num_bytes)
Send data.
Definition: Net.cpp:162
std::string std_str() const
Definition: String.h:428
DECLSPEC SDLNet_SocketSet SDLCALL SDLNet_AllocSocketSet(int maxsockets)
Definition: SDLnetselect.c:44
DECLSPEC int SDLCALL SDLNet_TCP_Recv(TCPsocket sock, void *data, int maxlen)
Definition: SDLnetTCP.c:269
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:137
Uint16 size() const
Definition: VLUID.h:60
int try_receive(void *const &data, const Uint16 &num_bytes)
Receive up to num_bytes.
Definition: Net.cpp:180
DECLSPEC void SDLCALL SDLNet_TCP_Close(TCPsocket sock)
Definition: SDLnetTCP.c:289
DECLSPEC int SDLCALL SDLNet_UDP_Recv(UDPsocket sock, UDPpacket *packet)
Definition: SDLnetUDP.c:504