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 <string.h>
24 #include "nlinternal.h"
25 #include "sock.h"
26 #include "serial.h"
27 #include "parallel.h"
28 
29 #ifdef NL_INCLUDE_LOOPBACK
30 #include "loopback.h"
31 #endif
32 
33 #if defined WINDOWS_APP && defined NL_INCLUDE_IPX
34   #include "ipx.h"
35 #endif
36 
37 #define MAX_NET_DRIVERS     6
38 
39 volatile nl_state_t nlState = {NL_FALSE, NL_TRUE};
40 
41 /* mutexes for global variables */
42 static NLmutex  socklock, instatlock, outstatlock;
43 
44 static volatile NLboolean nlBlocking = NL_FALSE;
45 
46 static volatile nl_stats_t nlInstats;
47 static volatile nl_stats_t nlOutstats;
48 
49 static volatile NLsocket nlNextsocket = 0;
50 static volatile NLint nlNumsockets = 0;
51 static volatile NLint nlMaxNumsockets = NL_MIN_SOCKETS; /* this is dynamic, and can grow as needed */
52 static volatile NLint nlInitCount = 0;
53 
54 pnl_socket_t *nlSockets = NULL;
55 
56 /* the current selected driver */
57 static nl_netdriver_t /*@null@*/*driver = NULL;
58 
59 static nl_netdriver_t netdrivers[] =
60 {
61     {
62         (NLchar*)TEXT("NL_IP"),
63         (NLchar*)TEXT("NL_RELIABLE NL_UNRELIABLE NL_RELIABLE_PACKETS NL_BROADCAST NL_UDP_MULTICAST NL_MULTICAST"),
64         NL_IP,
65         NL_FALSE,
66         sock_Init,
67         sock_Shutdown,
68         sock_Listen,
69         sock_AcceptConnection,
70         sock_Open,
71         sock_Connect,
72         sock_Close,
73         sock_Read,
74         sock_Write,
75         sock_AddrToString,
76         sock_StringToAddr,
77         sock_GetLocalAddr,
78         NULL,
79         sock_SetLocalAddr,
80         NULL,
81         NULL,
82         NULL,
83         NULL,
84         sock_AddrCompare,
85         sock_GetPortFromAddr,
86         sock_SetAddrPort,
87         sock_GetSystemError,
88         sock_PollGroup,
89         sock_Hint
90     }
91 #ifdef NL_INCLUDE_LOOPBACK
92     ,
93     {
94         (NLchar*)TEXT("NL_LOOP_BACK"),
95         (NLchar*)TEXT("NL_RELIABLE NL_UNRELIABLE NL_RELIABLE_PACKETS NL_BROADCAST"),
96         NL_LOOP_BACK,
97         NL_FALSE,
98         loopback_Init,
99         loopback_Shutdown,
100         loopback_Listen,
101         loopback_AcceptConnection,
102         loopback_Open,
103         loopback_Connect,
104         loopback_Close,
105         loopback_Read,
106         loopback_Write,
107         loopback_AddrToString,
108         loopback_StringToAddr,
109         loopback_GetLocalAddr,
110         loopback_GetAllLocalAddr,
111         loopback_SetLocalAddr,
112         loopback_GetNameFromAddr,
113         loopback_GetNameFromAddrAsync,
114         loopback_GetAddrFromName,
115         loopback_GetAddrFromNameAsync,
116         loopback_AddrCompare,
117         loopback_GetPortFromAddr,
118         loopback_SetAddrPort,
119         loopback_GetSystemError,
120         loopback_PollGroup,
121         loopback_Hint
122     }
123 #endif /* NL_INCLUDE_LOOPBACK */
124 #if defined WINDOWS_APP && defined NL_INCLUDE_IPX
125     ,
126     {
127         (NLchar*)TEXT("NL_IPX"),
128         (NLchar*)TEXT("NL_RELIABLE NL_UNRELIABLE NL_RELIABLE_PACKETS NL_BROADCAST"),
129         NL_IPX,
130         NL_FALSE,
131         ipx_Init,
132         ipx_Shutdown,
133         ipx_Listen,
134         ipx_AcceptConnection,
135         ipx_Open,
136         ipx_Connect,
137         ipx_Close,
138         ipx_Read,
139         ipx_Write,
140         ipx_AddrToString,
141         ipx_StringToAddr,
142         ipx_GetLocalAddr,
143         ipx_GetAllLocalAddr,
144         ipx_SetLocalAddr,
145         ipx_GetNameFromAddr,
146         ipx_GetNameFromAddrAsync,
147         ipx_GetAddrFromName,
148         ipx_GetAddrFromNameAsync,
149         ipx_AddrCompare,
150         ipx_GetPortFromAddr,
151         ipx_SetAddrPort,
152         ipx_GetSystemError,
153         ipx_PollGroup,
154         ipx_Hint
155     }
156 #endif /* WINDOWS_APP && NL_INCLUDE_IPX */
157     ,
158     {
159         (NLchar*)NULL,
160     }
161 };
162 
163 
164 
165 #define	MIN(X,Y)	((X) < (Y) ? (X) : (Y))
166 
167 
168 /*
169 
170  Internal helper functions.
171 
172 */
173 
isSafeString(const NLchar * string)174 static NLboolean isSafeString(const NLchar *string)
175 {
176     int i;
177     NLboolean   nullfound = NL_FALSE;
178 
179     /* make sure string is null terminated at less than NL_MAX_STRING_LENGTH */
180     for(i=0;i<NL_MAX_STRING_LENGTH;i++)
181     {
182         if(string[i] == (NLchar)'\0')
183         {
184             nullfound = NL_TRUE;
185             break;
186         }
187     }
188     if(nullfound == NL_FALSE)
189     {
190         return NL_FALSE;
191     }
192     /* check for formating characters */
193     if(_tcsrchr(string, '%') != NULL)
194     {
195         return NL_FALSE;
196     }
197     return NL_TRUE;
198 }
199 
safecat(NLchar * dest,const NLchar * src)200 static void safecat(NLchar *dest, const NLchar *src)
201 {
202     int len;
203 
204     if(isSafeString(dest) != NL_TRUE || isSafeString(src) != NL_TRUE)
205     {
206         /* don't do anything */
207         return;
208     }
209     len = (int)_tcslen(dest);
210     if( len < (NL_MAX_STRING_LENGTH - 1))
211     {
212         _tcsncat(dest, src, (size_t)(NL_MAX_STRING_LENGTH - len));
213         dest[NL_MAX_STRING_LENGTH - 1] = (NLchar)'\0';
214     }
215 }
216 
nlGetNewSocket(void)217 NLsocket nlGetNewSocket(void)
218 {
219     NLsocket    newsocket = NL_INVALID;
220     nl_socket_t *sock = NULL;
221 
222     if(nlMutexLock(&socklock) == NL_FALSE)
223     {
224         return NL_INVALID;
225     }
226     if(nlNumsockets == nlMaxNumsockets)
227     {
228         nl_socket_t **temp;
229         NLint       tempmaxnumsockets = nlMaxNumsockets;
230 
231         /* expand the list of sockets pointers */
232         tempmaxnumsockets *= 2;
233         temp = (nl_socket_t **)realloc((void *)nlSockets, tempmaxnumsockets * sizeof(nl_socket_t *));
234         if(temp == NULL)
235         {
236             (void)nlMutexUnlock(&socklock);
237             nlSetError(NL_OUT_OF_MEMORY);
238             return NL_INVALID;
239         }
240         nlSockets = temp;
241         nlMaxNumsockets = tempmaxnumsockets;
242     }
243     /* get a socket number */
244     if(nlNumsockets == (NLint)nlNextsocket)
245     {
246         newsocket = nlNextsocket++;
247         /* allocate the memory */
248         sock = (nl_socket_t *)malloc(sizeof(nl_socket_t));
249         if(sock == NULL)
250         {
251             (void)nlMutexUnlock(&socklock);
252             nlSetError(NL_OUT_OF_MEMORY);
253             return NL_INVALID;
254         }
255         else
256         {
257             nlSockets[newsocket] = sock;
258         }
259         /* clear the structure */
260         memset(sock, 0, sizeof(nl_socket_t));
261 
262         if(nlMutexInit(&sock->readlock) == NL_FALSE || nlMutexInit(&sock->writelock) == NL_FALSE)
263         {
264             (void)nlMutexUnlock(&socklock);
265             return NL_INVALID;
266         }
267     }
268     else
269     /* there is an open socket slot somewhere below nlNextsocket */
270     {
271         NLsocket    i;
272         NLmutex     readlock, writelock;
273 
274         for(i=0;i<nlNextsocket;i++)
275         {
276             if(nlSockets[i]->inuse == NL_FALSE)
277             {
278                 /* found an open socket slot */
279                 newsocket = i;
280                 sock = nlSockets[i];
281                 break;
282             }
283         }
284         /* let's check just to make sure we did find a socket */
285         if(sock == NULL)
286         {
287             (void)nlMutexUnlock(&socklock);
288             nlSetError(NL_OUT_OF_MEMORY);
289             return NL_INVALID;
290         }
291         readlock = sock->readlock;
292         writelock = sock->writelock;
293         /* clear the structure */
294         memset(sock, 0, sizeof(nl_socket_t));
295         sock->readlock = readlock;
296         sock->writelock = writelock;
297     }
298 
299     /* sockets are blocking until set for non-blocking */
300     sock->blocking = nlBlocking;
301     sock->inuse = NL_TRUE;
302     nlNumsockets++;
303     (void)nlMutexUnlock(&socklock);
304     return newsocket;
305 }
306 
nlReturnSocket(NLsocket socket)307 static void nlReturnSocket(NLsocket socket)
308 {
309     nl_socket_t     *sock = nlSockets[socket];
310 
311     if((sock != NULL) && (sock->inuse == NL_TRUE))
312     {
313         sock->inuse = NL_FALSE;
314         if(sock->inbuf != NULL)
315         {
316             free(sock->inbuf);
317             sock->inbuf = NULL;
318         }
319         if(sock->outbuf != NULL)
320         {
321             free(sock->outbuf);
322             sock->outbuf = NULL;
323         }
324         nlNumsockets--;
325     }
326 }
327 
328 static void nlFreeSocket(NLsocket socket);
nlFreeSocket(NLsocket socket)329 static void nlFreeSocket(NLsocket socket)
330 {
331     nl_socket_t     *sock = nlSockets[socket];
332 
333     if(sock != NULL)
334     {
335         if(sock->inbuf != NULL)
336         {
337             free(sock->inbuf);
338         }
339         if(sock->outbuf != NULL)
340         {
341             free(sock->outbuf);
342         }
343         (void)nlMutexDestroy(&sock->readlock);
344         (void)nlMutexDestroy(&sock->writelock);
345         free(sock);
346     }
347 }
348 
nlIsValidSocket(NLsocket socket)349 NLboolean nlIsValidSocket(NLsocket socket)
350 {
351     nl_socket_t *sock;
352 
353     if(socket < 0 || socket > nlMaxNumsockets)
354     {
355         nlSetError(NL_INVALID_SOCKET);
356         return NL_FALSE;
357     }
358     sock = nlSockets[socket];
359     if(sock == NULL)
360     {
361         nlSetError(NL_INVALID_SOCKET);
362         return NL_FALSE;
363     }
364     if(sock->inuse == NL_FALSE)
365     {
366         nlSetError(NL_INVALID_SOCKET);
367         return NL_FALSE;
368     }
369     return NL_TRUE;
370 }
371 
nlLockSocket(NLsocket socket,NLint which)372 NLboolean nlLockSocket(NLsocket socket, NLint which)
373 {
374     nl_socket_t     *sock = nlSockets[socket];
375 
376     if((which&NL_READ) > 0)
377     {
378         if(nlMutexLock(&sock->readlock) == NL_FALSE)
379         {
380             return NL_FALSE;
381         }
382     }
383     if((which&NL_WRITE) > 0)
384     {
385         if(nlMutexLock(&sock->writelock) == NL_FALSE)
386         {
387             if((which&NL_READ) > 0)
388             {
389                 (void)nlMutexUnlock(&sock->readlock);
390             }
391             return NL_FALSE;
392         }
393     }
394     return NL_TRUE;
395 }
396 
nlUnlockSocket(NLsocket socket,NLint which)397 void nlUnlockSocket(NLsocket socket, NLint which)
398 {
399     nl_socket_t     *sock = nlSockets[socket];
400 
401     if((which&NL_WRITE) > 0)
402     {
403         (void)nlMutexUnlock(&sock->writelock);
404     }
405     if((which&NL_READ) > 0)
406     {
407         (void)nlMutexUnlock(&sock->readlock);
408     }
409 }
410 
nlUpdateStats(volatile nl_stats_t * stats,NLint nbytes,NLint npackets)411 static void nlUpdateStats(volatile nl_stats_t *stats, NLint nbytes, NLint npackets)
412 {
413     time_t  t;
414 
415     (void)time(&t);
416     if(stats->stime == 0)
417     {
418         /* must be the first time through */
419         stats->stime = t;
420         stats->lastbucket = -1;
421         stats->firstround = NL_TRUE;
422     }
423     /* do the basic update */
424     stats->packets += npackets;
425     stats->bytes += nbytes;
426 
427     /* check to see if we need to do the full update */
428     if(stats->stime != t)
429     {
430         NLint   i;
431         NLlong  count = 0;
432         time_t  diff = t - stats->stime;
433 
434         stats->stime = t;
435 
436         if(stats->curbytes > stats->highest)
437         {
438             stats->highest = stats->curbytes;
439         }
440         if(diff >= NL_NUM_BUCKETS)
441         {
442             diff = NL_NUM_BUCKETS;
443         }
444 
445         while(diff > 1)
446         {
447             /* we need to zero out skipped over buckets */
448             stats->lastbucket++;
449             if(stats->lastbucket == NL_NUM_BUCKETS)
450             {
451                 stats->lastbucket = 0;
452             }
453             stats->bucket[stats->lastbucket] = 0;
454             diff--;
455         }
456         stats->lastbucket++;
457         if(stats->lastbucket == NL_NUM_BUCKETS)
458         {
459             stats->lastbucket = 0;
460             stats->firstround = NL_FALSE;
461         }
462         stats->bucket[stats->lastbucket] = stats->curbytes;
463         if(stats->firstround == NL_TRUE)
464         {
465             /* this corrects the stats for the first second */
466             for(i=stats->lastbucket + 1;i<NL_NUM_BUCKETS;i++)
467             {
468                 stats->bucket[i] = stats->curbytes;
469             }
470         }
471         stats->curbytes = 0;
472 
473         for(i=0;i<NL_NUM_BUCKETS;i++)
474         {
475             count += stats->bucket[i];
476         }
477         stats->average =  count / NL_NUM_BUCKETS;
478     }
479     stats->curbytes += nbytes;
480 }
481 
nlUpdateInStats(NLint nbytes,NLint npackets)482 static void nlUpdateInStats(NLint nbytes, NLint npackets)
483 {
484     if(nlState.socketStats == NL_FALSE)
485     {
486         return;
487     }
488     (void)nlMutexLock(&instatlock);
489     nlUpdateStats(&nlInstats, nbytes, npackets);
490     (void)nlMutexUnlock(&instatlock);
491 }
492 
nlUpdateOutStats(NLint nbytes,NLint npackets)493 static void nlUpdateOutStats(NLint nbytes, NLint npackets)
494 {
495     if(nlState.socketStats == NL_FALSE)
496     {
497         return;
498     }
499     (void)nlMutexLock(&outstatlock);
500     nlUpdateStats(&nlOutstats, nbytes, npackets);
501     (void)nlMutexUnlock(&outstatlock);
502 }
503 
nlUpdateSocketInStats(NLsocket socket,NLint nbytes,NLint npackets)504 static void nlUpdateSocketInStats(NLsocket socket, NLint nbytes, NLint npackets)
505 {
506     nl_socket_t     *sock = nlSockets[socket];
507 
508     if(nlState.socketStats == NL_FALSE)
509     {
510         return;
511     }
512     nlUpdateStats(&sock->instats, nbytes, npackets);
513 }
514 
nlUpdateSocketOutStats(NLsocket socket,NLint nbytes,NLint npackets)515 static void nlUpdateSocketOutStats(NLsocket socket, NLint nbytes, NLint npackets)
516 {
517     nl_socket_t     *sock = nlSockets[socket];
518 
519     if(nlState.socketStats == NL_FALSE)
520     {
521         return;
522     }
523     nlUpdateStats(&sock->outstats, nbytes, npackets);
524 }
525 
526 /*
527 
528   Low level functions, a thin layer over Sockets.
529 
530 */
531 
532 /*
533    Trys to init all drivers, BUT DOES NOT SELECT A DRIVER
534 */
535 
nlInit(void)536 NL_EXP NLboolean NL_APIENTRY nlInit(void)
537 {
538     int i, numdrivers = 0;
539 
540     nlSetError(NL_NO_ERROR);
541     /* init socket memory, mutexes, and global variables */
542     if(nlInitCount == 0)
543     {
544         nlMaxNumsockets = NL_MIN_SOCKETS;
545         if(nlSockets == NULL)
546         {
547             nlSockets = (nl_socket_t **)malloc(nlMaxNumsockets * sizeof(nl_socket_t *));
548         }
549         if(nlSockets == NULL)
550         {
551             nlSetError(NL_OUT_OF_MEMORY);
552             nlShutdown();
553             return NL_FALSE;
554         }
555         if(nlGroupInit() == NL_FALSE)
556         {
557             nlShutdown();
558             return NL_FALSE;
559         }
560         if(nlMutexInit(&socklock) == NL_FALSE || nlMutexInit(&instatlock) == NL_FALSE ||
561             nlMutexInit(&outstatlock) == NL_FALSE)
562         {
563             nlShutdown();
564             return NL_FALSE;
565         }
566         nlNumsockets = 0;
567         nlNextsocket = 0;
568         nlBlocking = NL_FALSE;
569         nlState.socketStats = NL_FALSE;
570         nlState.nl_big_endian_data = NL_TRUE;
571 
572         for(i=0;(unsigned int)i<MIN(MAX_NET_DRIVERS, sizeof(netdrivers)/sizeof(nl_netdriver_t));i++)
573         {
574             if(netdrivers[i].name == NULL)
575             {
576                 break;
577             }
578             if(netdrivers[i].initialized == NL_TRUE)
579             {
580                 numdrivers++;
581             }
582             else if(netdrivers[i].Init() == NL_TRUE)
583             {
584                 netdrivers[i].initialized = NL_TRUE;
585                 numdrivers++;
586             }
587         }
588         if(numdrivers == 0)
589         {
590             nlSetError(NL_NO_NETWORK);
591             nlShutdown();
592             return NL_FALSE;
593         }
594     }
595     nlInitCount++;
596     return NL_TRUE;
597 }
598 
599 /*
600    Called at the end of your program, shuts down the active driver and frees memory
601 */
602 
nlShutdown(void)603 NL_EXP void NL_APIENTRY nlShutdown(void)
604 {
605     --nlInitCount;
606 
607     if(nlInitCount > 0)
608     {
609         return;
610     }
611     if(driver != NULL)
612     {
613         /* close any open sockets */
614         (void)nlMutexLock(&socklock);
615         if(nlSockets != NULL)
616         {
617             NLsocket i;
618 
619             for(i=0;i<nlNextsocket;i++)
620             {
621                 if(nlSockets[i] != NULL)
622                 {
623                     if(nlIsValidSocket(i) == NL_TRUE)
624                     {
625                         driver->Close(i);
626                         nlThreadYield();
627                     }
628                 }
629             }
630         }
631         /* now we can shutdown the driver */
632         driver->Shutdown();
633         driver->initialized = NL_FALSE;
634         driver = NULL;
635     }
636     else
637     {
638         nlSetError(NL_NO_NETWORK);
639     }
640 
641     nlThreadSleep(1);
642 
643     /* now free all the socket structures */
644     if(nlSockets != NULL)
645     {
646         NLsocket i;
647 
648         for(i=0;i<nlNextsocket;i++)
649         {
650             if(nlSockets[i] != NULL)
651             {
652                 if(nlIsValidSocket(i) == NL_TRUE)
653                 {
654                     (void)nlLockSocket(i, NL_BOTH);
655                     nlReturnSocket(i);
656                     nlUnlockSocket(i, NL_BOTH);
657                     nlThreadYield();
658                 }
659                 nlFreeSocket(i);
660             }
661         }
662         free(nlSockets);
663         nlSockets = NULL;
664     }
665     (void)nlMutexUnlock(&socklock);
666     nlGroupShutdown();
667     /* destroy the mutexes */
668     (void)nlMutexDestroy(&socklock);
669     (void)nlMutexDestroy(&instatlock);
670     (void)nlMutexDestroy(&outstatlock);
671 }
672 
673 /*
674    Enables a socket to listen for incomming connections
675 */
676 
nlListen(NLsocket socket)677 NL_EXP NLboolean NL_APIENTRY nlListen(NLsocket socket)
678 {
679     if(driver != NULL)
680     {
681         if(nlIsValidSocket(socket) == NL_TRUE)
682         {
683             NLboolean result;
684 
685             if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
686             {
687                 return NL_FALSE;
688             }
689             result = driver->Listen(socket);
690             nlUnlockSocket(socket, NL_BOTH);
691             return result;
692         }
693         nlSetError(NL_INVALID_SOCKET);
694         return NL_FALSE;
695     }
696     nlSetError(NL_NO_NETWORK);
697     return NL_FALSE;
698 }
699 
700 /*
701    Accepts a pending connection.
702    Creates a new socket object for this connection.
703 */
704 
nlAcceptConnection(NLsocket socket)705 NL_EXP NLsocket NL_APIENTRY nlAcceptConnection(NLsocket socket)
706 {
707     if(driver)
708     {
709         if(nlIsValidSocket(socket) == NL_TRUE)
710         {
711             NLsocket newsocket;
712 
713             if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
714             {
715                 return NL_INVALID;
716             }
717             newsocket = driver->AcceptConnection(socket);
718             nlUnlockSocket(socket, NL_BOTH);
719             if(newsocket != NL_INVALID)
720             {
721                 /* the new socket was locked when it is created */
722                 nlUnlockSocket(newsocket, NL_BOTH);
723             }
724             return newsocket;
725         }
726         nlSetError(NL_INVALID_SOCKET);
727         return NL_INVALID;
728     }
729     nlSetError(NL_NO_NETWORK);
730     return NL_INVALID;
731 }
732 
733 /*
734    Creates a new socket object.
735    Can be used for reading or broadcast as is.
736    For non-broadcast use, call nlConnectSocket to connect to a remote address.
737 */
738 
nlOpen(NLushort port,NLenum type)739 NL_EXP NLsocket NL_APIENTRY nlOpen(NLushort port, NLenum type)
740 {
741     if(driver)
742     {
743         return (driver->Open(port, type));
744     }
745 
746     nlSetError(NL_NO_NETWORK);
747     return NL_INVALID;
748 }
749 
750 /*
751    Connect a socket to a remote address.
752 */
753 
nlConnect(NLsocket socket,const NLaddress * address)754 NL_EXP NLboolean NL_APIENTRY nlConnect(NLsocket socket, const NLaddress *address)
755 {
756     if(driver)
757     {
758         if(nlIsValidSocket(socket) == NL_TRUE)
759         {
760             if(address == NULL)
761             {
762                 nlSetError(NL_NULL_POINTER);
763             }
764             else
765             {
766                 NLboolean result;
767 
768                 if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
769                 {
770                     return NL_FALSE;
771                 }
772                 result = driver->Connect(socket, address);
773                 nlUnlockSocket(socket, NL_BOTH);
774                 return result;
775             }
776         }
777         else
778         {
779             nlSetError(NL_INVALID_SOCKET);
780         }
781         return NL_FALSE;
782     }
783     nlSetError(NL_NO_NETWORK);
784     return NL_FALSE;
785 }
786 
787 /*
788    Close the socket.
789 */
790 
nlClose(NLsocket socket)791 NL_EXP NLboolean NL_APIENTRY nlClose(NLsocket socket)
792 {
793     if(driver)
794     {
795         if(nlIsValidSocket(socket) == NL_TRUE)
796         {
797             if(nlMutexLock(&socklock) == NL_FALSE)
798             {
799                 return NL_FALSE;
800             }
801             if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
802             {
803                 return NL_FALSE;
804             }
805             driver->Close(socket);
806             /* return the socket for reuse */
807             nlReturnSocket(socket);
808             nlUnlockSocket(socket, NL_BOTH);
809             if(nlMutexUnlock(&socklock) == NL_FALSE)
810             {
811                 return NL_FALSE;
812             }
813             return NL_TRUE;
814         }
815         else
816         {
817             nlSetError(NL_INVALID_SOCKET);
818             return NL_TRUE;
819         }
820     }
821     nlSetError(NL_NO_NETWORK);
822     return NL_FALSE;
823 }
824 
825 /*
826    Reads from a socket.
827 */
828 
nlRead(NLsocket socket,NLvoid * buffer,NLint nbytes)829 NL_EXP NLint NL_APIENTRY nlRead(NLsocket socket, NLvoid *buffer, NLint nbytes)
830 {
831     if(driver)
832     {
833         if(nlIsValidSocket(socket) == NL_TRUE)
834         {
835             if(buffer == NULL)
836             {
837                 nlSetError(NL_NULL_POINTER);
838             }
839             else
840             {
841                 NLint received;
842 
843                 if(nlLockSocket(socket, NL_READ) == NL_FALSE)
844                 {
845                     return NL_INVALID;
846                 }
847                 received = driver->Read(socket, buffer, nbytes);
848 
849                 if(received > 0)
850                 {
851                     nlUpdateSocketInStats(socket, received, 1);
852                     nlUpdateInStats(received, 1);
853                 }
854                 nlUnlockSocket(socket, NL_READ);
855                 return received;
856             }
857         }
858         else
859         {
860             nlSetError(NL_INVALID_SOCKET);
861         }
862         return NL_INVALID;
863     }
864     nlSetError(NL_NO_NETWORK);
865     return NL_INVALID;
866 }
867 
868 /*
869    Writes to a socket.
870 */
871 
nlWrite(NLsocket socket,const NLvoid * buffer,NLint nbytes)872 NL_EXP NLint NL_APIENTRY nlWrite(NLsocket socket, const NLvoid *buffer, NLint nbytes)
873 {
874     if(driver)
875     {
876         /* check for group */
877         if(socket >= NL_FIRST_GROUP)
878         {
879             NLint       number = NL_MAX_GROUP_SOCKETS;
880             NLsocket    s[NL_MAX_GROUP_SOCKETS];
881             NLint       i;
882             NLint       sent = nbytes;
883 
884             if(nlGroupGetSockets((NLint)socket, (NLsocket *)s, &number) == NL_FALSE)
885             {
886                 return NL_INVALID;
887             }
888 
889             for(i=0;i<number;i++)
890             {
891                 NLint result;
892 
893                 if(nlIsValidSocket(s[i]) == NL_TRUE)
894                 {
895                     result = nlWrite(s[i], buffer, nbytes);
896                     if(result < sent)
897                     {
898                         sent = result;
899                     }
900                 }
901             }
902             return sent;
903         }
904         else
905         {
906             if(nlIsValidSocket(socket) == NL_TRUE)
907             {
908                 if(buffer == NULL)
909                 {
910                     nlSetError(NL_NULL_POINTER);
911                 }
912                 else
913                 {
914                     NLint sent;
915 
916                     if(nlLockSocket(socket, NL_WRITE) == NL_FALSE)
917                     {
918                         return NL_INVALID;
919                     }
920                     sent = driver->Write(socket, buffer, nbytes);
921                     if(sent > 0)
922                     {
923                         nlUpdateSocketOutStats(socket, sent, 1);
924                         nlUpdateOutStats(sent, 1);
925                     }
926                     nlUnlockSocket(socket, NL_WRITE);
927                     return sent;
928                 }
929             }
930             else
931             {
932                 nlSetError(NL_INVALID_SOCKET);
933             }
934             return NL_INVALID;
935         }
936     }
937     nlSetError(NL_NO_NETWORK);
938     return NL_INVALID;
939 }
940 
941 /*
942    Polls all sockets in the group to see which have data waiting to be read.
943    nlPollGroup uses select() on TCP or UDP sockets.
944    Returns number of sockets waiting, and a list of those sockets, or NL_INVALID
945    on an error.
946 */
947 
nlPollGroup(NLint group,NLenum name,NLsocket * sockets,NLint number,NLint timeout)948 NL_EXP NLint NL_APIENTRY nlPollGroup(NLint group, NLenum name, /*@out@*/ NLsocket *sockets, NLint number, NLint timeout)
949 {
950     if(driver)
951     {
952         if(sockets == NULL )
953         {
954             nlSetError(NL_NULL_POINTER);
955             return 0;
956         }
957         return (driver->PollGroup(group, name, sockets, number, timeout));
958     }
959     nlSetError(NL_NO_NETWORK);
960     return 0;
961 }
962 
nlHint(NLenum name,NLint arg)963 NL_EXP NLboolean NL_APIENTRY nlHint(NLenum name, NLint arg)
964 {
965     if(driver)
966     {
967         return driver->Hint(name, arg);
968     }
969     nlSetError(NL_NO_NETWORK);
970     return NL_FALSE;
971 }
972 
973 
974 /*
975    Converts the numeric address in the NLaddress structure to a string.
976 */
977 
nlAddrToString(const NLaddress * address,NLchar * string)978 NL_EXP /*@null@*/ NLchar* NL_APIENTRY nlAddrToString(const NLaddress *address, NLchar *string)
979 {
980     if(driver)
981     {
982         if((string == NULL) || (address == NULL))
983         {
984             nlSetError(NL_NULL_POINTER);
985             return NULL;
986         }
987         return (driver->AddrToString(address, string));
988     }
989     nlSetError(NL_NO_NETWORK);
990     return NULL;
991 }
992 
993 /*
994    Takes a string that contains a full network address (ie, for IP 192.168.0.1:27000),
995    and adds it to the NLaddress structure.
996 */
997 
nlStringToAddr(const NLchar * string,NLaddress * address)998 NL_EXP NLboolean NL_APIENTRY nlStringToAddr(const NLchar *string, NLaddress *address)
999 {
1000     if(driver)
1001     {
1002         if((string == NULL) || (address == NULL))
1003         {
1004             nlSetError(NL_NULL_POINTER);
1005             return NL_FALSE;
1006         }
1007         if(isSafeString(string) == NL_FALSE)
1008         {
1009             nlSetError(NL_STRING_OVER_RUN);
1010             return NL_FALSE;
1011         }
1012         return driver->StringToAddr(string, address);
1013     }
1014     nlSetError(NL_NO_NETWORK);
1015     return NL_FALSE;
1016 }
1017 
1018 /*
1019    Gets the remote address of the socket if connected to a remote host,
1020    or the local address if not connected.
1021 */
1022 
1023 /* Note: the drivers put a copy of address in nl_socket_t, so we just need to copy it */
nlGetRemoteAddr(NLsocket socket,NLaddress * address)1024 NL_EXP NLboolean NL_APIENTRY nlGetRemoteAddr(NLsocket socket, NLaddress *address)
1025 {
1026     if(driver)
1027     {
1028         if(address == NULL)
1029         {
1030             nlSetError(NL_NULL_POINTER);
1031             return NL_FALSE;
1032         }
1033         if(nlIsValidSocket(socket) == NL_TRUE)
1034         {
1035             nl_socket_t *sock = nlSockets[socket];
1036 
1037             if(nlLockSocket(socket, NL_READ) == NL_FALSE)
1038             {
1039                 return NL_FALSE;
1040             }
1041             memcpy(address, &sock->addressin, sizeof(NLaddress));
1042 			address->valid = NL_TRUE;
1043             nlUnlockSocket(socket, NL_READ);
1044         }
1045         else
1046         {
1047             nlSetError(NL_INVALID_SOCKET);
1048             memset(address, 0, sizeof(NLaddress));
1049             return NL_FALSE;
1050         }
1051         return NL_TRUE;
1052     }
1053     nlSetError(NL_NO_NETWORK);
1054     return NL_FALSE;
1055 }
1056 
1057 /*
1058    Sets the remote address of an unconnected UDP socket.
1059 */
1060 
nlSetRemoteAddr(NLsocket socket,const NLaddress * address)1061 NL_EXP NLboolean NL_APIENTRY nlSetRemoteAddr(NLsocket socket, const NLaddress *address)
1062 {
1063     if(driver)
1064     {
1065         if(nlIsValidSocket(socket) == NL_TRUE)
1066         {
1067             if(address == NULL)
1068             {
1069                 nlSetError(NL_NULL_POINTER);
1070                 return NL_FALSE;
1071             }
1072             else
1073             {
1074                 nl_socket_t *sock = nlSockets[socket];
1075 
1076                 if(nlLockSocket(socket, NL_WRITE) == NL_FALSE)
1077                 {
1078                     return NL_FALSE;
1079                 }
1080                 memcpy(&sock->addressout, address, sizeof(NLaddress));
1081                 nlUnlockSocket(socket, NL_WRITE);
1082             }
1083         }
1084         else
1085         {
1086             nlSetError(NL_INVALID_SOCKET);
1087             return NL_FALSE;
1088         }
1089         return NL_TRUE;
1090     }
1091     nlSetError(NL_NO_NETWORK);
1092     return NL_FALSE;
1093 }
1094 
1095 /*
1096    Gets the local address.
1097 */
1098 
nlGetLocalAddr(NLsocket socket,NLaddress * address)1099 NL_EXP NLboolean NL_APIENTRY nlGetLocalAddr(NLsocket socket, NLaddress *address)
1100 {
1101     if(driver)
1102     {
1103         if(nlIsValidSocket(socket) == NL_TRUE)
1104         {
1105             if(address == NULL)
1106             {
1107                 nlSetError(NL_NULL_POINTER);
1108                 return NL_FALSE;
1109             }
1110             if(nlLockSocket(socket, NL_READ) == NL_FALSE)
1111             {
1112                 return NL_FALSE;
1113             }
1114             if(driver->GetLocalAddr(socket, address) == NL_FALSE)
1115             {
1116                 nlUnlockSocket(socket, NL_READ);
1117                 return NL_FALSE;
1118             }
1119             nlUnlockSocket(socket, NL_READ);
1120         }
1121         else
1122         {
1123             nlSetError(NL_INVALID_SOCKET);
1124             return NL_FALSE;
1125         }
1126         return NL_TRUE;
1127     }
1128     nlSetError(NL_NO_NETWORK);
1129     return NL_FALSE;
1130 }
1131 
nlSetLocalAddr(const NLaddress * address)1132 NL_EXP NLboolean NL_APIENTRY nlSetLocalAddr(const NLaddress *address)
1133 {
1134     if(driver)
1135     {
1136         if(address == NULL)
1137         {
1138             nlSetError(NL_NULL_POINTER);
1139             return NL_FALSE;
1140         }
1141         return driver->SetLocalAddr(address);
1142     }
1143     nlSetError(NL_NO_NETWORK);
1144     return NL_FALSE;
1145 }
1146 
1147 /*
1148    Compare two addresses.
1149 */
1150 
nlAddrCompare(const NLaddress * address1,const NLaddress * address2)1151 NL_EXP NLboolean NL_APIENTRY nlAddrCompare(const NLaddress *address1, const NLaddress *address2)
1152 {
1153     if(driver)
1154     {
1155         if((address1 == NULL) || (address2 == NULL))
1156         {
1157             nlSetError(NL_NULL_POINTER);
1158             return NL_FALSE;
1159         }
1160         return driver->AddrCompare(address1, address2);
1161     }
1162     nlSetError(NL_NO_NETWORK);
1163     return NL_FALSE;
1164 }
1165 
1166 /*
1167    Get the port number from an address.
1168 */
1169 
nlGetPortFromAddr(const NLaddress * address)1170 NL_EXP NLushort NL_APIENTRY nlGetPortFromAddr(const NLaddress *address)
1171 {
1172     if(driver)
1173     {
1174         if(address == NULL)
1175         {
1176             nlSetError(NL_NULL_POINTER);
1177             return 0;
1178         }
1179         return driver->GetPortFromAddr(address);
1180     }
1181     nlSetError(NL_NO_NETWORK);
1182     return 0;
1183 }
1184 
1185 /*
1186    Set the port number in the address.
1187 */
1188 
nlSetAddrPort(NLaddress * address,NLushort port)1189 NL_EXP NLboolean NL_APIENTRY nlSetAddrPort(NLaddress *address, NLushort port)
1190 {
1191     if(driver)
1192     {
1193         if(address == NULL)
1194         {
1195             nlSetError(NL_NULL_POINTER);
1196             return NL_FALSE;
1197         }
1198         driver->SetAddrPort(address, port);
1199         return NL_TRUE;
1200     }
1201     nlSetError(NL_NO_NETWORK);
1202     return NL_FALSE;
1203 }
1204 
1205 
1206 /*
1207 
1208   Non-socket functions
1209 
1210 */
1211 
1212 /*
1213    Select the network to use.
1214 */
1215 
nlSelectNetwork(NLenum network)1216 NL_EXP NLboolean NL_APIENTRY nlSelectNetwork(NLenum network)
1217 {
1218     int i, found = 0;
1219 
1220     if(driver != NULL)
1221     {
1222         /* we cannot select a new network without shutting down first */
1223         nlSetError(NL_SELECT_NET_ERROR);
1224         return NL_FALSE;
1225     }
1226 
1227     for(i=0;(unsigned int)i<MIN(MAX_NET_DRIVERS, sizeof(netdrivers)/sizeof(nl_netdriver_t));i++)
1228     {
1229         if(netdrivers[i].name == NULL)
1230         {
1231             break;
1232         }
1233         if(netdrivers[i].type == network)
1234         {
1235             found++;
1236             if(netdrivers[i].initialized == NL_TRUE)
1237             {
1238                 driver = &netdrivers[i];
1239                 return NL_TRUE;
1240             }
1241         }
1242     }
1243     if(found > 0)
1244     {
1245         nlSetError(NL_INVALID_TYPE);
1246     }
1247     else
1248     {
1249         nlSetError(NL_INVALID_ENUM);
1250     }
1251     return NL_FALSE;
1252 }
1253 
1254 /*
1255    Returns a string corresponding to the NLenum.
1256 */
1257 
nlGetString(NLenum name)1258 NL_EXP const /*@observer@*//*@null@*/ NLchar* NL_APIENTRY nlGetString(NLenum name)
1259 {
1260 	/* use seperate strings for thread safety */
1261     static NLchar   vstring[NL_MAX_STRING_LENGTH];
1262     static NLchar   tstring[NL_MAX_STRING_LENGTH];
1263     NLint i;
1264 
1265     /* intitialize the version string */
1266     _tcsncpy(vstring, (NLchar *)TEXT(NL_VERSION_STRING), (size_t)NL_MAX_STRING_LENGTH);
1267     vstring[NL_MAX_STRING_LENGTH - 1] = (NLchar) '\0';
1268 #ifdef _UNICODE
1269     /* add the UNICODE string */
1270     safecat(vstring, (NLchar *)TEXT(" UNICODE version"));
1271 #endif
1272     /* intitialize the network types string */
1273     memset(tstring, 0, sizeof(NLchar) * NL_MAX_STRING_LENGTH);
1274     for(i=0;i<MAX_NET_DRIVERS;i++)
1275     {
1276         if(netdrivers[i].name == NULL)
1277         {
1278             break;
1279         }
1280         if(netdrivers[i].initialized == NL_TRUE)
1281         {
1282             safecat((NLchar *)tstring, (const NLchar *)netdrivers[i].name);
1283             safecat((NLchar *)tstring, (NLchar *)TEXT(" "));
1284         }
1285     }
1286 
1287     switch (name) {
1288 
1289     case NL_VERSION:
1290 		return (const NLchar*)vstring;
1291 
1292     case NL_NETWORK_TYPES:
1293 		return (const NLchar*)tstring;
1294 
1295     case NL_CONNECTION_TYPES:
1296         if(driver != NULL)
1297         {
1298 		    return (const NLchar*)(driver->connections);
1299         }
1300         break;
1301 
1302     default:
1303         nlSetError(NL_INVALID_ENUM);
1304     }
1305 
1306     return NULL;
1307 }
1308 
1309 /*
1310    Returns an integer corresponding to the NLenum.
1311 */
1312 
nlGetInteger(NLenum name)1313 NL_EXP NLlong NL_APIENTRY nlGetInteger(NLenum name)
1314 {
1315     switch (name) {
1316 
1317     case NL_PACKETS_SENT:
1318         return nlOutstats.packets;
1319 
1320     case NL_BYTES_SENT:
1321         return nlOutstats.bytes;
1322 
1323     case NL_AVE_BYTES_SENT:
1324         nlUpdateOutStats(0, 0);
1325         return nlOutstats.average;
1326 
1327     case NL_HIGH_BYTES_SENT:
1328         return nlOutstats.highest;
1329 
1330     case NL_PACKETS_RECEIVED:
1331         return nlInstats.packets;
1332 
1333     case NL_BYTES_RECEIVED:
1334         return nlInstats.bytes;
1335 
1336     case NL_AVE_BYTES_RECEIVED:
1337         nlUpdateInStats(0, 0);
1338         return nlInstats.average;
1339 
1340     case NL_HIGH_BYTES_RECEIVED:
1341         return nlInstats.highest;
1342 
1343     case NL_OPEN_SOCKETS:
1344         return nlNumsockets;
1345 
1346     default:
1347         nlSetError(NL_INVALID_ENUM);
1348     }
1349     return 0;
1350 }
1351 
1352 /*
1353    Clears the stat corresponding to the NLenum.
1354 */
1355 
nlClear(NLenum name)1356 NL_EXP NLboolean NL_APIENTRY nlClear(NLenum name)
1357 {
1358     switch (name) {
1359 
1360     case NL_PACKETS_SENT:
1361         if(nlMutexLock(&outstatlock) == NL_FALSE)
1362         {
1363             return NL_FALSE;
1364         }
1365         nlOutstats.packets = 0;
1366         if(nlMutexUnlock(&outstatlock) == NL_FALSE)
1367         {
1368             return NL_FALSE;
1369         }
1370         break;
1371 
1372     case NL_BYTES_SENT:
1373         if(nlMutexLock(&outstatlock) == NL_FALSE)
1374         {
1375             return NL_FALSE;
1376         }
1377         nlOutstats.bytes = 0;
1378         if(nlMutexUnlock(&outstatlock) == NL_FALSE)
1379         {
1380             return NL_FALSE;
1381         }
1382         break;
1383 
1384     case NL_AVE_BYTES_SENT:
1385         if(nlMutexLock(&outstatlock) == NL_FALSE)
1386         {
1387             return NL_FALSE;
1388         }
1389         nlOutstats.average = 0;
1390         memset((NLbyte *)nlOutstats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
1391         if(nlMutexUnlock(&outstatlock) == NL_FALSE)
1392         {
1393             return NL_FALSE;
1394         }
1395         break;
1396 
1397     case NL_HIGH_BYTES_SENT:
1398         if(nlMutexLock(&outstatlock) == NL_FALSE)
1399         {
1400             return NL_FALSE;
1401         }
1402         nlOutstats.highest = 0;
1403         if(nlMutexUnlock(&outstatlock) == NL_FALSE)
1404         {
1405             return NL_FALSE;
1406         }
1407         break;
1408 
1409     case NL_PACKETS_RECEIVED:
1410         if(nlMutexLock(&instatlock) == NL_FALSE)
1411         {
1412             return NL_FALSE;
1413         }
1414         nlInstats.packets = 0;
1415         if(nlMutexUnlock(&instatlock) == NL_FALSE)
1416         {
1417             return NL_FALSE;
1418         }
1419         break;
1420 
1421     case NL_BYTES_RECEIVED:
1422         if(nlMutexLock(&instatlock) == NL_FALSE)
1423         {
1424             return NL_FALSE;
1425         }
1426         nlInstats.bytes = 0;
1427         if(nlMutexUnlock(&instatlock) == NL_FALSE)
1428         {
1429             return NL_FALSE;
1430         }
1431         break;
1432 
1433     case NL_AVE_BYTES_RECEIVED:
1434         if(nlMutexLock(&instatlock) == NL_FALSE)
1435         {
1436             return NL_FALSE;
1437         }
1438         nlInstats.average = 0;
1439         memset((NLbyte *)nlInstats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
1440         if(nlMutexUnlock(&instatlock) == NL_FALSE)
1441         {
1442             return NL_FALSE;
1443         }
1444         break;
1445 
1446     case NL_HIGH_BYTES_RECEIVED:
1447         if(nlMutexLock(&instatlock) == NL_FALSE)
1448         {
1449             return NL_FALSE;
1450         }
1451         nlInstats.highest = 0;
1452         if(nlMutexUnlock(&instatlock) == NL_FALSE)
1453         {
1454             return NL_FALSE;
1455         }
1456         break;
1457 
1458     case NL_ALL_STATS:
1459         (void)nlClear(NL_PACKETS_SENT);
1460         (void)nlClear(NL_BYTES_SENT);
1461         (void)nlClear(NL_AVE_BYTES_SENT);
1462         (void)nlClear(NL_HIGH_BYTES_SENT);
1463         (void)nlClear(NL_PACKETS_RECEIVED);
1464         (void)nlClear(NL_BYTES_RECEIVED);
1465         (void)nlClear(NL_AVE_BYTES_RECEIVED);
1466         (void)nlClear(NL_HIGH_BYTES_RECEIVED);
1467         break;
1468 
1469     default:
1470         nlSetError(NL_INVALID_ENUM);
1471         return NL_FALSE;
1472     }
1473     return NL_TRUE;
1474 }
1475 
1476 /*
1477    Get the socket or system error.
1478 */
1479 
nlGetSystemError(void)1480 NL_EXP NLint NL_APIENTRY nlGetSystemError(void)
1481 {
1482     if(driver)
1483     {
1484         return driver->GetSystemError();
1485     }
1486     return NL_NO_NETWORK;
1487 }
1488 
nlEnable(NLenum name)1489 NL_EXP NLboolean NL_APIENTRY nlEnable(NLenum name)
1490 {
1491     switch (name) {
1492 
1493     case NL_BLOCKING_IO:
1494         nlBlocking = NL_TRUE;
1495         break;
1496 
1497     case NL_TCP_NO_DELAY:
1498         return nlHint(NL_TCP_NO_DELAY, (NLint)NL_TRUE);
1499 
1500     case NL_SOCKET_STATS:
1501         nlState.socketStats = NL_TRUE;
1502         break;
1503 
1504     case NL_BIG_ENDIAN_DATA:
1505         nlState.nl_big_endian_data = NL_TRUE;
1506         break;
1507 
1508     case NL_LITTLE_ENDIAN_DATA:
1509         nlState.nl_big_endian_data = NL_FALSE;
1510         break;
1511 
1512     default:
1513         nlSetError(NL_INVALID_ENUM);
1514         return NL_FALSE;
1515     }
1516     return NL_TRUE;
1517 }
1518 
nlDisable(NLenum name)1519 NL_EXP NLboolean NL_APIENTRY nlDisable(NLenum name)
1520 {
1521     switch (name) {
1522 
1523     case NL_BLOCKING_IO:
1524         nlBlocking = NL_FALSE;
1525         break;
1526 
1527     case NL_TCP_NO_DELAY:
1528         return nlHint(NL_TCP_NO_DELAY, NL_FALSE);
1529 
1530     case NL_SOCKET_STATS:
1531         nlState.socketStats = NL_FALSE;
1532         break;
1533 
1534     case NL_BIG_ENDIAN_DATA:
1535         nlState.nl_big_endian_data = NL_FALSE;
1536         break;
1537 
1538     case NL_LITTLE_ENDIAN_DATA:
1539         nlState.nl_big_endian_data = NL_TRUE;
1540         break;
1541 
1542     default:
1543         nlSetError(NL_INVALID_ENUM);
1544         return NL_FALSE;
1545     }
1546     return NL_TRUE;
1547 }
1548 
nlGetBoolean(NLenum name)1549 NL_EXP NLboolean NL_APIENTRY nlGetBoolean(NLenum name)
1550 {
1551     switch (name) {
1552 
1553     case NL_BLOCKING_IO:
1554         return nlBlocking;
1555 
1556     case NL_SOCKET_STATS:
1557         return nlState.socketStats;
1558 
1559     case NL_BIG_ENDIAN_DATA:
1560         return nlState.nl_big_endian_data;
1561 
1562     case NL_LITTLE_ENDIAN_DATA:
1563         return (NLboolean)(nlState.nl_big_endian_data == NL_TRUE ? NL_FALSE:NL_TRUE);
1564 
1565     default:
1566         nlSetError(NL_INVALID_ENUM);
1567         return NL_FALSE;
1568     }
1569 }
1570 
nlGetSocketStat(NLsocket socket,NLenum name)1571 NL_EXP NLlong NL_APIENTRY nlGetSocketStat(NLsocket socket, NLenum name)
1572 {
1573     nl_socket_t     *sock;
1574     NLlong          result = 0;
1575 
1576     if(nlIsValidSocket(socket) == NL_FALSE)
1577     {
1578         nlSetError(NL_INVALID_SOCKET);
1579         return 0;
1580     }
1581     if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
1582     {
1583         return 0;
1584     }
1585     sock = nlSockets[socket];
1586 
1587     switch (name) {
1588 
1589     case NL_PACKETS_SENT:
1590         result = sock->outstats.packets;
1591         break;
1592 
1593     case NL_BYTES_SENT:
1594         result = sock->outstats.bytes;
1595         break;
1596 
1597     case NL_AVE_BYTES_SENT:
1598         nlUpdateSocketOutStats(socket, 0, 0);
1599         result = sock->outstats.average;
1600         if(result == 0)
1601         {
1602             /* this corrects the stats for the first second */
1603             result = sock->outstats.curbytes;
1604         }
1605         break;
1606 
1607     case NL_HIGH_BYTES_SENT:
1608         result = sock->outstats.highest;
1609         break;
1610 
1611     case NL_PACKETS_RECEIVED:
1612         result = sock->instats.packets;
1613         break;
1614 
1615     case NL_BYTES_RECEIVED:
1616         result = sock->instats.bytes;
1617         break;
1618 
1619     case NL_AVE_BYTES_RECEIVED:
1620         nlUpdateSocketInStats(socket, 0, 0);
1621         result = sock->instats.average;
1622         if(result == 0)
1623         {
1624             /* this corrects the stats for the first second */
1625             result = sock->instats.curbytes;
1626         }
1627         break;
1628 
1629     case NL_HIGH_BYTES_RECEIVED:
1630         result = sock->instats.highest;
1631         break;
1632 
1633     default:
1634         nlSetError(NL_INVALID_ENUM);
1635     }
1636     nlUnlockSocket(socket, NL_BOTH);
1637     return result;
1638 }
1639 
nlClearSocketStat(NLsocket socket,NLenum name)1640 NL_EXP NLboolean NL_APIENTRY nlClearSocketStat(NLsocket socket, NLenum name)
1641 {
1642     nl_socket_t     *sock;
1643 
1644     if(nlIsValidSocket(socket) == NL_FALSE)
1645     {
1646         nlSetError(NL_INVALID_SOCKET);
1647         return NL_FALSE;
1648     }
1649     if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
1650     {
1651         return NL_FALSE;
1652     }
1653     sock = nlSockets[socket];
1654 
1655     switch (name) {
1656 
1657     case NL_PACKETS_SENT:
1658         sock->outstats.packets = 0;
1659         break;
1660 
1661     case NL_BYTES_SENT:
1662         sock->outstats.bytes = 0;
1663         break;
1664 
1665     case NL_AVE_BYTES_SENT:
1666         sock->outstats.average = 0;
1667         memset((NLbyte *)sock->outstats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
1668         break;
1669 
1670     case NL_HIGH_BYTES_SENT:
1671         sock->outstats.highest = 0;
1672         break;
1673 
1674     case NL_PACKETS_RECEIVED:
1675         sock->instats.packets = 0;
1676         break;
1677 
1678     case NL_BYTES_RECEIVED:
1679         sock->instats.bytes = 0;
1680         break;
1681 
1682     case NL_AVE_BYTES_RECEIVED:
1683         sock->instats.average = 0;
1684         memset((NLbyte *)sock->instats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
1685         break;
1686 
1687     case NL_HIGH_BYTES_RECEIVED:
1688         sock->instats.highest = 0;
1689         break;
1690 
1691     case NL_ALL_STATS:
1692         sock->outstats.packets = 0;
1693         sock->outstats.bytes = 0;
1694         sock->outstats.average = 0;
1695         memset((NLbyte *)sock->outstats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
1696         sock->outstats.highest = 0;
1697         sock->instats.packets = 0;
1698         sock->instats.bytes = 0;
1699         sock->instats.average = 0;
1700         memset((NLbyte *)sock->instats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
1701         sock->instats.highest = 0;
1702         break;
1703 
1704     default:
1705         nlSetError(NL_INVALID_ENUM);
1706         nlUnlockSocket(socket, NL_BOTH);
1707         return NL_FALSE;
1708     }
1709     nlUnlockSocket(socket, NL_BOTH);
1710     return NL_TRUE;
1711 }
1712 
nlSwaps(NLushort x)1713 NL_EXP NLushort  NL_APIENTRY nlSwaps(NLushort x)
1714 {
1715     if(NL_SWAP_TRUE)
1716     {
1717         return (NLushort)(((((NLushort)x) & 0x00ff) << 8) | ((((NLushort)x) & 0xff00) >> 8));
1718     }
1719     else
1720     {
1721         return x;
1722     }
1723 }
1724 
nlSwapl(NLulong x)1725 NL_EXP NLulong   NL_APIENTRY nlSwapl(NLulong x)
1726 {
1727     if(NL_SWAP_TRUE)
1728     {
1729         return (NLulong)(((((NLulong)x) & 0x000000ff) << 24) | ((((NLulong)x) & 0x0000ff00) << 8) | ((((NLulong)x) & 0x00ff0000) >> 8) | ((((NLulong)x) & 0xff000000) >> 24));
1730     }
1731     else
1732     {
1733         return x;
1734     }
1735 }
1736 
nlSwapf(NLfloat f)1737 NL_EXP NLfloat   NL_APIENTRY nlSwapf(NLfloat f)
1738 {
1739     if(NL_SWAP_TRUE)
1740     {
1741 	union {
1742 		NLulong l;
1743 		NLfloat f;
1744 	} tmp;
1745 	tmp.f = f;
1746         tmp.l = nlSwapl(tmp.l);
1747 
1748         return tmp.f;
1749     }
1750     else
1751     {
1752         return f;
1753     }
1754 }
1755 
nlSwapd(NLdouble d)1756 NL_EXP NLdouble  NL_APIENTRY nlSwapd(NLdouble d)
1757 {
1758     if(NL_SWAP_TRUE)
1759     {
1760         union {NLulong l[2]; NLdouble d;} in, out;
1761 
1762         in.d = d;
1763         out.l[0] = nlSwapl(in.l[1]);
1764         out.l[1] = nlSwapl(in.l[0]);
1765         return out.d;
1766     }
1767     else
1768     {
1769         return d;
1770     }
1771 }
1772 
1773 #if defined (__LCC__)
LibMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)1774 BOOL WINAPI __declspec(dllexport) LibMain(/*@unused@*/HINSTANCE hinstDLL, /*@unused@*/DWORD fdwReason, /*@unused@*/LPVOID lpvReserved)
1775 {
1776     return TRUE;
1777 }
1778 #endif /* WINDOWS APP */
1779