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