1 /*
2 HawkNL cross platform network library
3 Copyright (C) 2000-2002 Phil Frisbie, Jr. (phil@hawksoft.com)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19
20 Or go to http://www.gnu.org/copyleft/lgpl.html
21 */
22
23 #include <memory.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27
28
29 #define FD_SETSIZE 8192
30
31
32 #if defined WIN32 || defined WIN64
33
34 #include "wsock.h"
35 #ifndef sleep
36 #define sleep(x) Sleep((DWORD)(1000 * (x)))
37 #endif
38
39 #ifdef _MSC_VER
40 #pragma warning (disable:4100) /* disable "unreferenced formal parameter" */
41 #endif
42
43 #else
44 /* Unix-style systems */
45 #include <sys/time.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <netdb.h>
51 #include <sys/ioctl.h>
52 #define readsocket read
53 #define writesocket write
54 #define closesocket close
55 #define INVALID_SOCKET -1
56 #define SOCKET_ERROR -1
57 #define SOCKET int
58 /* define INADDR_NONE if not already */
59 #ifndef INADDR_NONE
60 #define INADDR_NONE ((unsigned long) -1)
61 #define sockerrno errno
62 #endif
63
64 #endif
65
66 #include "nlinternal.h"
67
68 #ifdef NL_INCLUDE_IPX
69 #include "ipx.h"
70
71 typedef struct
72 {
73 NLaddress /*@temp@*/*address;
74 NLchar /*@temp@*/*name;
75 NLsocket socket;
76 } NLaddress_ex_t;
77
78 extern SOCKET nlGroupGetFdset(NLint group, /*@out@*/ fd_set *fd);
79
80 #define MAXHOSTNAMELEN 256
81 #define NL_CONNECT_STRING "HawkNL request connection."
82 #define NL_REPLY_STRING "HawkNL connection OK."
83
84 static NLaddress ipx_ouraddress;
85 static NLaddress ipx_ouraddress_copy;
86 static NLint ipxport = 0;
87 static volatile int backlog = SOMAXCONN;
88 static volatile NLboolean reuseaddress = NL_FALSE;
89
90 #ifdef WINDOWS_APP
91
92 static NLmutex ipxportlock;
93
94 static volatile NLushort ipxnextport = 1024;
95
ipx_getNextPort(void)96 static NLushort ipx_getNextPort(void)
97 {
98 NLlong temp;
99
100 (void)nlMutexLock(&ipxportlock);
101 temp = (NLlong)ipxnextport;
102 if(++temp > 65535)
103 {
104 /* skip the well known ports */
105 temp = 1024;
106 }
107 ipxnextport = (NLushort)temp;
108 (void)nlMutexUnlock(&ipxportlock);
109 return ipxnextport;
110 }
111
ipx_bind(SOCKET socket,const struct sockaddr * a,int len)112 static NLint ipx_bind(SOCKET socket, const struct sockaddr *a, int len)
113 {
114 struct sockaddr_ipx *addr = (struct sockaddr_ipx *)a;
115 int ntries = 500; /* this is to prevent an infinite loop */
116 NLboolean found = NL_FALSE;
117
118 /* check to see if the port is already specified */
119 if(addr->sa_socket != 0)
120 {
121 /* do the normal bind */
122 return bind(socket, a, len);
123 }
124
125 /* let's find our own port number */
126 while(ntries-- > 0)
127 {
128 addr->sa_socket = htons(ipx_getNextPort());
129 if(bind(socket, (struct sockaddr *)addr, len) != SOCKET_ERROR)
130 {
131 found = NL_TRUE;
132 break;
133 }
134 }
135 if(found == NL_TRUE)
136 {
137 return 0;
138 }
139 /* could not find a port, restore the port number back to 0 */
140 addr->sa_socket = 0;
141 /* return error */
142 return SOCKET_ERROR;
143 }
144
145 #else
146 #define sock_bind bind
147 #endif /* WINDOWS_APP */
148
149 /*
150 handle some common connection errors so the app knows when a connection has been dropped
151 */
152
ipx_Error(void)153 static NLint ipx_Error(void)
154 {
155 int err = sockerrno;
156
157 switch (err) {
158
159 #ifdef WINDOWS_APP
160 case WSABASEERR:
161 return 0;
162 #endif
163
164 case EWOULDBLOCK:
165 return 0;
166
167 case ENETRESET:
168 case EHOSTUNREACH:
169 case ECONNABORTED:
170 case ECONNRESET:
171 case ENETUNREACH:
172 case ETIMEDOUT:
173 nlSetError(NL_SOCK_DISCONNECT);
174 break;
175
176 default:
177 nlSetError(NL_SYSTEM_ERROR);
178 break;
179 }
180
181 return NL_INVALID;
182 }
183
ipx_SetReuseAddr(SOCKET socket)184 static void ipx_SetReuseAddr(SOCKET socket)
185 {
186 int i = 1;
187
188 if(reuseaddress == NL_FALSE)
189 {
190 return;
191 }
192 if(setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&i, (int)sizeof(i)) == SOCKET_ERROR)
193 {
194 nlSetError(NL_SYSTEM_ERROR);
195 }
196 }
197
ipx_SetNonBlocking(SOCKET socket)198 static NLboolean ipx_SetNonBlocking(SOCKET socket)
199 {
200 unsigned long i = 1;
201
202 if(ioctl(socket, FIONBIO, &i) == SOCKET_ERROR)
203 {
204 return NL_FALSE;
205 }
206 return NL_TRUE;
207 }
208
ipx_SetBlocking(SOCKET socket)209 static NLboolean ipx_SetBlocking(SOCKET socket)
210 {
211 unsigned long i = 0;
212
213 if(ioctl(socket, FIONBIO, &i) == SOCKET_ERROR)
214 {
215 return NL_FALSE;
216 }
217 return NL_TRUE;
218 }
219
ipx_SetBroadcast(SOCKET socket)220 static NLboolean ipx_SetBroadcast(SOCKET socket)
221 {
222 int i = 1;
223
224 if(setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, (int)sizeof(i)) == SOCKET_ERROR)
225 {
226 nlSetError(NL_SYSTEM_ERROR);
227 return NL_FALSE;
228 }
229 return NL_TRUE;
230
231 }
232
233 /* is there a better way to get our address? */
ipx_GetHostAddress(NLaddress * address)234 static NLboolean ipx_GetHostAddress(NLaddress *address)
235 {
236 NLint addrlen = (NLint)sizeof(NLaddress);
237 SOCKET sock;
238
239 sock = socket(PF_IPX, SOCK_DGRAM, NSPROTO_IPX);
240
241 if(sock == INVALID_SOCKET)
242 {
243 nlSetError(NL_NO_NETWORK);
244 return NL_FALSE;
245 }
246
247 ((struct sockaddr_ipx *)address)->sa_family = AF_IPX;
248 memset(((struct sockaddr_ipx *)address)->sa_netnum, 0, 4);
249 memset(((struct sockaddr_ipx *)address)->sa_nodenum, 0, 6);
250 ((struct sockaddr_ipx *)address)->sa_socket = 0;
251
252 if(ipx_bind(sock, (struct sockaddr *)address, (int)sizeof(NLaddress)) == SOCKET_ERROR)
253 {
254 nlSetError(NL_NO_NETWORK);
255 (void)closesocket(sock);
256 return NL_FALSE;
257 }
258
259 if(getsockname(sock, (struct sockaddr *)address, &addrlen) != 0)
260 {
261 nlSetError(NL_NO_NETWORK);
262 (void)closesocket(sock);
263 return NL_FALSE;
264 }
265
266 (void)closesocket(sock);
267 return NL_TRUE;
268 }
269
ipx_GetPort(SOCKET socket)270 static NLushort ipx_GetPort(SOCKET socket)
271 {
272 struct sockaddr_ipx addr;
273 int len;
274
275 len = (int)sizeof(struct sockaddr_ipx);
276 if(getsockname(socket, (struct sockaddr *)&addr, &len) != 0)
277 {
278 return 0;
279 }
280
281 return ntohs(addr.sa_socket);
282 }
283
284
ipx_Init(void)285 NLboolean ipx_Init(void)
286 {
287 #ifdef WINDOWS_APP
288 WSADATA libmibWSAdata;
289
290 if(WSAStartup(0x101,&libmibWSAdata) != 0)
291 {
292 return NL_FALSE;
293 }
294 #endif
295 if(ipx_GetHostAddress(&ipx_ouraddress) == NL_FALSE)
296 {
297 ipx_Shutdown();
298 return NL_FALSE;
299 }
300
301 return NL_TRUE;
302 }
303
ipx_Shutdown(void)304 void ipx_Shutdown(void)
305 {
306 #ifdef WINDOWS_APP
307 (void)WSACleanup();
308 #endif
309 }
310
ipx_Listen(NLsocket socket)311 NLboolean ipx_Listen(NLsocket socket)
312 {
313 nl_socket_t *sock = nlSockets[socket];
314
315 if(sock->reliable == NL_TRUE)
316 {
317 if(listen((SOCKET)sock->realsocket, backlog) != 0)
318 {
319 nlSetError(NL_SYSTEM_ERROR);
320 return NL_FALSE;
321 }
322 }
323
324 sock->listen = NL_TRUE;
325 return NL_TRUE;
326 }
327
ipx_AcceptIPX(NLsocket nlsocket,struct sockaddr_ipx * newaddr)328 static SOCKET ipx_AcceptIPX(NLsocket nlsocket, struct sockaddr_ipx /*@out@*/ *newaddr)
329 {
330 nl_socket_t *sock = nlSockets[nlsocket];
331 struct sockaddr_ipx ouraddr;
332 SOCKET newsocket;
333 NLushort localport;
334 NLbyte buffer[NL_MAX_STRING_LENGTH];
335 socklen_t len = (socklen_t)sizeof(struct sockaddr_ipx);
336 NLint slen = (NLint)sizeof(NL_CONNECT_STRING);
337 NLbyte reply = (NLbyte)0x00;
338 NLint count = 0;
339
340 /* Get the packet and remote host address */
341 if(recvfrom((SOCKET)sock->realsocket, buffer, (int)sizeof(buffer), 0,
342 (struct sockaddr *)newaddr, &len) < (int)sizeof(NL_CONNECT_STRING))
343 {
344 nlSetError(NL_NO_PENDING);
345 return INVALID_SOCKET;
346 }
347 /* Let's check for the connection string */
348 buffer[slen - 1] = (NLbyte)0; /* null terminate for peace of mind */
349 if(strcmp(buffer, NL_CONNECT_STRING) != 0)
350 {
351 nlSetError(NL_NO_PENDING);
352 return INVALID_SOCKET;
353 }
354 /* open up a new socket on this end */
355 newsocket = socket(PF_IPX, SOCK_DGRAM, NSPROTO_IPX);
356 if(newsocket == INVALID_SOCKET)
357 {
358 nlSetError(NL_SYSTEM_ERROR);
359 (void)closesocket(newsocket);
360 return INVALID_SOCKET;
361 }
362
363 ouraddr.sa_family = AF_IPX;
364 memset(&ouraddr.sa_netnum, 0, 4);
365 memset(&ouraddr.sa_nodenum, 0, 6);
366 ouraddr.sa_socket = 0;
367
368 if(ipx_bind(newsocket, (struct sockaddr *)&ouraddr, len) == SOCKET_ERROR)
369 {
370 nlSetError(NL_SYSTEM_ERROR);
371 (void)closesocket(newsocket);
372 return INVALID_SOCKET;
373 }
374 /* get the new port */
375 localport = ipx_GetPort(newsocket);
376
377 /* create the return message */
378 writeShort(buffer, count, localport);
379 writeString(buffer, count, (NLchar *)TEXT(NL_REPLY_STRING));
380
381 /* send back the reply with our new port */
382 if(sendto((SOCKET)sock->realsocket, buffer, count, 0, (struct sockaddr *)newaddr,
383 (int)sizeof(struct sockaddr_ipx)) < count)
384 {
385 nlSetError(NL_SYSTEM_ERROR);
386 (void)closesocket(newsocket);
387 return INVALID_SOCKET;
388 }
389 /* send back a 0 length packet from our new port, needed for firewalls */
390 if(sendto(newsocket, &reply, 0, 0,
391 (struct sockaddr *)newaddr,
392 (int)sizeof(struct sockaddr_ipx)) < 0)
393 {
394 nlSetError(NL_SYSTEM_ERROR);
395 (void)closesocket(newsocket);
396 return INVALID_SOCKET;
397 }
398 /* connect the socket */
399 if(connect(newsocket, (struct sockaddr *)newaddr,
400 (int)sizeof(struct sockaddr_ipx)) == SOCKET_ERROR)
401 {
402 nlSetError(NL_SYSTEM_ERROR);
403 (void)closesocket(newsocket);
404 return INVALID_SOCKET;
405 }
406
407 return newsocket;
408 }
409
ipx_AcceptConnection(NLsocket socket)410 NLsocket ipx_AcceptConnection(NLsocket socket)
411 {
412 nl_socket_t *sock = nlSockets[socket];
413 nl_socket_t *newsock;
414 NLsocket newsocket;
415 SOCKET realsocket;
416 struct sockaddr_ipx newaddr;
417
418 if(sock->listen == NL_FALSE)
419 {
420 nlSetError(NL_NOT_LISTEN);
421 return NL_INVALID;
422 }
423
424 if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS)
425 {
426 NLint len = (NLint)sizeof(newaddr);
427
428 realsocket = accept((SOCKET)sock->realsocket,
429 (struct sockaddr *)&newaddr, &len);
430
431 if(realsocket == INVALID_SOCKET)
432 {
433 if(sockerrno == EWOULDBLOCK || errno == EAGAIN)/* yes, we need to use errno here */
434 {
435 nlSetError(NL_NO_PENDING);
436 }
437 else
438 {
439 nlSetError(NL_SYSTEM_ERROR);
440 }
441 return NL_INVALID;
442 }
443 }
444 else if(sock->type == NL_UNRELIABLE)
445 {
446 realsocket = ipx_AcceptIPX(socket, &newaddr);
447
448 if(realsocket == INVALID_SOCKET)
449 {
450 /* error is already set in sock_AcceptUDP */
451 return NL_INVALID;
452 }
453 }
454 else
455 {
456 nlSetError(NL_WRONG_TYPE);
457 return NL_INVALID;
458 }
459
460 newsocket = nlGetNewSocket();
461 if(newsocket == NL_INVALID)
462 {
463 return NL_INVALID;
464 }
465 if(nlLockSocket(newsocket, NL_BOTH) == NL_FALSE)
466 {
467 return NL_INVALID;
468 }
469 newsock = nlSockets[newsocket];
470
471 /* update the remote address */
472 memcpy((char *)&newsock->addressin, (char *)&newaddr, sizeof(struct sockaddr_ipx));
473 newsock->realsocket = (NLint)realsocket;
474 newsock->localport = ipx_GetPort(realsocket);
475 newsock->remoteport = ipx_GetPortFromAddr((NLaddress *)&newsock->addressin);
476
477 if(newsock->blocking == NL_FALSE)
478 {
479 if(ipx_SetNonBlocking((SOCKET)newsock->realsocket) == NL_FALSE)
480 {
481 nlSetError(NL_SYSTEM_ERROR);
482 ipx_Close(newsocket);
483 return NL_INVALID;
484 }
485 }
486
487 newsock->reliable = sock->reliable;
488
489 return newsocket;
490 }
491
ipx_Open(NLushort port,NLenum type)492 NLsocket ipx_Open(NLushort port, NLenum type)
493 {
494 nl_socket_t *newsock;
495 NLsocket newsocket;
496 SOCKET realsocket;
497
498 switch (type) {
499
500 case NL_RELIABLE:
501 case NL_RELIABLE_PACKETS:
502 realsocket = socket(PF_IPX, SOCK_SEQPACKET, NSPROTO_SPXII);
503 break;
504
505 case NL_UNRELIABLE:
506 case NL_BROADCAST:
507 realsocket = socket(PF_IPX, SOCK_DGRAM, NSPROTO_IPX);
508 break;
509
510 default:
511 nlSetError(NL_INVALID_ENUM);
512 return NL_INVALID;
513 }
514
515 if(realsocket == INVALID_SOCKET)
516 {
517 nlSetError(NL_SYSTEM_ERROR);
518 return NL_INVALID;
519 }
520
521 newsocket = nlGetNewSocket();
522 if(newsocket == NL_INVALID)
523 {
524 return NL_INVALID;
525 }
526 if(nlLockSocket(newsocket, NL_BOTH) == NL_FALSE)
527 {
528 return NL_INVALID;
529 }
530 newsock = nlSockets[newsocket];
531 newsock->realsocket = (NLint)realsocket;
532
533 if(type == NL_RELIABLE || type == NL_RELIABLE_PACKETS)
534 {
535 newsock->reliable = NL_TRUE;
536 }
537 else
538 {
539 newsock->reliable = NL_FALSE;
540 }
541
542 ipx_SetReuseAddr(realsocket);
543
544 if(newsock->blocking == NL_FALSE)
545 {
546 if(ipx_SetNonBlocking(realsocket) == NL_FALSE)
547 {
548 nlSetError(NL_SYSTEM_ERROR);
549 nlUnlockSocket(newsocket, NL_BOTH);
550 ipx_Close(newsocket);
551 return NL_INVALID;
552 }
553 }
554
555 ((struct sockaddr_ipx *)&newsock->addressin)->sa_family = AF_IPX;
556 memset(((struct sockaddr_ipx *)&newsock->addressin)->sa_netnum, 0, 4);
557 memset(((struct sockaddr_ipx *)&newsock->addressin)->sa_nodenum, 0, 6);
558 ((struct sockaddr_ipx *)&newsock->addressin)->sa_socket = htons((unsigned short)port);
559
560 if(ipx_bind((SOCKET)realsocket, (struct sockaddr *)&newsock->addressin, (int)sizeof(newsock->addressin)) == SOCKET_ERROR)
561 {
562 nlSetError(NL_SYSTEM_ERROR);
563 nlUnlockSocket(newsocket, NL_BOTH);
564 ipx_Close(newsocket);
565 return NL_INVALID;
566 }
567 if(type == NL_BROADCAST)
568 {
569 ((struct sockaddr_ipx *)&newsock->addressout)->sa_family = AF_IPX;
570 memset(((struct sockaddr_ipx *)&newsock->addressout)->sa_netnum, 0, 4);
571 memset(((struct sockaddr_ipx *)&newsock->addressout)->sa_nodenum, 0xff, 6);
572 ((struct sockaddr_ipx *)&newsock->addressout)->sa_socket = htons((unsigned short)port);
573 if(ipx_SetBroadcast(realsocket) == NL_FALSE)
574 {
575 nlSetError(NL_SYSTEM_ERROR);
576 nlUnlockSocket(newsocket, NL_BOTH);
577 return NL_INVALID;
578 }
579 }
580
581 newsock->localport = ipx_GetPort(realsocket);
582 newsock->type = type;
583 nlUnlockSocket(newsocket, NL_BOTH);
584 return newsocket;
585 }
586
ipx_ConnectIPX(NLsocket socket,const NLaddress * address)587 static NLboolean ipx_ConnectIPX(NLsocket socket, const NLaddress *address)
588 {
589 nl_socket_t *sock = nlSockets[socket];
590 time_t begin, t;
591
592 if(sendto((SOCKET)sock->realsocket, (char *)NL_CONNECT_STRING, (NLint)sizeof(NL_CONNECT_STRING),
593 0, (struct sockaddr *)address, (int)sizeof(struct sockaddr_ipx))
594 == SOCKET_ERROR)
595 {
596 if(sock->blocking == NL_TRUE)
597 {
598 nlSetError(NL_SYSTEM_ERROR);
599 }
600 else
601 {
602 sock->conerror = NL_TRUE;
603 }
604 return NL_FALSE;
605 }
606
607 (void)time(&begin);
608
609 /* try for six seconds */
610 while((time(&t) - begin) < 6)
611 {
612 NLbyte buffer[NL_MAX_STRING_LENGTH];
613 NLbyte *pbuffer = buffer;
614 NLushort newport;
615 NLint slen = (NLint)(sizeof(NL_REPLY_STRING) + sizeof(newport));
616 NLint received;
617 NLbyte reply = (NLbyte)0;
618 socklen_t len = (socklen_t)sizeof(struct sockaddr_ipx);
619
620 received = recvfrom((SOCKET)sock->realsocket, (char *)buffer, (int)sizeof(buffer), 0,
621 (struct sockaddr *)&sock->addressin, &len);
622
623 if(received == SOCKET_ERROR)
624 {
625 if(sockerrno != EWOULDBLOCK)
626 {
627 if(sock->blocking == NL_TRUE)
628 {
629 nlSetError(NL_CON_REFUSED);
630 }
631 else
632 {
633 sock->conerror = NL_TRUE;
634 }
635 return NL_FALSE;
636 }
637 }
638 if(received >= slen)
639 {
640 NLint count = 0;
641
642 /* retrieve the port number */
643 readShort(buffer, count, newport);
644 ((struct sockaddr_ipx *)&sock->addressin)->sa_socket = htons(newport);
645 /* Lets check for the reply string */
646 pbuffer[slen - 1] = (NLbyte)0; /* null terminate for peace of mind */
647 pbuffer += sizeof(newport);
648 if(strcmp(pbuffer, NL_REPLY_STRING) == 0)
649 {
650 if(connect((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin,
651 (int)sizeof(struct sockaddr_ipx)) == SOCKET_ERROR)
652 {
653 if(sock->blocking == NL_TRUE)
654 {
655 nlSetError(NL_SYSTEM_ERROR);
656 }
657 else
658 {
659 sock->conerror = NL_TRUE;
660 }
661 return NL_FALSE;
662 }
663 /* send back a 0 length packet to the new port, needed for firewalls */
664 if(send((SOCKET)sock->realsocket, &reply, 0, 0) == SOCKET_ERROR)
665 {
666 if(sock->blocking == NL_TRUE)
667 {
668 nlSetError(NL_SYSTEM_ERROR);
669 }
670 else
671 {
672 sock->conerror = NL_TRUE;
673 }
674 return NL_FALSE;
675 }
676 /* success! */
677 sock->localport = ipx_GetPort((SOCKET)sock->realsocket);
678 sock->remoteport = ipx_GetPortFromAddr((NLaddress *)&sock->addressin);
679 sock->connected = NL_TRUE;
680 sock->connecting = NL_FALSE;
681 return NL_TRUE;
682 }
683 }
684 nlThreadSleep(NL_CONNECT_SLEEP);
685 }
686
687 if(sock->blocking == NL_TRUE)
688 {
689 nlSetError(NL_CON_REFUSED);
690 }
691 else
692 {
693 sock->conerror = NL_TRUE;
694 }
695 return NL_FALSE;
696 }
697
ipx_ConnectIPXAsynchInt(void * addr)698 static void *ipx_ConnectIPXAsynchInt(void /*@owned@*/*addr)
699 {
700 NLaddress_ex_t *address = (NLaddress_ex_t *)addr;
701
702 (void)ipx_ConnectIPX(address->socket, address->address);
703 free(addr);
704 return NULL;
705 }
706
ipx_ConnectIPXAsynch(NLsocket socket,const NLaddress * address)707 static NLboolean ipx_ConnectIPXAsynch(NLsocket socket, const NLaddress *address)
708 {
709 NLaddress_ex_t /*@dependent@*/*addr;
710 nl_socket_t *sock = nlSockets[socket];
711
712 addr = (NLaddress_ex_t *)malloc(sizeof(NLaddress_ex_t));
713 if(addr == NULL)
714 {
715 nlSetError(NL_OUT_OF_MEMORY);
716 return NL_FALSE;
717 }
718 addr->address = (NLaddress *)address;
719 addr->socket = socket;
720 sock->connecting = NL_TRUE;
721 sock->conerror = NL_FALSE;
722 if(nlThreadCreate(ipx_ConnectIPXAsynchInt, (void *)addr, NL_FALSE) == (NLthreadID)NL_INVALID)
723 {
724 return NL_FALSE;
725 }
726 return NL_TRUE;
727 }
728
ipx_Connect(NLsocket socket,const NLaddress * address)729 NLboolean ipx_Connect(NLsocket socket, const NLaddress *address)
730 {
731 nl_socket_t *sock = nlSockets[socket];
732
733 memcpy((char *)&sock->addressin, (char *)address, sizeof(struct sockaddr_ipx));
734
735 if((sock->type == NL_RELIABLE) || (sock->type == NL_RELIABLE_PACKETS))
736 {
737 if(sock->blocking == NL_FALSE)
738 {
739 (void)ipx_SetBlocking((SOCKET)sock->realsocket);
740 }
741
742 if(connect((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin,
743 (int)sizeof(struct sockaddr_ipx)) != 0)
744 {
745 if(sock->blocking == NL_FALSE &&
746 (sockerrno == EWOULDBLOCK || sockerrno == EINPROGRESS))
747 {
748 sock->connecting = NL_TRUE;
749 }
750 else
751 {
752 nlSetError(NL_SYSTEM_ERROR);
753 return NL_FALSE;
754 }
755 }
756 if(sock->blocking == NL_FALSE)
757 {
758 (void)ipx_SetNonBlocking((SOCKET)sock->realsocket);
759 }
760 sock->localport = ipx_GetPort((SOCKET)sock->realsocket);
761 sock->remoteport = ipx_GetPortFromAddr((NLaddress *)&sock->addressin);
762 sock->connected = NL_TRUE;
763 }
764 else if(sock->type == NL_UNRELIABLE)
765 {
766 if(sock->blocking == NL_TRUE)
767 {
768 return ipx_ConnectIPX(socket, &sock->addressin);
769 }
770 else
771 {
772 return ipx_ConnectIPXAsynch(socket, &sock->addressin);
773 }
774 }
775 else
776 {
777 nlSetError(NL_WRONG_TYPE);
778 }
779
780 return NL_TRUE;
781 }
782
ipx_Close(NLsocket socket)783 void ipx_Close(NLsocket socket)
784 {
785 nl_socket_t *sock = nlSockets[socket];
786
787 if((sock->type == NL_RELIABLE_PACKETS || sock->type == NL_RELIABLE) && sock->listen == NL_FALSE)
788 {
789 struct linger l = {1, 10};
790
791 (void)setsockopt((SOCKET)sock->realsocket, SOL_SOCKET, SO_LINGER, (const char *)&l, (int)sizeof(l));
792 }
793 (void)closesocket((SOCKET)sock->realsocket);
794 }
795
ipx_Read(NLsocket socket,NLvoid * buffer,NLint nbytes)796 NLint ipx_Read(NLsocket socket, NLvoid *buffer, NLint nbytes)
797 {
798 nl_socket_t *sock = nlSockets[socket];
799 NLint count;
800
801 if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS)
802 {
803 /* check for a non-blocking connection pending */
804 if(sock->connecting == NL_TRUE)
805 {
806 fd_set fdset;
807 struct timeval t = {0,0};
808
809 FD_ZERO(&fdset);
810 FD_SET((SOCKET)sock->realsocket, &fdset);
811 if(select(sock->realsocket + 1, NULL, &fdset, NULL, &t) == 1)
812 {
813 /* the connect has completed */
814 sock->connected = NL_TRUE;
815 sock->connecting = NL_FALSE;
816 }
817 else
818 {
819 /* check for a failed connect */
820 FD_ZERO(&fdset);
821 FD_SET((SOCKET)sock->realsocket, &fdset);
822 if(select(sock->realsocket + 1, NULL, NULL, &fdset, &t) == 1)
823 {
824 nlSetError(NL_CON_REFUSED);
825 }
826 else
827 {
828 nlSetError(NL_CON_PENDING);
829 }
830 return NL_INVALID;
831 }
832 }
833 count = recv((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
834 }
835 else
836 {
837 /* check for a non-blocking connection pending */
838 if(sock->connecting == NL_TRUE)
839 {
840 nlSetError(NL_CON_PENDING);
841 return NL_INVALID;
842 }
843 /* check for a connection error */
844 if(sock->conerror == NL_TRUE)
845 {
846 nlSetError(NL_CON_REFUSED);
847 return NL_INVALID;
848 }
849 if(sock->connected == NL_TRUE)
850 {
851 count = recv((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
852 }
853 else
854 {
855 socklen_t len = (socklen_t)sizeof(struct sockaddr_ipx);
856
857 count = recvfrom((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0,
858 (struct sockaddr *)&sock->addressin, &len);
859 }
860 }
861 if(count == SOCKET_ERROR)
862 {
863 return ipx_Error();
864 }
865 return count;
866 }
867
ipx_Write(NLsocket socket,const NLvoid * buffer,NLint nbytes)868 NLint ipx_Write(NLsocket socket, const NLvoid *buffer, NLint nbytes)
869 {
870 nl_socket_t *sock = nlSockets[socket];
871 NLint count;
872
873 if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS)
874 {
875 if(sock->connecting == NL_TRUE)
876 {
877 fd_set fdset;
878 struct timeval t = {0,0};
879
880 FD_ZERO(&fdset);
881 FD_SET((SOCKET)(sock->realsocket), &fdset);
882 if(select(sock->realsocket + 1, NULL, &fdset, NULL, &t) == 1)
883 {
884 /* the connect has completed */
885 sock->connected = NL_TRUE;
886 sock->connecting = NL_FALSE;
887 }
888 else
889 {
890 /* check for a failed connect */
891 FD_ZERO(&fdset);
892 FD_SET((SOCKET)sock->realsocket, &fdset);
893 if(select(sock->realsocket + 1, NULL, NULL, &fdset, &t) == 1)
894 {
895 nlSetError(NL_CON_REFUSED);
896 }
897 else
898 {
899 nlSetError(NL_CON_PENDING);
900 }
901 return NL_INVALID;
902 }
903 }
904 count = send((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
905 }
906 else /* IPX */
907 {
908 /* check for a non-blocking connection pending */
909 if(sock->connecting == NL_TRUE)
910 {
911 nlSetError(NL_CON_PENDING);
912 return NL_INVALID;
913 }
914 /* check for a connection error */
915 if(sock->conerror == NL_TRUE)
916 {
917 nlSetError(NL_CON_REFUSED);
918 return NL_INVALID;
919 }
920 if(nbytes > 1466)
921 {
922 nlSetError(NL_PACKET_SIZE);
923 return NL_INVALID;
924 }
925 if(sock->connected == NL_TRUE)
926 {
927 count = send((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
928 }
929 else
930 {
931 count = sendto((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0,
932 (struct sockaddr *)&sock->addressout,
933 (int)sizeof(struct sockaddr_ipx));
934 }
935 }
936 if(count == SOCKET_ERROR)
937 {
938 return ipx_Error();
939 }
940 return count;
941 }
942
ipx_AddrToString(const NLaddress * address,NLchar * string)943 NLchar *ipx_AddrToString(const NLaddress *address, NLchar *string)
944 {
945 _stprintf(string, TEXT("%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u"),
946 (unsigned int)((struct sockaddr_ipx *)address)->sa_netnum[0] & 0xff,
947 (unsigned int)((struct sockaddr_ipx *)address)->sa_netnum[1] & 0xff,
948 (unsigned int)((struct sockaddr_ipx *)address)->sa_netnum[2] & 0xff,
949 (unsigned int)((struct sockaddr_ipx *)address)->sa_netnum[3] & 0xff,
950 (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[0] & 0xff,
951 (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[1] & 0xff,
952 (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[2] & 0xff,
953 (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[3] & 0xff,
954 (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[4] & 0xff,
955 (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[5] & 0xff,
956 ntohs(((struct sockaddr_ipx *)address)->sa_socket));
957 return string;
958 }
959
ipx_StringToAddr(const NLchar * string,NLaddress * address)960 NLboolean ipx_StringToAddr(const NLchar *string, NLaddress *address)
961 {
962 int val;
963 NLchar buffer[3];
964
965 buffer[2] = (NLchar)0;
966 memset(address, 0, sizeof(NLaddress));
967 ((struct sockaddr_ipx *)address)->sa_family = AF_IPX;
968 address->valid = NL_FALSE;
969
970 #define DO(src,dest) \
971 buffer[0] = string[(sizeof(NLchar) * src)]; \
972 buffer[1] = string[src + 1]; \
973 if(_stscanf (buffer, (const NLchar *)TEXT("%x"), &val) != 1) \
974 return NL_FALSE; \
975 ((struct sockaddr_ipx *)address)->dest = (char)val
976
977 DO(0, sa_netnum[0]);
978 DO(2, sa_netnum[1]);
979 DO(4, sa_netnum[2]);
980 DO(6, sa_netnum[3]);
981 DO(9, sa_nodenum[0]);
982 DO(11, sa_nodenum[1]);
983 DO(13, sa_nodenum[2]);
984 DO(15, sa_nodenum[3]);
985 DO(17, sa_nodenum[4]);
986 DO(19, sa_nodenum[5]);
987 #undef DO
988
989 (void)_stscanf(&string[(sizeof(NLchar) * 22)], (const NLchar *)TEXT("%d"), &val);
990 ((struct sockaddr_ipx *)address)->sa_socket = htons((unsigned short)val);
991 address->valid = NL_TRUE;
992 return NL_TRUE;
993 }
994
ipx_GetLocalAddr(NLsocket socket,NLaddress * address)995 NLboolean ipx_GetLocalAddr(NLsocket socket, NLaddress *address)
996 {
997 nl_socket_t *sock = nlSockets[socket];
998
999 memcpy(address, &ipx_ouraddress, sizeof(NLaddress));
1000 ipx_SetAddrPort(address, sock->localport);
1001 address->valid = NL_TRUE;
1002 return NL_TRUE;
1003 }
1004
ipx_GetAllLocalAddr(NLint * count)1005 NLaddress *ipx_GetAllLocalAddr(NLint *count)
1006 {
1007 *count = 1;
1008 memcpy(&ipx_ouraddress_copy, &ipx_ouraddress, sizeof(NLaddress));
1009 ipx_ouraddress_copy.valid = NL_TRUE;
1010 return &ipx_ouraddress_copy;
1011 }
1012
ipx_SetLocalAddr(const NLaddress * address)1013 NLboolean ipx_SetLocalAddr(const NLaddress *address)
1014 {
1015 memcpy(&ipx_ouraddress, address, sizeof(NLaddress));
1016 return NL_TRUE;
1017 }
1018
ipx_GetNameFromAddr(const NLaddress * address,NLchar * name)1019 NLchar *ipx_GetNameFromAddr(const NLaddress *address, NLchar *name)
1020 {
1021 return ipx_AddrToString(address, name);
1022 }
1023
ipx_GetNameFromAddrAsync(const NLaddress * address,NLchar * name)1024 NLboolean ipx_GetNameFromAddrAsync(const NLaddress *address, NLchar *name)
1025 {
1026 (void)ipx_AddrToString(address, name);
1027 return NL_TRUE;
1028 }
1029
ipx_GetAddrFromName(const NLchar * name,NLaddress * address)1030 NLboolean ipx_GetAddrFromName(const NLchar *name, NLaddress *address)
1031 {
1032 NLint n;
1033 NLchar buffer[(sizeof(NLchar) * 32)];
1034
1035 address->valid = NL_TRUE;
1036 n = (NLint)_tcslen(name);
1037
1038 if(n == (sizeof(NLchar) * 12))
1039 {
1040 _stprintf(buffer, TEXT("00000000:%s:%d"), name, ipxport);
1041 return ipx_StringToAddr (buffer, address);
1042 }
1043 if(n == (sizeof(NLchar) * 21))
1044 {
1045 _stprintf(buffer, TEXT("%s:%d"), name, ipxport);
1046 return ipx_StringToAddr (buffer, address);
1047 }
1048 if((n > (sizeof(NLchar) * 21)) && (n <= (sizeof(NLchar) * 27)))
1049 {
1050 return ipx_StringToAddr (name, address);
1051 }
1052 memset(address, 0, sizeof(NLaddress));
1053 address->valid = NL_FALSE;
1054 return NL_FALSE;
1055 }
1056
ipx_GetAddrFromNameAsync(const NLchar * name,NLaddress * address)1057 NLboolean ipx_GetAddrFromNameAsync(const NLchar *name, NLaddress *address)
1058 {
1059 return ipx_GetAddrFromName(name, address);
1060 }
1061
ipx_AddrCompare(const NLaddress * address1,const NLaddress * address2)1062 NLboolean ipx_AddrCompare(const NLaddress *address1, const NLaddress *address2)
1063 {
1064 if(((struct sockaddr_ipx *)address1)->sa_family != ((struct sockaddr_ipx *)address2)->sa_family)
1065 return NL_FALSE;
1066
1067 if(memcmp(((struct sockaddr_ipx *)address1)->sa_netnum, ((struct sockaddr_ipx *)address2)->sa_netnum, 4) != 0)
1068 return NL_FALSE;
1069 if(memcmp(((struct sockaddr_ipx *)address1)->sa_nodenum, ((struct sockaddr_ipx *)address2)->sa_nodenum, 6) != 0)
1070 return NL_FALSE;
1071
1072 if(((struct sockaddr_ipx *)address1)->sa_socket != ((struct sockaddr_ipx *)address2)->sa_socket)
1073 return NL_FALSE;
1074
1075 return NL_TRUE;
1076 }
1077
ipx_GetPortFromAddr(const NLaddress * address)1078 NLushort ipx_GetPortFromAddr(const NLaddress *address)
1079 {
1080 return ntohs(((struct sockaddr_ipx *)address)->sa_socket);
1081 }
1082
ipx_SetAddrPort(NLaddress * address,NLushort port)1083 void ipx_SetAddrPort(NLaddress *address, NLushort port)
1084 {
1085 ((struct sockaddr_ipx *)address)->sa_socket = htons((NLushort)port);
1086 }
1087
ipx_GetSystemError(void)1088 NLint ipx_GetSystemError(void)
1089 {
1090 NLint err = sockerrno;
1091
1092 #ifdef WINDOWS_APP
1093 if(err < WSABASEERR)
1094 {
1095 if(errno > 0)
1096 {
1097 err = errno;
1098 }
1099 }
1100 #endif
1101 return err;
1102 }
1103
ipx_PollGroup(NLint group,NLenum name,NLsocket * sockets,NLint number,NLint timeout)1104 NLint ipx_PollGroup(NLint group, NLenum name, NLsocket *sockets, NLint number, NLint timeout)
1105 {
1106 NLint numselect, count = 0;
1107 NLint numsockets = NL_MAX_GROUP_SOCKETS;
1108 NLsocket temp[NL_MAX_GROUP_SOCKETS];
1109 NLsocket *ptemp = temp;
1110 fd_set fdset;
1111 SOCKET highest;
1112 struct timeval t = {0,0}; /* {seconds, useconds}*/
1113 struct timeval *tp = &t;
1114 NLboolean result;
1115
1116 nlGroupLock();
1117 highest = nlGroupGetFdset(group, &fdset);
1118
1119 if(highest == INVALID_SOCKET)
1120 {
1121 /* error is set by nlGroupGetFdset */
1122 nlGroupUnlock();
1123 return NL_INVALID;
1124 }
1125
1126 result = nlGroupGetSocketsINT(group, ptemp, &numsockets);
1127 nlGroupUnlock();
1128
1129 if(result == NL_FALSE)
1130 {
1131 /* any error is set by nlGroupGetSockets */
1132 return NL_INVALID;
1133 }
1134 if(numsockets == 0)
1135 {
1136 return 0;
1137 }
1138
1139 /* check for full blocking call */
1140 if(timeout < 0)
1141 {
1142 tp = NULL;
1143 }
1144 else /* set t values */
1145 {
1146 t.tv_sec = timeout/1000;
1147 t.tv_usec = (timeout%1000) * 1000;
1148 }
1149
1150 /* call select to check the status */
1151 switch(name) {
1152
1153 case NL_READ_STATUS:
1154 numselect = select((int)highest, &fdset, NULL, NULL, tp);
1155 break;
1156
1157 case NL_WRITE_STATUS:
1158 numselect = select((int)highest, NULL, &fdset, NULL, tp);
1159 break;
1160
1161 case NL_ERROR_STATUS:
1162 numselect = select((int)highest, NULL, NULL, &fdset, tp);
1163 break;
1164
1165 default:
1166 nlSetError(NL_INVALID_ENUM);
1167 return NL_INVALID;
1168 }
1169 if(numselect == SOCKET_ERROR)
1170 {
1171 if(sockerrno == ENOTSOCK)
1172 {
1173 /* one of the sockets has been closed */
1174 nlSetError(NL_INVALID_SOCKET);
1175 }
1176 else if(sockerrno == EINTR)
1177 {
1178 /* select was interrupted by the system, maybe because the app is exiting */
1179 return 0;
1180 }
1181 else
1182 {
1183 nlSetError(NL_SYSTEM_ERROR);
1184 }
1185 return NL_INVALID;
1186 }
1187
1188 if(numselect > number)
1189 {
1190 nlSetError(NL_BUFFER_SIZE);
1191 return NL_INVALID;
1192 }
1193 /* fill *sockets with a list of the sockets ready to be read */
1194 while(numsockets-- > 0 && numselect > count)
1195 {
1196 if(FD_ISSET(nlSockets[*ptemp]->realsocket, &fdset) != 0)
1197 {
1198 *sockets = *ptemp;
1199 sockets++;
1200 count ++;
1201 }
1202 ptemp++;
1203 }
1204 return count;
1205 }
1206
ipx_Hint(NLenum name,NLint arg)1207 NLboolean ipx_Hint(NLenum name, NLint arg)
1208 {
1209 switch(name) {
1210
1211 case NL_LISTEN_BACKLOG:
1212 backlog = arg;
1213 break;
1214
1215 case NL_REUSE_ADDRESS:
1216 reuseaddress = (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE);
1217 break;
1218
1219 default:
1220 nlSetError(NL_INVALID_ENUM);
1221 return NL_FALSE;
1222 }
1223 return NL_TRUE;
1224 }
1225
1226 #endif /* NL_INCLUDE_IPX */
1227