zenilib: zenilib/jni/external/sdl_net/SDLnetUDP.c Source File

zenilib 0.5.3.0

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDLnetUDP.c
Go to the documentation of this file.
1 /*
2 SDL_net: An example cross-platform network library for use with SDL
3 Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21
22 /* $Id$ */
23
24 #include "SDLnetsys.h"
25 #include "SDL_net.h"
26
27 #ifdef __WIN32__
28 #define srandom srand
29 #define random rand
30 #endif
31
32 struct UDP_channel {
33 int numbound;
34 IPaddress address[SDLNET_MAX_UDPADDRESSES];
35 };
36
37 struct _UDPsocket {
38 int ready;
39 SOCKET channel;
40 IPaddress address;
41
42 struct UDP_channel binding[SDLNET_MAX_UDPCHANNELS];
43
44 /* For debugging purposes */
45 int packetloss;
46 };
47
48 /* Allocate/free a single UDP packet 'size' bytes long.
49 The new packet is returned, or NULL if the function ran out of memory.
50 */
51 extern UDPpacket *SDLNet_AllocPacket(int size)
52 {
53 UDPpacket *packet;
54 int error;
55
56
57 error = 1;
58 packet = (UDPpacket *)malloc(sizeof(*packet));
59 if ( packet != NULL ) {
60 packet->maxlen = size;
61 packet->data = (Uint8 *)malloc(size);
62 if ( packet->data != NULL ) {
63 error = 0;
64 }
65 }
66 if ( error ) {
67 SDLNet_SetError("Out of memory");
68 SDLNet_FreePacket(packet);
69 packet = NULL;
70 }
71 return(packet);
72 }
73 int SDLNet_ResizePacket(UDPpacket *packet, int newsize)
74 {
75 Uint8 *newdata;
76
77 newdata = (Uint8 *)malloc(newsize);
78 if ( newdata != NULL ) {
79 free(packet->data);
80 packet->data = newdata;
81 packet->maxlen = newsize;
82 }
83 return(packet->maxlen);
84 }
85 extern void SDLNet_FreePacket(UDPpacket *packet)
86 {
87 if ( packet ) {
88 free(packet->data);
89 free(packet);
90 }
91 }
92
93 /* Allocate/Free a UDP packet vector (array of packets) of 'howmany' packets,
94 each 'size' bytes long.
95 A pointer to the packet array is returned, or NULL if the function ran out
96 of memory.
97 */
98 UDPpacket **SDLNet_AllocPacketV(int howmany, int size)
99 {
100 UDPpacket **packetV;
101
102 packetV = (UDPpacket **)malloc((howmany+1)*sizeof(*packetV));
103 if ( packetV != NULL ) {
104 int i;
105 for ( i=0; i<howmany; ++i ) {
106 packetV[i] = SDLNet_AllocPacket(size);
107 if ( packetV[i] == NULL ) {
108 break;
109 }
110 }
111 packetV[i] = NULL;
112
113 if ( i != howmany ) {
114 SDLNet_SetError("Out of memory");
115 SDLNet_FreePacketV(packetV);
116 packetV = NULL;
117 }
118 }
119 return(packetV);
120 }
121 void SDLNet_FreePacketV(UDPpacket **packetV)
122 {
123 if ( packetV ) {
124 int i;
125 for ( i=0; packetV[i]; ++i ) {
126 SDLNet_FreePacket(packetV[i]);
127 }
128 free(packetV);
129 }
130 }
131
132 /* Since the UNIX/Win32/BeOS code is so different from MacOS,
133 we'll just have two completely different sections here.
134 */
135
136 /* Open a UDP network socket
137 If 'port' is non-zero, the UDP socket is bound to a fixed local port.
138 */
139 UDPsocket SDLNet_UDP_Open(Uint16 port)
140 {
141 UDPsocket sock;
142 struct sockaddr_in sock_addr;
143 socklen_t sock_len;
144
145 /* Allocate a UDP socket structure */
146 sock = (UDPsocket)malloc(sizeof(*sock));
147 if ( sock == NULL ) {
148 SDLNet_SetError("Out of memory");
149 goto error_return;
150 }
151 memset(sock, 0, sizeof(*sock));
152 memset(&sock_addr, 0, sizeof(sock_addr));
153
154 /* Open the socket */
155 sock->channel = socket(AF_INET, SOCK_DGRAM, 0);
156 if ( sock->channel == INVALID_SOCKET )
157 {
158 SDLNet_SetError("Couldn't create socket");
159 goto error_return;
160 }
161
162 /* Bind locally, if appropriate */
163 sock_addr.sin_family = AF_INET;
164 sock_addr.sin_addr.s_addr = INADDR_ANY;
165 sock_addr.sin_port = SDLNet_Read16(&port);
166
167 /* Bind the socket for listening */
168 if ( bind(sock->channel, (struct sockaddr *)&sock_addr,
169 sizeof(sock_addr)) == SOCKET_ERROR ) {
170 SDLNet_SetError("Couldn't bind to local port");
171 goto error_return;
172 }
173
174 /* Get the bound address and port */
175 sock_len = sizeof(sock_addr);
176 if ( getsockname(sock->channel, (struct sockaddr *)&sock_addr, &sock_len) < 0 ) {
177 SDLNet_SetError("Couldn't get socket address");
178 goto error_return;
179 }
180
181 /* Fill in the channel host address */
182 sock->address.host = sock_addr.sin_addr.s_addr;
183 sock->address.port = sock_addr.sin_port;
184
185 #ifdef SO_BROADCAST
186 /* Allow LAN broadcasts with the socket */
187 { int yes = 1;
188 setsockopt(sock->channel, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes));
189 }
190 #endif
191 #ifdef IP_ADD_MEMBERSHIP
192 /* Receive LAN multicast packets on 224.0.0.1
193 This automatically works on Mac OS X, Linux and BSD, but needs
194 this code on Windows.
195 */
196 /* A good description of multicast can be found here:
197 http://www.docs.hp.com/en/B2355-90136/ch05s05.html
198 */
199 /* FIXME: Add support for joining arbitrary groups to the API */
200 {
201 struct ip_mreq g;
202
203 g.imr_multiaddr.s_addr = inet_addr("224.0.0.1");
204 g.imr_interface.s_addr = INADDR_ANY;
205 setsockopt(sock->channel, IPPROTO_IP, IP_ADD_MEMBERSHIP,
206 (char*)&g, sizeof(g));
207 }
208 #endif
209
210 /* The socket is ready */
211
212 return(sock);
213
214 error_return:
215 SDLNet_UDP_Close(sock);
216
217 return(NULL);
218 }
219
220 void SDLNet_UDP_SetPacketLoss(UDPsocket sock, int percent)
221 {
222 /* FIXME: We may want this behavior to be reproducible
223 but there isn't a portable reentrant random
224 number generator with good randomness.
225 */
226 srandom(time(NULL));
227
228 if (percent < 0) {
229 percent = 0;
230 } else if (percent > 100) {
231 percent = 100;
232 }
233 sock->packetloss = percent;
234 }
235
236 /* Verify that the channel is in the valid range */
237 static int ValidChannel(int channel)
238 {
239 if ( (channel < 0) || (channel >= SDLNET_MAX_UDPCHANNELS) ) {
240 SDLNet_SetError("Invalid channel");
241 return(0);
242 }
243 return(1);
244 }
245
246 /* Bind the address 'address' to the requested channel on the UDP socket.
247 If the channel is -1, then the first unbound channel that has not yet
248 been bound to the maximum number of addresses will be bound with
249 the given address as it's primary address.
250 If the channel is already bound, this new address will be added to the
251 list of valid source addresses for packets arriving on the channel.
252 If the channel is not already bound, then the address becomes the primary
253 address, to which all outbound packets on the channel are sent.
254 This function returns the channel which was bound, or -1 on error.
255 */
256 int SDLNet_UDP_Bind(UDPsocket sock, int channel, const IPaddress *address)
257 {
258 struct UDP_channel *binding;
259
260 if ( sock == NULL ) {
261 SDLNet_SetError("Passed a NULL socket");
262 return(-1);
263 }
264
265 if ( channel == -1 ) {
266 for ( channel=0; channel < SDLNET_MAX_UDPCHANNELS; ++channel ) {
267 binding = &sock->binding[channel];
268 if ( binding->numbound < SDLNET_MAX_UDPADDRESSES ) {
269 break;
270 }
271 }
272 } else {
273 if ( ! ValidChannel(channel) ) {
274 return(-1);
275 }
276 binding = &sock->binding[channel];
277 }
278 if ( binding->numbound == SDLNET_MAX_UDPADDRESSES ) {
279 SDLNet_SetError("No room for new addresses");
280 return(-1);
281 }
282 binding->address[binding->numbound++] = *address;
283 return(channel);
284 }
285
286 /* Unbind all addresses from the given channel */
287 void SDLNet_UDP_Unbind(UDPsocket sock, int channel)
288 {
289 if ( (channel >= 0) && (channel < SDLNET_MAX_UDPCHANNELS) ) {
290 sock->binding[channel].numbound = 0;
291 }
292 }
293
294 /* Get the primary IP address of the remote system associated with the
295 socket and channel.
296 If the channel is not bound, this function returns NULL.
297 */
298 IPaddress *SDLNet_UDP_GetPeerAddress(UDPsocket sock, int channel)
299 {
300 IPaddress *address;
301
302 address = NULL;
303 switch (channel) {
304 case -1:
305 /* Return the actual address of the socket */
306 address = &sock->address;
307 break;
308 default:
309 /* Return the address of the bound channel */
310 if ( ValidChannel(channel) &&
311 (sock->binding[channel].numbound > 0) ) {
312 address = &sock->binding[channel].address[0];
313 }
314 break;
315 }
316 return(address);
317 }
318
319 /* Send a vector of packets to the the channels specified within the packet.
320 If the channel specified in the packet is -1, the packet will be sent to
321 the address in the 'src' member of the packet.
322 Each packet will be updated with the status of the packet after it has
323 been sent, -1 if the packet send failed.
324 This function returns the number of packets sent.
325 */
326 int SDLNet_UDP_SendV(UDPsocket sock, UDPpacket **packets, int npackets)
327 {
328 int numsent, i, j;
329 struct UDP_channel *binding;
330 int status;
331 int sock_len;
332 struct sockaddr_in sock_addr;
333
334 if ( sock == NULL ) {
335 SDLNet_SetError("Passed a NULL socket");
336 return(0);
337 }
338
339 /* Set up the variables to send packets */
340 sock_len = sizeof(sock_addr);
341
342 numsent = 0;
343 for ( i=0; i<npackets; ++i )
344 {
345 /* Simulate packet loss, if desired */
346 if (sock->packetloss) {
347 if ((random()%100) <= sock->packetloss) {
348 packets[i]->status = packets[i]->len;
349 ++numsent;
350 continue;
351 }
352 }
353
354 /* if channel is < 0, then use channel specified in sock */
355
356 if ( packets[i]->channel < 0 )
357 {
358 sock_addr.sin_addr.s_addr = packets[i]->address.host;
359 sock_addr.sin_port = packets[i]->address.port;
360 sock_addr.sin_family = AF_INET;
361 status = sendto(sock->channel,
362 packets[i]->data, packets[i]->len, 0,
363 (struct sockaddr *)&sock_addr,sock_len);
364 if ( status >= 0 )
365 {
366 packets[i]->status = status;
367 ++numsent;
368 }
369 }
370 else
371 {
372 /* Send to each of the bound addresses on the channel */
373 #ifdef DEBUG_NET
374 printf("SDLNet_UDP_SendV sending packet to channel = %d\n", packets[i]->channel );
375 #endif
376
377 binding = &sock->binding[packets[i]->channel];
378
379 for ( j=binding->numbound-1; j>=0; --j )
380 {
381 sock_addr.sin_addr.s_addr = binding->address[j].host;
382 sock_addr.sin_port = binding->address[j].port;
383 sock_addr.sin_family = AF_INET;
384 status = sendto(sock->channel,
385 packets[i]->data, packets[i]->len, 0,
386 (struct sockaddr *)&sock_addr,sock_len);
387 if ( status >= 0 )
388 {
389 packets[i]->status = status;
390 ++numsent;
391 }
392 }
393 }
394 }
395
396 return(numsent);
397 }
398
399 int SDLNet_UDP_Send(UDPsocket sock, int channel, UDPpacket *packet)
400 {
401 /* This is silly, but... */
402 packet->channel = channel;
403 return(SDLNet_UDP_SendV(sock, &packet, 1));
404 }
405
406 /* Returns true if a socket is has data available for reading right now */
407 static int SocketReady(SOCKET sock)
408 {
409 int retval = 0;
410 struct timeval tv;
411 fd_set mask;
412
413 /* Check the file descriptors for available data */
414 do {
415 SDLNet_SetLastError(0);
416
417 /* Set up the mask of file descriptors */
418 FD_ZERO(&mask);
419 FD_SET(sock, &mask);
420
421 /* Set up the timeout */
422 tv.tv_sec = 0;
423 tv.tv_usec = 0;
424
425 /* Look! */
426 retval = select(sock+1, &mask, NULL, NULL, &tv);
427 } while ( SDLNet_GetLastError() == EINTR );
428
429 return(retval == 1);
430 }
431
432 /* Receive a vector of pending packets from the UDP socket.
433 The returned packets contain the source address and the channel they arrived
434 on. If they did not arrive on a bound channel, the the channel will be set
435 to -1.
436 This function returns the number of packets read from the network, or -1
437 on error. This function does not block, so can return 0 packets pending.
438 */
439 extern int SDLNet_UDP_RecvV(UDPsocket sock, UDPpacket **packets)
440 {
441 int numrecv, i, j;
442 struct UDP_channel *binding;
443 socklen_t sock_len;
444 struct sockaddr_in sock_addr;
445
446 if ( sock == NULL ) {
447 return(0);
448 }
449
450 numrecv = 0;
451 while ( packets[numrecv] && SocketReady(sock->channel) )
452 {
453 UDPpacket *packet;
454
455 packet = packets[numrecv];
456
457 sock_len = sizeof(sock_addr);
458 packet->status = recvfrom(sock->channel,
459 packet->data, packet->maxlen, 0,
460 (struct sockaddr *)&sock_addr,
461 &sock_len);
462 if ( packet->status >= 0 ) {
463 packet->len = packet->status;
464 packet->address.host = sock_addr.sin_addr.s_addr;
465 packet->address.port = sock_addr.sin_port;
466 packet->channel = -1;
467
468 for (i=(SDLNET_MAX_UDPCHANNELS-1); i>=0; --i )
469 {
470 binding = &sock->binding[i];
471
472 for ( j=binding->numbound-1; j>=0; --j )
473 {
474 if ( (packet->address.host == binding->address[j].host) &&
475 (packet->address.port == binding->address[j].port) )
476 {
477 packet->channel = i;
478 goto foundit; /* break twice */
479 }
480 }
481 }
482 foundit:
483 ++numrecv;
484 }
485
486 else
487 {
488 packet->len = 0;
489 }
490 }
491
492 sock->ready = 0;
493
494 return(numrecv);
495 }
496
497 /* Receive a single packet from the UDP socket.
498 The returned packet contains the source address and the channel it arrived
499 on. If it did not arrive on a bound channel, the the channel will be set
500 to -1.
501 This function returns the number of packets read from the network, or -1
502 on error. This function does not block, so can return 0 packets pending.
503 */
504 int SDLNet_UDP_Recv(UDPsocket sock, UDPpacket *packet)
505 {
506 UDPpacket *packets[2];
507
508 /* Receive a packet array of 1 */
509 packets[0] = packet;
510 packets[1] = NULL;
511 return(SDLNet_UDP_RecvV(sock, packets));
512 }
513
514 /* Close a UDP network socket */
515 extern void SDLNet_UDP_Close(UDPsocket sock)
516 {
517 if ( sock != NULL )
518 {
519 if ( sock->channel != INVALID_SOCKET )
520 {
521 closesocket(sock->channel);
522 }
523
524 free(sock);
525 }
526 }
527
SDLNet_SetError
DECLSPEC void SDLCALL SDLNet_SetError(const char *fmt,...)
Definition: SDLnet.c:65
SocketReady
static int SocketReady(SOCKET sock)
Definition: SDLnetUDP.c:407
SOCKET
#define SOCKET
Definition: SDLnetsys.h:78
IPaddress::host
Uint32 host
Definition: SDL_net.h:91
ValidChannel
static int ValidChannel(int channel)
Definition: SDLnetUDP.c:237
UDPsocket
struct _UDPsocket * UDPsocket
Definition: SDL_net.h:182
SDLNet_UDP_Open
DECLSPEC UDPsocket SDLCALL SDLNet_UDP_Open(Uint16 port)
Definition: SDLnetUDP.c:139
closesocket
#define closesocket
Definition: SDLnetsys.h:76
NULL
#define NULL
Definition: ftobjs.h:61
IPaddress
Definition: SDL_net.h:90
SDLnetsys.h
free
SDL_EventEntry * free
Definition: SDL_events.c:80
j
int32_t j
Definition: e_log.c:102
memset
#define memset
Definition: SDL_malloc.c:633
UDPpacket
Definition: SDL_net.h:183
SDLNet_GetLastError
int SDLNet_GetLastError(void)
Definition: SDLnet.c:51
SDLNet_AllocPacket
DECLSPEC UDPpacket *SDLCALL SDLNet_AllocPacket(int size)
Definition: SDLnetUDP.c:51
UDPpacket::len
int len
Definition: SDL_net.h:186
UDPpacket::address
IPaddress address
Definition: SDL_net.h:189
SDLNet_UDP_Unbind
DECLSPEC void SDLCALL SDLNet_UDP_Unbind(UDPsocket sock, int channel)
Definition: SDLnetUDP.c:287
packets
static UDPpacket ** packets
Definition: chat.cpp:46
SDLNET_MAX_UDPADDRESSES
#define SDLNET_MAX_UDPADDRESSES
Definition: SDL_net.h:180
INVALID_SOCKET
#define INVALID_SOCKET
Definition: SDLnetsys.h:79
UDPpacket::channel
int channel
Definition: SDL_net.h:184
error
FT_Error error
Definition: cffdrivr.c:407
SDLNet_UDP_SendV
DECLSPEC int SDLCALL SDLNet_UDP_SendV(UDPsocket sock, UDPpacket **packets, int npackets)
Definition: SDLnetUDP.c:326
SDLNet_FreePacketV
DECLSPEC void SDLCALL SDLNet_FreePacketV(UDPpacket **packetV)
Definition: SDLnetUDP.c:121
SDLNet_AllocPacketV
DECLSPEC UDPpacket **SDLCALL SDLNet_AllocPacketV(int howmany, int size)
Definition: SDLnetUDP.c:98
SDLNET_MAX_UDPCHANNELS
#define SDLNET_MAX_UDPCHANNELS
Definition: SDL_net.h:178
address
GLuint GLuint64EXT address
Definition: glew.h:13266
IPaddress::port
Uint16 port
Definition: SDL_net.h:92
SDLNet_UDP_Send
DECLSPEC int SDLCALL SDLNet_UDP_Send(UDPsocket sock, int channel, UDPpacket *packet)
Definition: SDLnetUDP.c:399
malloc
#define malloc
Definition: SDL_malloc.c:635
SDLNet_UDP_SetPacketLoss
DECLSPEC void SDLCALL SDLNet_UDP_SetPacketLoss(UDPsocket sock, int percent)
Definition: SDLnetUDP.c:220
SDLNet_FreePacket
DECLSPEC void SDLCALL SDLNet_FreePacket(UDPpacket *packet)
Definition: SDLnetUDP.c:85
sock
TCPsocket sock
Definition: chatd.c:41
Uint8
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
INADDR_ANY
#define INADDR_ANY
Definition: SDL_net.h:102
mask
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
Definition: gl2ext.h:961
UDPpacket::status
int status
Definition: SDL_net.h:188
SDLNet_UDP_Close
DECLSPEC void SDLCALL SDLNet_UDP_Close(UDPsocket sock)
Definition: SDLnetUDP.c:515
SDLNet_UDP_Bind
DECLSPEC int SDLCALL SDLNet_UDP_Bind(UDPsocket sock, int channel, const IPaddress *address)
Definition: SDLnetUDP.c:256
SDLNet_UDP_GetPeerAddress
DECLSPEC IPaddress *SDLCALL SDLNet_UDP_GetPeerAddress(UDPsocket sock, int channel)
Definition: SDLnetUDP.c:298
SOCKET_ERROR
#define SOCKET_ERROR
Definition: SDLnetsys.h:80
Uint16
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:137
UDPpacket::maxlen
int maxlen
Definition: SDL_net.h:187
SDLNet_SetLastError
void SDLNet_SetLastError(int err)
Definition: SDLnet.c:56
SDLNet_Read16
#define SDLNet_Read16(areap)
Definition: SDL_net.h:380
i
int i
Definition: pngrutil.c:1377
UDPpacket::data
Uint8 * data
Definition: SDL_net.h:185
SDLNet_ResizePacket
DECLSPEC int SDLCALL SDLNet_ResizePacket(UDPpacket *packet, int newsize)
Definition: SDLnetUDP.c:73
SDLNet_UDP_Recv
DECLSPEC int SDLCALL SDLNet_UDP_Recv(UDPsocket sock, UDPpacket *packet)
Definition: SDLnetUDP.c:504
SDLNet_UDP_RecvV
DECLSPEC int SDLCALL SDLNet_UDP_RecvV(UDPsocket sock, UDPpacket **packets)
Definition: SDLnetUDP.c:439
size
GLsizei size
Definition: gl2ext.h:1467