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