Nilorea Library
C utilities for networking, threading, graphics
n_network.c
Go to the documentation of this file.
1
8#include <errno.h>
9#include <limits.h>
10#include <pthread.h>
11#include <unistd.h>
12#include <string.h>
13#include <sys/types.h>
14
15#include "nilorea/n_network.h"
17#include "nilorea/n_log.h"
18#include "nilorea/n_hash.h"
19
22
23#ifdef __windows__
24
25 /*
26 * From https://stackoverflow.com/questions/3019977/convert-wchar-t-to-char/55715607#55715607 by Richard Bamford
27 */
28char* wchar_to_char(const wchar_t* pwchar)
29{
30 // get the number of characters in the string.
31 int currentCharIndex = 0;
32 char currentChar = pwchar[currentCharIndex];
33 char *filePathC = NULL ;
34
35 while (currentChar != '\0')
36 {
37 currentCharIndex++;
38 currentChar = pwchar[currentCharIndex];
39 }
40
41 const int charCount = currentCharIndex + 1;
42
43 // allocate a new block of memory size char (1 byte) instead of wide char (2 bytes)
44 Malloc( filePathC, char, charCount );
45 __n_assert( filePathC, return NULL );
46
47 for (int i = 0; i < charCount; i++)
48 {
49 // convert to char (1 byte)
50 char character = pwchar[i];
51
52 *filePathC = character;
53
54 filePathC += sizeof(char);
55
56 }
57 filePathC += '\0';
58
59 filePathC -= (sizeof(char) * charCount);
60
61 return filePathC;
62}
63
64#define neterrno WSAGetLastError()
65
66#define netstrerror( code )({ \
67 wchar_t *s = NULL; \
68 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
69 NULL, code , \
70 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), \
71 (LPWSTR)&s, 0, NULL); \
72 char *netstr = wchar_to_char( s ); \
73 LocalFree( s ); \
74 netstr ; \
75 })
76
77
78#if __GNUC__ <= 6 && __GNUC_MINOR__ <= 3
79
80/*--------------------------------------------------------------------------------------
81 By Marco Ladino - mladinox.. jan/2016
82 MinGW 3.45 thru 4.5 versions, don't have the socket functions:
83 --> inet_ntop(..)
84 --> inet_pton(..)
85 But with this adapted code using the original functions from FreeBSD,
86 one can to use it in the C/C++ Applications, without problem..!
87 This implementation, include tests for IPV4 and IPV6 addresses,
88 and is full C/C++ compatible..
89 --------------------------------------------------------------------------------------*/
90/* OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp */
91/*-
92 * Copyright (c) 1998 Todd C. Miller <Todd.Miller at courtesan.com>
93 *
94 * Permission to use, copy, modify, and distribute this software for any
95 * purpose with or without fee is hereby granted, provided that the above
96 * copyright notice and this permission notice appear in all copies.
97 *
98 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
100 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
101 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
102 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
103 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
104 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
105 */
106
107/*
108 * Copy src to string dst of size siz. At most siz-1 characters
109 * will be copied. Always NUL terminates (unless siz == 0).
110 * Returns strlen(src); if retval >= siz, truncation occurred.
111 */
112size_t strlcpy(char *dst, const char *src, size_t siz)
113{
114 char *d = dst;
115 const char *s = src;
116 size_t n = siz;
117
118 /* Copy as many bytes as will fit */
119 if (n != 0)
120 {
121 while (--n != 0)
122 {
123 if ((*d++ = *s++) == '\0')
124 break;
125 }
126 }
127
128 /* Not enough room in dst, add NUL and traverse rest of src */
129 if (n == 0)
130 {
131 if (siz != 0)
132 *d = '\0'; /* NUL-terminate dst */
133 while (*s++)
134 ;
135 }
136
137 return(s - src - 1); /* count does not include NUL */
138}
139
140
141/*
142 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
143 * Copyright (c) 1996-1999 by Internet Software Consortium.
144 *
145 * Permission to use, copy, modify, and distribute this software for any
146 * purpose with or without fee is hereby granted, provided that the above
147 * copyright notice and this permission notice appear in all copies.
148 *
149 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
150 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
151 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
152 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
153 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
154 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
155 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
156 */
157
158/*
159 * WARNING: Don't even consider trying to compile this on a system where
160 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
161 */
162
163static char *inet_ntop4(const unsigned char *src, char *dst, socklen_t size);
164static char *inet_ntop6(const unsigned char *src, char *dst, socklen_t size);
165
166/* char *
167 * inet_ntop(af, src, dst, size)
168 * convert a network format address to presentation format.
169 * return:
170 * pointer to presentation format address (`dst'), or NULL (see errno).
171 * author:
172 * Paul Vixie, 1996.
173 */
174char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
175{
176 switch (af)
177 {
178 case AF_INET:
179 return (inet_ntop4((const unsigned char*)src, dst, size));
180 case AF_INET6:
181 return (inet_ntop6((const unsigned char*)src, dst, size));
182 default:
183 return (NULL);
184 }
185 /* NOTREACHED */
186}
187
188/* const char *
189 * inet_ntop4(src, dst, size)
190 * format an IPv4 address
191 * return:
192 * `dst' (as a const)
193 * notes:
194 * (1) uses no statics
195 * (2) takes a u_char* not an in_addr as input
196 * author:
197 * Paul Vixie, 1996.
198 */
199static char *inet_ntop4(const unsigned char *src, char *dst, socklen_t size)
200{
201 static const char fmt[] = "%u.%u.%u.%u";
202 char tmp[sizeof "255.255.255.255"];
203 int l;
204
205 l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
206 if (l <= 0 || (socklen_t) l >= size)
207 {
208 return (NULL);
209 }
210 strlcpy(dst, tmp, size);
211 return (dst);
212}
213
214/* const char *
215 * inet_ntop6(src, dst, size)
216 * convert IPv6 binary address into presentation (printable) format
217 * author:
218 * Paul Vixie, 1996.
219 */
220static char *inet_ntop6(const unsigned char *src, char *dst, socklen_t size)
221{
222 /*
223 * Note that int32_t and int16_t need only be "at least" large enough
224 * to contain a value of the specified size. On some systems, like
225 * Crays, there is no such thing as an integer variable with 16 bits.
226 * Keep this in mind if you think this function should have been coded
227 * to use pointer overlays. All the world's not a VAX.
228 */
229 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
230 struct
231 {
232 int base, len;
233 } best, cur;
234#define NS_IN6ADDRSZ 16
235#define NS_INT16SZ 2
236 u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
237 int i;
238
239 /*
240 * Preprocess:
241 * Copy the input (bytewise) array into a wordwise array.
242 * Find the longest run of 0x00's in src[] for :: shorthanding.
243 */
244 memset(words, '\0', sizeof words);
245 for (i = 0; i < NS_IN6ADDRSZ; i++)
246 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
247 best.base = -1;
248 best.len = 0;
249 cur.base = -1;
250 cur.len = 0;
251 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
252 {
253 if (words[i] == 0)
254 {
255 if (cur.base == -1)
256 cur.base = i, cur.len = 1;
257 else
258 cur.len++;
259 }
260 else
261 {
262 if (cur.base != -1)
263 {
264 if (best.base == -1 || cur.len > best.len)
265 best = cur;
266 cur.base = -1;
267 }
268 }
269 }
270 if (cur.base != -1)
271 {
272 if (best.base == -1 || cur.len > best.len)
273 best = cur;
274 }
275 if (best.base != -1 && best.len < 2)
276 best.base = -1;
277
278 /*
279 * Format the result.
280 */
281 tp = tmp;
282 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
283 {
284 /* Are we inside the best run of 0x00's? */
285 if (best.base != -1 && i >= best.base &&
286 i < (best.base + best.len))
287 {
288 if (i == best.base)
289 *tp++ = ':';
290 continue;
291 }
292 /* Are we following an initial run of 0x00s or any real hex? */
293 if (i != 0)
294 *tp++ = ':';
295 /* Is this address an encapsulated IPv4? */
296 if (i == 6 && best.base == 0 && (best.len == 6 ||
297 (best.len == 7 && words[7] != 0x0001) ||
298 (best.len == 5 && words[5] == 0xffff)))
299 {
300 if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
301 return (NULL);
302 tp += strlen(tp);
303 break;
304 }
305 tp += sprintf(tp, "%x", words[i]);
306 }
307 /* Was it a trailing run of 0x00's? */
308 if (best.base != -1 && (best.base + best.len) ==
309 (NS_IN6ADDRSZ / NS_INT16SZ))
310 *tp++ = ':';
311 *tp++ = '\0';
312
313 /*
314 * Check for overflow, copy, and we're done.
315 */
316 if ((socklen_t)(tp - tmp) > size)
317 {
318 return (NULL);
319 }
320 strcpy(dst, tmp);
321 return (dst);
322}
323
324/*
325 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
326 * Copyright (c) 1996,1999 by Internet Software Consortium.
327 *
328 * Permission to use, copy, modify, and distribute this software for any
329 * purpose with or without fee is hereby granted, provided that the above
330 * copyright notice and this permission notice appear in all copies.
331 *
332 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
333 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
334 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
335 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
336 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
337 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
338 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
339 */
340
341/*
342 * WARNING: Don't even consider trying to compile this on a system where
343 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
344 */
345
346static int inet_pton4(const char *src, u_char *dst);
347static int inet_pton6(const char *src, u_char *dst);
348
349/* int
350 * inet_pton(af, src, dst)
351 * convert from presentation format (which usually means ASCII printable)
352 * to network format (which is usually some kind of binary format).
353 * return:
354 * 1 if the address was valid for the specified address family
355 * 0 if the address wasn't valid (`dst' is untouched in this case)
356 * -1 if some other error occurred (`dst' is untouched in this case, too)
357 * author:
358 * Paul Vixie, 1996.
359 */
360int inet_pton(int af, const char *src, void *dst)
361{
362 switch (af)
363 {
364 case AF_INET:
365 return (inet_pton4(src, (unsigned char *)dst));
366 case AF_INET6:
367 return (inet_pton6(src, (unsigned char *)dst));
368 default:
369 return (-1);
370 }
371 /* NOTREACHED */
372}
373
374/* int
375 * inet_pton4(src, dst)
376 * like inet_aton() but without all the hexadecimal and shorthand.
377 * return:
378 * 1 if `src' is a valid dotted quad, else 0.
379 * notice:
380 * does not touch `dst' unless it's returning 1.
381 * author:
382 * Paul Vixie, 1996.
383 */
384static int inet_pton4(const char *src, u_char *dst)
385{
386 static const char digits[] = "0123456789";
387 int saw_digit, octets, ch;
388#define NS_INADDRSZ 4
389 u_char tmp[NS_INADDRSZ], *tp;
390
391 saw_digit = 0;
392 octets = 0;
393 *(tp = tmp) = 0;
394 while ((ch = *src++) != '\0')
395 {
396 const char *pch;
397
398 if ((pch = strchr(digits, ch)) != NULL)
399 {
400 u_int uiNew = *tp * 10 + (pch - digits);
401
402 if (saw_digit && *tp == 0)
403 return (0);
404 if (uiNew > 255)
405 return (0);
406 *tp = uiNew;
407 if (!saw_digit)
408 {
409 if (++octets > 4)
410 return (0);
411 saw_digit = 1;
412 }
413 }
414 else if (ch == '.' && saw_digit)
415 {
416 if (octets == 4)
417 return (0);
418 *++tp = 0;
419 saw_digit = 0;
420 }
421 else
422 return (0);
423 }
424 if (octets < 4)
425 return (0);
426 memcpy(dst, tmp, NS_INADDRSZ);
427 return (1);
428}
429
430/* int
431 * inet_pton6(src, dst)
432 * convert presentation level address to network order binary form.
433 * return:
434 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
435 * notice:
436 * (1) does not touch `dst' unless it's returning 1.
437 * (2) :: in a full address is silently ignored.
438 * credit:
439 * inspired by Mark Andrews.
440 * author:
441 * Paul Vixie, 1996.
442 */
443static int inet_pton6(const char *src, u_char *dst)
444{
445 static const char xdigits_l[] = "0123456789abcdef",
446 xdigits_u[] = "0123456789ABCDEF";
447#define NS_IN6ADDRSZ 16
448#define NS_INT16SZ 2
449 u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
450 const char *curtok;
451 int ch, seen_xdigits;
452 u_int val;
453
454 memset((tp = tmp), '\0', NS_IN6ADDRSZ);
455 endp = tp + NS_IN6ADDRSZ;
456 colonp = NULL;
457 /* Leading :: requires some special handling. */
458 if (*src == ':')
459 if (*++src != ':')
460 return (0);
461 curtok = src;
462 seen_xdigits = 0;
463 val = 0;
464 while ((ch = *src++) != '\0')
465 {
466 const char *xdigits :
467 const char *pch ;
468
469 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
470 pch = strchr((xdigits = xdigits_u), ch);
471 if (pch != NULL)
472 {
473 val <<= 4;
474 val |= (pch - xdigits);
475 if (++seen_xdigits > 4)
476 return (0);
477 continue;
478 }
479 if (ch == ':')
480 {
481 curtok = src;
482 if (!seen_xdigits)
483 {
484 if (colonp)
485 return (0);
486 colonp = tp;
487 continue;
488 }
489 else if (*src == '\0')
490 {
491 return (0);
492 }
493 if (tp + NS_INT16SZ > endp)
494 return (0);
495 *tp++ = (u_char) (val >> 8) & 0xff;
496 *tp++ = (u_char) val & 0xff;
497 seen_xdigits = 0;
498 val = 0;
499 continue;
500 }
501 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
502 inet_pton4(curtok, tp) > 0)
503 {
504 tp += NS_INADDRSZ;
505 seen_xdigits = 0;
506 break; /* '\\0' was seen by inet_pton4(). */
507 }
508 return (0);
509 }
510 if (seen_xdigits)
511 {
512 if (tp + NS_INT16SZ > endp)
513 return (0);
514 *tp++ = (u_char) (val >> 8) & 0xff;
515 *tp++ = (u_char) val & 0xff;
516 }
517 if (colonp != NULL)
518 {
519 /*
520 * Since some memmove()'s erroneously fail to handle
521 * overlapping regions, we'll do the shift by hand.
522 */
523 const int n = tp - colonp;
524 int i;
525
526 if (tp == endp)
527 return (0);
528 for (i = 1; i <= n; i++)
529 {
530 endp[- i] = colonp[n - i];
531 colonp[n - i] = 0;
532 }
533 tp = endp;
534 }
535 if (tp != endp)
536 return (0);
537 memcpy(dst, tmp, NS_IN6ADDRSZ);
538 return (1);
539}
540
541#endif /* if GCC_VERSION <= 4.5 */
542
543#else /* not __windows__ */
544
545#include <sys/types.h>
546#include <sys/wait.h>
547
548
550#define neterrno errno
551
553/* #define netstrerror( code )({ \
554 size_t errmsglen = 512 ; // strerrorlen_s( code ) + 1 ; \
555 char *errmsg = NULL ; \
556 Malloc( errmsg , char , errmsglen ); \
557 if( errmsg ) \
558 { \
559 strerror_s( errmsg , errmsglen , code ); \
560 } \
561 errmsg ; \
562 }) */
563
565#define netstrerror( code )({ \
566 char *errmsg = NULL ; \
567 errno = 0 ; \
568 errmsg = strdup( strerror( code ) ); \
569 if( errno == ENOMEM ) \
570 { \
571 errmsg = NULL ; \
572 } \
573 errmsg ; \
574 })
575
576
581void netw_sigchld_handler( int sig )
582{
583 // waitpid() might overwrite errno, so we save and restore it:
584 int saved_errno = errno;
585 while(waitpid(-1, NULL, WNOHANG) > 0);
586 errno = saved_errno;
587 n_log( LOG_DEBUG, "Signal %d", sig );
588}
589
590#endif /* if not def windows */
591
598NETWORK *netw_new( int send_list_limit, int recv_list_limit )
599{
600 NETWORK *netw = NULL ;
601
602 Malloc( netw, NETWORK, 1 );
603 __n_assert( netw, return NULL );
604
605 /* netw itself */
606 netw -> nb_pending = -1 ;
607 netw -> mode = -1 ;
608 netw -> user_id = -1 ;
609 netw -> nb_running_threads = 0 ;
610 netw -> state = NETW_EXITED ;
611 netw -> threaded_engine_status = NETW_THR_ENGINE_STOPPED ;
612
613 /* netw -> link */
614 netw -> link . sock = -1 ;
615 netw -> link . port =
616 netw -> link . ip = NULL ;
617 memset( &netw -> link . hints, 0, sizeof( struct addrinfo ) );
618 memset( &netw -> link . raddr, 0, sizeof( struct sockaddr_storage ) );
619
620 /*initiliaze mutexs*/
621 if ( pthread_mutex_init( &netw -> sendbolt, NULL ) != 0 )
622 {
623 n_log( LOG_ERR, "Error initializing netw -> sendbolt" );
624 Free( netw );
625 return NULL ;
626 }
627 /*initiliaze mutexs*/
628 if ( pthread_mutex_init( &netw -> recvbolt, NULL ) != 0 )
629 {
630 n_log( LOG_ERR, "Error initializing netw -> recvbolt" );
631 pthread_mutex_destroy( &netw -> sendbolt );
632 Free( netw );
633 return NULL ;
634 }
635 /*initiliaze mutexs*/
636 if ( pthread_mutex_init( &netw -> eventbolt, NULL ) != 0 )
637 {
638 n_log( LOG_ERR, "Error initializing netw -> eventbolt" );
639 pthread_mutex_destroy( &netw -> sendbolt );
640 pthread_mutex_destroy( &netw -> recvbolt );
641 Free( netw );
642 return NULL ;
643 }
644 /* initialize send sem bolt */
645 if( sem_init(&netw -> send_blocker, 0, 0 ) != 0 )
646 {
647 n_log( LOG_ERR, "Error initializing netw -> eventbolt" );
648 pthread_mutex_destroy( &netw -> eventbolt );
649 pthread_mutex_destroy( &netw -> sendbolt );
650 pthread_mutex_destroy( &netw -> recvbolt );
651 Free( netw );
652 return NULL ;
653 }
654 /*initialize queues */
655 netw -> recv_buf = new_generic_list( recv_list_limit );
656 if( ! netw -> recv_buf )
657 {
658 n_log( LOG_ERR, "Error when creating receive list with %d item limit", recv_list_limit );
659 netw_close( &netw );
660 return NULL ;
661 }
662 netw -> send_buf = new_generic_list( send_list_limit );
663 if( !netw -> send_buf )
664 {
665 n_log( LOG_ERR, "Error when creating send list with %d item limit", send_list_limit );
666 netw_close( &netw );
667 return NULL ;
668 }
669 netw -> pools = new_generic_list( -1 );
670 if( !netw -> pools )
671 {
672 n_log( LOG_ERR, "Error when creating pools list" );
673 netw_close( &netw );
674 return NULL ;
675 }
676 netw -> addr_infos_loaded = 0 ;
677 netw -> send_queue_consecutive_wait = 0 ;
678 netw -> so_reuseaddr = -1 ;
679 netw -> tcpnodelay = -1 ;
680 netw -> so_sndbuf = -1 ;
681 netw -> so_rcvbuf = -1 ;
682 netw -> so_rcvtimeo = -1 ;
683 netw -> so_sndtimeo = -1 ;
684 netw -> so_linger = -1 ;
685 netw -> deplete_timeout = 0 ;
686 netw -> crypto_mode = NETW_CRYPTO_NONE ;
687 netw -> crypto_algo = NETW_ENCRYPT_NONE ;
688
689 netw -> send_data = &send_data;
690 netw -> recv_data = &recv_data;
691
692 netw -> link . is_blocking = 0 ;
693 return netw ;
694
695} /* netw_new() */
696
697
698
704char *get_in_addr(struct sockaddr *sa)
705{
706 return sa->sa_family == AF_INET
707 ? (char *)&(((struct sockaddr_in *)sa)->sin_addr)
708 : (char *)&(((struct sockaddr_in6 *)sa)->sin6_addr);
709}
710
711
719int netw_init_wsa( int mode, int v1, int v2 )
720{
721 int compiler_warning_suppressor = 0 ;
722#if !defined( __linux__ ) && !defined( __sun ) && !defined( _AIX )
723 static WSADATA WSAdata; /*WSA world*/
724 static int WSA_IS_INITIALIZED = 0; /*status checking*/
725
726 switch ( mode )
727 {
728 default:
729 /*returning WSA status*/
730 case 2 :
731 return WSA_IS_INITIALIZED;
732 break;
733 /*loading WSA dll*/
734 case 1 :
735 if ( WSA_IS_INITIALIZED == 1 )
736 return TRUE; /*already loaded*/
737 if ( ( WSAStartup( MAKEWORD( v1, v2 ), &WSAdata ) ) != 0 )
738 {
739 WSA_IS_INITIALIZED = 0;
740 return FALSE;
741 }
742 else
743 {
744 WSA_IS_INITIALIZED = 1 ;
745 return TRUE;
746 }
747 break;
748 /*unloading (closing) WSA */
749 case 0 :
750 if ( WSA_IS_INITIALIZED == 0 )
751 return TRUE; /*already CLEANED or not loaded */
752 if ( WSACleanup() == 0 )
753 {
754 WSA_IS_INITIALIZED = 0;
755 return TRUE;
756 }
757 break;
758 } /*switch(...)*/
759#endif /* ifndef __linux__ __sun _AIX */
760 compiler_warning_suppressor = mode + v1 + v2 ;
761 compiler_warning_suppressor = TRUE ;
762 return compiler_warning_suppressor ;
763} /*netw_init_wsa(...)*/
764
765
766
773int netw_set_blocking( NETWORK *netw, unsigned long int is_blocking )
774{
775 __n_assert( netw, return FALSE );
776
777 int error = 0 ;
778 char *errmsg = NULL ;
779
780#if defined(__linux__) || defined(__sun)
781 int flags = fcntl( netw -> link . sock, F_GETFL, 0 );
782 if ( (flags &O_NONBLOCK) && !is_blocking )
783 {
784 n_log( LOG_DEBUG, "socket %d was already in non-blocking mode", netw -> link . sock );
785 /* in case we missed it, let's update the link mode */
786 netw -> link. is_blocking = 0 ;
787 return TRUE;
788 }
789 if (!(flags &O_NONBLOCK) && is_blocking )
790 {
791 /* in case we missed it, let's update the link mode */
792 netw -> link. is_blocking = 1 ;
793 n_log( LOG_DEBUG, "socket %d was already in blocking mode", netw -> link . sock );
794 return TRUE;
795 }
796 if( fcntl(netw -> link . sock, F_SETFL, is_blocking ? flags ^ O_NONBLOCK : flags | O_NONBLOCK) == -1 )
797 {
798 error = neterrno ;
799 errmsg = netstrerror( error );
800 n_log( LOG_ERR, "couldn't set blocking mode %d on %d: %s", is_blocking, netw -> link . sock, _str( errmsg ) );
801 FreeNoLog( errmsg );
802 return FALSE ;
803 }
804#else
805 unsigned long int blocking = 1 - is_blocking ;
806 int res = ioctlsocket( netw -> link . sock, FIONBIO, &blocking );
807 error = neterrno ;
808 if( res != NO_ERROR )
809 {
810 errmsg = netstrerror( error );
811 n_log( LOG_ERR, "ioctlsocket failed with error: %ld , neterrno: %s", res, _str( errmsg ) );
812 FreeNoLog( errmsg );
813 netw_close( &netw );
814 return FALSE ;
815 }
816#endif
817 netw -> link. is_blocking = is_blocking ;
818 return TRUE ;
819} /* netw_set_blocking */
820
821
822
830int netw_setsockopt( NETWORK *netw, int optname, int value )
831{
832 __n_assert( netw, return FALSE );
833
834 int error = 0 ;
835 char *errmsg = NULL ;
836
837 switch( optname )
838 {
839 case TCP_NODELAY :
840 if( value >= 0 )
841 {
842 /* disable naggle algorithm */
843 if ( setsockopt( netw -> link . sock, IPPROTO_TCP, TCP_NODELAY, ( const char * ) &value, sizeof( value ) ) == -1 )
844 {
845 error = neterrno ;
846 errmsg = netstrerror( error );
847 n_log( LOG_ERR, "Error from setsockopt(TCP_NODELAY) on socket %d. neterrno: %s", netw -> link . sock, _str( errmsg ) );
848 FreeNoLog( errmsg );
849 return FALSE ;
850 }
851 }
852 netw -> tcpnodelay = value ;
853 break ;
854 case SO_SNDBUF :
855 /* socket sending buffer size */
856 if( value >= 0 )
857 {
858 if ( setsockopt ( netw -> link . sock, SOL_SOCKET, SO_SNDBUF, ( const char * ) &value, sizeof( value ) ) == -1 )
859 {
860 error = neterrno ;
861 errmsg = netstrerror( error );
862 n_log( LOG_ERR, "Error from setsockopt(SO_SNDBUF) on socket %d. neterrno: %s", netw -> link . sock, _str( errmsg ) );
863 return FALSE ;
864 }
865 }
866 netw -> so_sndbuf = value ;
867 break ;
868 case SO_RCVBUF :
869 /* socket receiving buffer */
870 if( value >= 0 )
871 {
872 if ( setsockopt ( netw -> link . sock, SOL_SOCKET, SO_RCVBUF, ( const char * ) &value, sizeof( value ) ) == -1 )
873 {
874 error = neterrno ;
875 errmsg = netstrerror( error );
876 n_log( LOG_ERR, "Error from setsockopt(SO_RCVBUF) on socket %d. neterrno: %s", netw -> link . sock, _str( errmsg ) );
877 FreeNoLog( errmsg );
878 return FALSE ;
879 }
880 }
881 netw -> so_rcvbuf = value ;
882 break ;
883 case SO_REUSEADDR :
884 /* lose the pesky "Address already in use" error message*/
885 /* Disabled SO_REUSEPORT because not widely supported */
886 if ( setsockopt( netw -> link . sock, SOL_SOCKET, SO_REUSEADDR, (char *)&value, sizeof( value ) ) == -1 )
887 {
888 error=neterrno ;
889 errmsg = netstrerror( error );
890 n_log( LOG_ERR, "Error from setsockopt(SO_REUSEADDR) on socket %d. neterrno: %s", netw -> link . sock, _str( errmsg ) );
891 FreeNoLog( errmsg );
892 return FALSE ;
893 }
894 netw -> so_reuseaddr = value ;
895 break ;
896 case SO_LINGER :
897 {
898 struct linger ling;
899 if( value < 0 )
900 {
901 ling.l_onoff=0;
902 ling.l_linger=0;
903 }
904 else if( value == 0 )
905 {
906 ling.l_onoff=1;
907 ling.l_linger=0;
908 }
909 else
910 {
911 ling.l_onoff=1;
912 ling.l_linger=value;
913 }
914#ifndef __windows__
915 if( setsockopt(netw -> link . sock, SOL_SOCKET, SO_LINGER, &ling, sizeof( ling ) ) == -1 )
916 {
917 error=neterrno ;
918 errmsg = netstrerror( error );
919 n_log( LOG_ERR, "Error from setsockopt(SO_LINGER) on socket %d. neterrno: %s", netw -> link . sock,_str( errmsg ) );
920 FreeNoLog( errmsg );
921 return FALSE ;
922 }
923#else
924 if( setsockopt(netw -> link . sock, SOL_SOCKET, SO_LINGER, (const char *)&ling, sizeof( ling ) ) == -1 )
925 {
926 error=neterrno ;
927 errmsg = netstrerror( error );
928 n_log( LOG_ERR, "Error from setsockopt(SO_LINGER) on socket %d. neterrno: %s", netw -> link . sock,_str( errmsg ) );
929 FreeNoLog( errmsg );
930 return FALSE ;
931 }
932#endif // __windows__
933 netw -> so_linger = value ;
934 }
935 break ;
936 case SO_RCVTIMEO :
937 if( value >= 0 )
938 {
939#ifndef __windows__
940 {
941 struct timeval tv;
942 tv.tv_sec = value ;
943 tv.tv_usec = 0;
944 if( setsockopt(netw -> link . sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv) == -1 )
945 {
946 error=neterrno ;
947 errmsg = netstrerror( error );
948 n_log( LOG_ERR, "Error from setsockopt(SO_RCVTIMEO) on socket %d. neterrno: %s", netw -> link . sock, _str( errmsg ) );
949 FreeNoLog( errmsg );
950 return FALSE ;
951 }
952 }
953#else
954 if( setsockopt(netw -> link . sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&value, sizeof value ) == -1 )
955 {
956 error=neterrno ;
957 errmsg = netstrerror( error );
958 n_log( LOG_ERR, "Error from setsockopt(SO_RCVTIMEO) on socket %d. neterrno: %s", netw -> link . sock, _str( errmsg ) );
959 FreeNoLog( errmsg );
960 return FALSE ;
961 }
962#endif
963 }
964 netw -> so_rcvtimeo = value ;
965 break ;
966 case SO_SNDTIMEO :
967 if( value >= 0 )
968 {
969#ifndef __windows__
970 {
971 struct timeval tv;
972 tv.tv_sec = value ;
973 tv.tv_usec = 0;
974
975 if( setsockopt(netw -> link . sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof tv) == -1 )
976 {
977 error=neterrno ;
978 errmsg = netstrerror( error );
979 n_log( LOG_ERR, "Error from setsockopt(SO_SNDTIMEO) on socket %d. neterrno: %s", netw -> link . sock, _str( errmsg ) );
980 FreeNoLog( errmsg );
981 return FALSE ;
982 }
983 }
984#else
985 if( setsockopt(netw -> link . sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&value, sizeof value ) == -1 )
986 {
987 error=neterrno ;
988 errmsg = netstrerror( error );
989 n_log( LOG_ERR, "Error from setsockopt(SO_SNDTIMEO) on socket %d. neterrno: %s", netw -> link . sock, _str( errmsg ) );
990 FreeNoLog( errmsg );
991 return FALSE ;
992 }
993#endif
994 }
995 netw -> so_sndtimeo = value ;
996 break ;
998 netw -> deplete_timeout = value ;
999 break;
1001 netw -> send_queue_consecutive_wait = value ;
1002 break ;
1003#ifdef __linux__
1004 case TCP_USER_TIMEOUT:
1005 {
1006 unsigned int timeout = 1000 * value ;
1007 if( setsockopt(netw -> link . sock, SOL_SOCKET, TCP_USER_TIMEOUT, (const char*)&timeout, sizeof timeout) == -1 )
1008 {
1009 error=neterrno ;
1010 errmsg = netstrerror( error );
1011 n_log( LOG_ERR, "Error from setsockopt(TCP_USER_TIMEOUT) on socket %d. neterrno: %s", netw -> link . sock, _str( errmsg ) );
1012 FreeNoLog( errmsg );
1013 return FALSE ;
1014 }
1015 }
1016 break ;
1017#endif
1018 case SO_KEEPALIVE:
1019 if( setsockopt(netw -> link . sock, SOL_SOCKET, SO_KEEPALIVE, (const char*)&value, sizeof value) == -1 )
1020 {
1021 error=neterrno ;
1022 errmsg = netstrerror( error );
1023 n_log( LOG_ERR, "Error from setsockopt(SO_KEEPALIVE) on socket %d. neterrno: %s", netw -> link . sock, _str( errmsg ) );
1024 FreeNoLog( errmsg );
1025 return FALSE ;
1026 }
1027 break ;
1028
1029 default:
1030 n_log( LOG_ERR, "%d is not a supported setsockopt", optname );
1031 return FALSE ;
1032 }
1033 return TRUE ;
1034} /* netw_set_sock_opt */
1035
1036
1037
1038#ifdef HAVE_OPENSSL
1039/***************************************************************************
1040 * _ _ ____ _
1041 * Project ___| | | | _ \| |
1042 * / __| | | | |_) | |
1043 * | (__| |_| | _ <| |___
1044 * \___|\___/|_| \_\_____|
1045 *
1046 * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel at haxx.se>, et al.
1047 *
1048 * This software is licensed as described in the file COPYING, which
1049 * you should have received as part of this distribution. The terms
1050 * are also available at https://curl.haxx.se/docs/copyright.html.
1051 *
1052 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1053 * copies of the Software, and permit persons to whom the Software is
1054 * furnished to do so, under the terms of the COPYING file.
1055 *
1056 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1057 * KIND, either express or implied.
1058 *
1059 ***************************************************************************/
1060/* <DESC>
1061 * Show the required mutex callback setups for GnuTLS and OpenSSL when using
1062 * libcurl multi-threaded.
1063 * </DESC>
1064 */
1065/* A multi-threaded example that uses pthreads and fetches 4 remote files at
1066 * once over HTTPS. The lock callbacks and stuff assume OpenSSL <1.1 or GnuTLS
1067 * (libgcrypt) so far.
1068 *
1069 * OpenSSL docs for this:
1070 * https://www.openssl.org/docs/man1.0.2/man3/CRYPTO_num_locks.html
1071 * gcrypt docs for this:
1072 * https://gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html
1073 */
1074
1075/* we have this global to let the callback get easy access to it */
1076static pthread_mutex_t *lockarray;
1077
1078static void lock_callback(int mode, int type, char *file, int line)
1079{
1080 (void)file;
1081 (void)line;
1082 if(mode & CRYPTO_LOCK)
1083 {
1084 pthread_mutex_lock(&(lockarray[type]));
1085 }
1086 else
1087 {
1088 pthread_mutex_unlock(&(lockarray[type]));
1089 }
1090}
1091
1092static unsigned long thread_id(void)
1093{
1094 unsigned long ret;
1095
1096 ret = (unsigned long)pthread_self();
1097 return ret;
1098}
1099
1100static void init_locks(void)
1101{
1102 int i;
1103
1104 lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
1105 sizeof(pthread_mutex_t));
1106 for(i = 0; i<CRYPTO_num_locks(); i++)
1107 {
1108 pthread_mutex_init(&(lockarray[i]), NULL);
1109 }
1110
1111 CRYPTO_set_id_callback((unsigned long (*)())thread_id);
1112 CRYPTO_set_locking_callback((void (*)())lock_callback);
1113}
1114
1115static void kill_locks(void)
1116{
1117 int i;
1118
1119 CRYPTO_set_locking_callback(NULL);
1120 for(i = 0; i<CRYPTO_num_locks(); i++)
1121 pthread_mutex_destroy(&(lockarray[i]));
1122
1123 OPENSSL_free(lockarray);
1124}
1125
1126
1131int netw_init_openssl( void )
1132{
1133 static int OPENSSL_IS_INITIALIZED = 0; /*status checking*/
1134
1135 if ( OPENSSL_IS_INITIALIZED == 1 )
1136 return TRUE; /*already loaded*/
1137
1138#ifdef HAVE_OPENSSL
1139 SSL_library_init();
1140 SSL_load_error_strings();
1141 ERR_load_BIO_strings();
1142 OpenSSL_add_all_algorithms();
1143 OpenSSL_add_all_algorithms();
1144 init_locks();
1145#endif
1146
1147 OPENSSL_IS_INITIALIZED = 1 ;
1148
1149 return TRUE ;
1150} /*netw_init_openssl(...)*/
1151
1156int netw_init_openssl( void )
1157{
1158 static int OPENSSL_IS_INITIALIZED = 0; /*status checking*/
1159
1160 if ( OPENSSL_IS_INITIALIZED == 1 )
1161 return TRUE; /*already loaded*/
1162
1163#ifdef HAVE_OPENSSL
1164 SSL_load_error_strings();
1165 SSL_library_init();
1166 ERR_load_BIO_strings();
1167 OpenSSL_add_all_algorithms();
1168 OpenSSL_add_all_algorithms();
1169 init_locks();
1170#endif
1171
1172 OPENSSL_IS_INITIALIZED = 1 ;
1173
1174 return TRUE ;
1175} /*netw_init_openssl(...)*/
1176
1177int netw_set_crypto( NETWORK *netw, char *key, char *certificat, char *vigenere )
1178{
1179 __n_assert( netw, return FALSE );
1180
1181 if( key && strlen( key ) > 0 )
1182 {
1183 netw -> key = strdup( key );
1184 }
1185 if( certificat && strlen( certificat ) > 0 )
1186 {
1187 netw -> certificat = strdup( certificat );
1188 }
1189 if( vigenere && strlen( vigenere ) > 0 )
1190 {
1191 netw -> vigenere = strdup( vigenere );
1192 }
1193
1194 netw_init_openssl();
1195
1196 netw -> method = TLSv1_2_method(); /* create new server-method instance */
1197 netw -> ctx = SSL_CTX_new(method); /* create new context from method */
1198 if ( ctx == NULL )
1199 {
1200 unsigned long error = 0 ;
1201 while( error = ERR_get_error() )
1202 {
1203 n_log( LOG_ERR, "%s on socket %d", ERR_reason_error_string( ERR_get_error(), NULL ) );
1204 }
1205
1206 EVP_CIPHER_CTX_free( netw -> ctx );
1207 return FALSE ;
1208 }
1209} /* netw_set_crypto */
1210
1211
1212#endif // HAVE_OPENSSL WIP
1213
1214
1215
1226int netw_connect_ex( NETWORK **netw, char *host, char *port, int send_list_limit, int recv_list_limit, int ip_version )
1227{
1228 int error = 0, net_status = 0;
1229 char *errmsg = NULL ;
1230
1231 /*do not work over an already used netw*/
1232 if( (*netw) )
1233 {
1234 n_log( LOG_ERR, "Unable to allocate (*netw), already existing. You must use empty NETWORK *structs." );
1235 return FALSE ;
1236 }
1237
1238 /*creating array*/
1239 (*netw) = netw_new( send_list_limit, recv_list_limit );
1240 __n_assert( netw&&(*netw), return FALSE );
1241
1242 /*checking WSA when under windows*/
1243 if ( netw_init_wsa( 1, 2, 2 ) == FALSE )
1244 {
1245 n_log( LOG_ERR, "Unable to load WSA dll's" );
1246 Free( (*netw) );
1247 return FALSE ;
1248 }
1249
1250 /* choose ip version */
1251 if( ip_version == NETWORK_IPV4 )
1252 {
1253 (*netw) -> link . hints . ai_family = AF_INET ; /* Allow IPv4 */
1254 }
1255 else if( ip_version == NETWORK_IPV6 )
1256 {
1257 (*netw) -> link . hints . ai_family = AF_INET6 ; /* Allow IPv6 */
1258 }
1259 else
1260 {
1261 /* NETWORK_ALL or unknown value */
1262 (*netw) -> link . hints . ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
1263 }
1264
1265 (*netw) -> link . hints . ai_socktype = SOCK_STREAM;
1266 (*netw) -> link . hints . ai_protocol = IPPROTO_TCP;
1267 (*netw) -> link . hints . ai_flags = AI_PASSIVE;
1268 (*netw) -> link . hints . ai_canonname = NULL;
1269 (*netw) -> link . hints . ai_next = NULL;
1270
1271 /* Note: on some system, i.e Solaris, it WILL show leak in getaddrinfo.
1272 * Testing it inside a 1,100 loop showed not effect on the amount of leaked
1273 * memory */
1274 error = getaddrinfo( host, port, &(*netw) -> link . hints, &(*netw) -> link . rhost );
1275 if( error != 0 )
1276 {
1277 n_log( LOG_ERR, "Error when resolving %s:%s getaddrinfo: %s", host, port, gai_strerror( error ) );
1278 netw_close( &(*netw) );
1279 return FALSE ;
1280 }
1281 (*netw) -> addr_infos_loaded = 1 ;
1282 Malloc( (*netw) -> link . ip, char, 64 );
1283 __n_assert( (*netw) -> link . ip, netw_close( &(*netw ) ); return FALSE );
1284
1285 /* getaddrinfo() returns a list of address structures. Try each address until we successfully connect. If socket or connect fails, we close the socket and try the next address. */
1286 struct addrinfo *rp = NULL ;
1287 for( rp = (*netw) -> link . rhost ; rp != NULL ; rp = rp -> ai_next )
1288 {
1289 int sock = socket( rp -> ai_family, rp -> ai_socktype, rp->ai_protocol );
1290 if( sock == -1 )
1291 {
1292 error = neterrno ;
1293 errmsg = netstrerror( error );
1294 n_log( LOG_ERR, "Error while trying to make a socket: %s", _str( errmsg ) );
1295 FreeNoLog( errmsg );
1296 continue ;
1297 }
1298
1299 (*netw) -> link . sock = sock ;
1300
1301 net_status = connect( sock, rp -> ai_addr, rp -> ai_addrlen );
1302 if( net_status == -1 )
1303 {
1304 error = neterrno ;
1305 errmsg = netstrerror( error );
1306 n_log( LOG_INFO, "connecting to %s:%s : %s", host, port, _str( errmsg ) );
1307 FreeNoLog( errmsg );
1308 closesocket( sock );
1309 (*netw) -> link . sock = -1 ;
1310 continue ;
1311 }
1312 else
1313 {
1314 /*storing connected port and ip adress*/
1315 if(!inet_ntop( rp->ai_family, get_in_addr( rp -> ai_addr ), (*netw) -> link . ip, 64 ) )
1316 {
1317 error = neterrno ;
1318 errmsg = netstrerror( error );
1319 n_log( LOG_ERR, "inet_ntop: %p , %s", rp, _str( errmsg ) );
1320 FreeNoLog( errmsg );
1321 }
1322 break; /* Success */
1323 }
1324 }
1325 if( rp == NULL )
1326 {
1327 /* No address succeeded */
1328 n_log( LOG_ERR, "Couldn't connect to %s:%s : no adress succeeded", host, port );
1329 netw_close( &(*netw) );
1330 return FALSE ;
1331 }
1332
1333 (*netw)->link . port = strdup( port );
1334 __n_assert( (*netw) -> link . port, netw_close( &(*netw ) ); return FALSE );
1335
1336#ifdef HAVE_OPENSSL
1337 (*netw) -> key = NULL ;
1338 (*netw) -> certificat = NULL ;
1339#endif
1340
1341 (*netw) -> vigenere_key = NULL ;
1342
1343
1344 n_log( LOG_DEBUG, "Connected to %s:%s", (*netw) -> link . ip, (*netw) -> link . port );
1345
1346 netw_set( (*netw), NETW_CLIENT|NETW_RUN|NETW_THR_ENGINE_STOPPED );
1347
1348 return TRUE ;
1349} /* netw_connect_ex(...)*/
1350
1351
1352
1361int netw_connect( NETWORK **netw, char *host, char *port, int ip_version )
1362{
1363 n_log( LOG_INFO, "Trying to connect to %s : %s", _str( host ), _str( port ) );
1364 return netw_connect_ex( &(*netw), host, port, -1, -1, ip_version );
1365} /* netw_connect() */
1366
1367
1368
1376int netw_get_state( NETWORK *netw, int *state, int *thr_engine_status )
1377{
1378 if( netw )
1379 {
1380 pthread_mutex_lock( &netw -> sendbolt );
1381 if( state )
1382 (*state) = netw -> state ;
1383 if( thr_engine_status )
1384 (*thr_engine_status) = netw -> threaded_engine_status ;
1385 pthread_mutex_unlock( &netw -> sendbolt );
1386 return TRUE ;
1387 }
1388 else
1389 {
1390 n_log( LOG_ERR, "Can't get status of a NULL network" );
1391 }
1392 return FALSE ;
1393} /*netw_get_state() */
1394
1395
1396
1403int netw_set( NETWORK *netw, int flag )
1404{
1405 if( flag & NETW_EMPTY_SENDBUF )
1406 {
1407 pthread_mutex_lock( &netw -> sendbolt );
1408 if( netw -> send_buf )
1409 list_empty( netw -> send_buf );
1410 pthread_mutex_unlock( &netw -> sendbolt );
1411 };
1412 if( flag & NETW_EMPTY_RECVBUF )
1413 {
1414 pthread_mutex_lock( &netw -> recvbolt );
1415 if( netw -> recv_buf )
1416 list_empty( netw -> recv_buf );
1417 pthread_mutex_unlock( &netw -> recvbolt );
1418 }
1419 if( flag & NETW_DESTROY_SENDBUF )
1420 {
1421 pthread_mutex_lock( &netw -> sendbolt );
1422 if( netw -> send_buf )
1423 list_destroy( &netw -> send_buf );
1424 pthread_mutex_unlock( &netw -> sendbolt );
1425 };
1426 if( flag & NETW_DESTROY_RECVBUF )
1427 {
1428 pthread_mutex_lock( &netw -> recvbolt );
1429 if( netw -> recv_buf )
1430 list_destroy( &netw -> recv_buf );
1431 pthread_mutex_unlock( &netw -> recvbolt );
1432 }
1433 pthread_mutex_lock( &netw -> eventbolt );
1434 if( flag & NETW_CLIENT )
1435 {
1436 netw -> mode = NETW_CLIENT ;
1437 }
1438 if( flag & NETW_SERVER )
1439 {
1440 netw -> mode = NETW_SERVER ;
1441 }
1442 if( flag & NETW_RUN )
1443 {
1444 netw -> state = NETW_RUN ;
1445 }
1446 if( flag & NETW_EXITED )
1447 {
1448 netw -> state = NETW_EXITED ;
1449 }
1450 if( flag & NETW_ERROR )
1451 {
1452 netw -> state = NETW_ERROR ;
1453 }
1454 if( flag & NETW_EXIT_ASKED )
1455 {
1456 netw -> state = NETW_EXIT_ASKED ;
1457 }
1458 if( flag & NETW_THR_ENGINE_STARTED )
1459 {
1460 netw -> threaded_engine_status = NETW_THR_ENGINE_STARTED ;
1461 }
1462 if( flag & NETW_THR_ENGINE_STOPPED )
1463 {
1464 netw -> threaded_engine_status = NETW_THR_ENGINE_STOPPED ;
1465 }
1466 pthread_mutex_unlock( &netw -> eventbolt );
1467
1468 sem_post( &netw -> send_blocker );
1469
1470 return TRUE;
1471} /* netw_set(...) */
1472
1473
1474
1480int netw_close( NETWORK **netw )
1481{
1482 int state = 0, thr_engine_status = 0 ;
1483 __n_assert( netw&&(*netw), return FALSE );
1484
1485 list_foreach( node, (*netw) -> pools )
1486 {
1487 NETWORK_POOL *pool = (NETWORK_POOL *)node -> ptr ;
1488 netw_pool_remove( pool, (*netw) );
1489 }
1490
1491 list_destroy( &(*netw) -> pools );
1492
1493 netw_get_state( (*netw), &state, &thr_engine_status );
1494 if( thr_engine_status == NETW_THR_ENGINE_STARTED )
1495 {
1496 netw_stop_thr_engine( (*netw ) );
1497 }
1498
1499 /*closing connection*/
1500 /* Now with end of send fix */
1501 if( (*netw) -> link . sock != INVALID_SOCKET )
1502 {
1503 closesocket( (*netw) -> link . sock );
1504 n_log( LOG_DEBUG, "socket %d closed", (*netw) -> link . sock );
1505 }
1506
1507 FreeNoLog( (*netw) -> link . ip );
1508 FreeNoLog( (*netw) -> link . port );
1509#ifdef HAVE_OPENSSL
1510 FreeNoLog( (*netw) -> key );
1511 FreeNoLog( (*netw) -> certificat );
1512#endif
1513 FreeNoLog( (*netw) -> vigenere_key );
1514
1515 if( (*netw) -> link . rhost )
1516 {
1517 freeaddrinfo( (*netw) -> link . rhost );
1518 }
1519
1520 /*list freeing*/
1521 netw_set( (*netw), NETW_DESTROY_SENDBUF|NETW_DESTROY_RECVBUF );
1522
1523 pthread_mutex_destroy( &(*netw) -> recvbolt );
1524 pthread_mutex_destroy( &(*netw) -> sendbolt );
1525 pthread_mutex_destroy( &(*netw) -> eventbolt );
1526 sem_destroy( &(*netw) -> send_blocker );
1527
1528 Free( (*netw) );
1529
1530 return TRUE;
1531} /* netw_close(...)*/
1532
1533
1534
1541int deplete_send_buffer( int fd, size_t timeout )
1542{
1543#if defined( __linux__ )
1544 int outstanding = 0 ;
1545 if( timeout == 0 )
1546 {
1547 return 0 ;
1548 }
1549 for( size_t it = 0 ; it < timeout ; it += 100 )
1550 {
1551 outstanding = 0 ;
1552 ioctl(fd, SIOCOUTQ, &outstanding);
1553 if(!outstanding)
1554 {
1555 break;
1556 }
1557 usleep( 100000 );
1558 }
1559 return outstanding ;
1560#else
1561 (void)fd;
1562 (void)timeout;
1563 return 0 ;
1564#endif
1565}
1566
1567
1575{
1576 // default 30 secs timeout
1577 return netw_wait_close_timed( netw, 30 );
1578} /* netw_wait_close(...)*/
1579
1580
1581
1589int netw_wait_close_timed( NETWORK **netw, size_t timeout )
1590{
1591 int state = 0, thr_engine_status = 0 ;
1592 __n_assert( netw&&(*netw), return FALSE );
1593
1594 int error = 0 ;
1595 size_t countdown = timeout * 1000000 ;
1596 char *errmsg = NULL ;
1597 int nb_running = 0 ;
1598
1599 netw_get_state( (*netw), &state, &thr_engine_status );
1600 if( thr_engine_status == NETW_THR_ENGINE_STARTED )
1601 {
1602 do
1603 {
1604 pthread_mutex_lock( &(*netw) -> eventbolt );
1605 nb_running = (*netw) -> nb_running_threads ;
1606 pthread_mutex_unlock( &(*netw) -> eventbolt );
1607 usleep( 100000 );
1608 countdown -= 100000 ;
1609 }
1610 while( nb_running > 0 && countdown > 0 );
1611 netw_get_state( (*netw), &state, &thr_engine_status );
1612 if( countdown == 0 && nb_running > 0 )
1613 {
1614 n_log( LOG_ERR, "netw %d: %d threads are still running after %d seconds, netw is in state %s (%d)", (*netw) -> link . sock, nb_running, timeout, N_ENUM_ENTRY(__netw_code_type,toString)(state), state );
1615 }
1616 }
1617
1618 /* wait for close fix */
1619 if( (*netw) -> link . sock != INVALID_SOCKET )
1620 {
1621 /* inform peer that we have finished */
1622 shutdown( (*netw) -> link . sock, SHUT_WR );
1623 int remaining = deplete_send_buffer( (*netw) -> link . sock, (*netw) -> deplete_timeout );
1624 if( remaining > 0 )
1625 {
1626 n_log( LOG_ERR, "socket %d (%s:%s) %d octets still in send buffer before closing after a wait of %d seconds", (*netw) -> link . sock, (*netw) -> link . ip, (*netw) -> link . port, remaining, (int)(*netw) -> deplete_timeout );
1627 }
1628 /* wait for fin ack */
1629 char buffer[ 4096 ] = "" ;
1630 for( size_t it = 0 ; it < (timeout*1000000) ; it += 100000 )
1631 {
1632 int res = 0 ;
1633 res = recv( (*netw) -> link . sock, buffer, 4096, NETFLAGS );
1634 if( !res )
1635 break;
1636 if( res < 0 )
1637 {
1638 error = neterrno ;
1639 if( error != ENOTCONN && error != 10057 && error != EINTR && error != ECONNRESET ) // no an error if already closed
1640 {
1641 errmsg = netstrerror( error );
1642 n_log( LOG_ERR, "read returned error %d when closing socket %d (%s:%s): %s", error, (*netw) -> link . sock, _str( (*netw) -> link . ip ), (*netw) -> link . port, _str( errmsg ) );
1643 FreeNoLog( errmsg );
1644 }
1645 break ;
1646 }
1647 usleep( 100000 );
1648 }
1649 }
1650 return netw_close( &(*netw) );
1651
1652} /* netw_wait_close_timed(...)*/
1653
1654
1655
1665int netw_make_listening( NETWORK **netw, char *addr, char *port, int nbpending, int ip_version )
1666{
1667 __n_assert( port, return FALSE );
1668
1669 int error = 0 ;
1670 char *errmsg = NULL ;
1671
1672 if( *netw )
1673 {
1674 n_log( LOG_ERR, "Cannot use an allocated network. Please pass a NULL network to modify" );
1675 return FALSE;
1676 }
1677
1678 /*checking WSA when under windows*/
1679 if ( netw_init_wsa( 1, 2, 2 ) == FALSE )
1680 {
1681 n_log( LOG_ERR, "Unable to load WSA dll's" );
1682 return FALSE ;
1683 }
1684
1685 (*netw) = netw_new( -1, -1 );
1686 (*netw) -> link . port = strdup( port );
1687 /*creating array*/
1688 if( ip_version == NETWORK_IPV4 )
1689 {
1690 (*netw) -> link . hints . ai_family = AF_INET ; /* Allow IPv4 */
1691 }
1692 else if( ip_version == NETWORK_IPV6 )
1693 {
1694 (*netw) -> link . hints . ai_family = AF_INET6 ; /* Allow IPv6 */
1695 }
1696 else
1697 {
1698 /* NETWORK_ALL or unknown value */
1699 (*netw) -> link . hints . ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
1700 }
1701 if( !addr )
1702 {
1703 (*netw) -> link . hints . ai_flags = AI_PASSIVE; /* For wildcard IP address */
1704 }
1705 (*netw) -> link . hints . ai_socktype = SOCK_STREAM;
1706 (*netw) -> link . hints . ai_protocol = IPPROTO_TCP;
1707 (*netw) -> link . hints . ai_canonname = NULL;
1708 (*netw) -> link . hints . ai_next = NULL;
1709
1710 error = getaddrinfo( addr, port, &(*netw) -> link . hints, &(*netw) -> link . rhost );
1711 if( error != 0)
1712 {
1713 n_log( LOG_ERR, "Error when resolving %s:%s getaddrinfo: %s", _str( addr ), port, gai_strerror( error ) );
1714 netw_close( &(*netw) );
1715 return FALSE ;
1716 }
1717 (*netw) -> addr_infos_loaded = 1 ;
1718
1719 /* getaddrinfo() returns a list of address structures.
1720 Try each address until we successfully connect(2).
1721 If socket(2) (or connect(2)) fails, we (close the socket
1722 and) try the next address. */
1723 struct addrinfo *rp = NULL ;
1724 for( rp = (*netw) -> link . rhost ; rp != NULL ; rp = rp -> ai_next )
1725 {
1726 (*netw) -> link . sock = socket( rp -> ai_family, rp -> ai_socktype, rp->ai_protocol );
1727 if( (*netw) -> link . sock == INVALID_SOCKET )
1728 {
1729 error = neterrno ;
1730 errmsg = netstrerror( error );
1731 n_log( LOG_ERR, "Error while trying to make a socket: %s", _str( errmsg ) );
1732 FreeNoLog( errmsg );
1733 continue ;
1734 }
1735 netw_setsockopt( (*netw), SO_REUSEADDR, 1 );
1736 if( bind( (*netw) -> link . sock, rp -> ai_addr, rp -> ai_addrlen ) == 0 )
1737 {
1738 char *ip = NULL ;
1739 Malloc( ip, char, 64 );
1740 if( !ip )
1741 {
1742 n_log( LOG_ERR, "Error allocating 64 bytes for ip" );
1743 netw_close( &(*netw) );
1744 return FALSE ;
1745 }
1746 if( !inet_ntop( rp -> ai_family, get_in_addr( rp -> ai_addr ), ip, 64 ) )
1747 {
1748 error = neterrno ;
1749 errmsg = netstrerror( error );
1750 n_log( LOG_ERR, "inet_ntop: %p , %s", (*netw) -> link . raddr, _str( errmsg ) );
1751 FreeNoLog( errmsg );
1752 }
1753 /*n_log( LOG_DEBUG, "Socket %d successfully binded to %s %s", (*netw) -> link . sock, _str( ip ) , _str( port ) );*/
1754 (*netw) -> link . ip = ip ;
1755 break; /* Success */
1756 }
1757 error = neterrno ;
1758 errmsg = netstrerror( error );
1759 n_log( LOG_ERR, "Error from bind() on port %s neterrno: %s", port, netstrerror( neterrno ), error );
1760 FreeNoLog( errmsg );
1761 closesocket( (*netw) -> link .sock );
1762 }
1763 if( rp == NULL )
1764 {
1765 /* No address succeeded */
1766 n_log( LOG_ERR, "Couldn't get a socket for listening on port %s", port );
1767 netw_close( &(*netw) );
1768 return FALSE ;
1769 }
1770
1771 /* nb_pending connections*/
1772 ( *netw ) -> nb_pending = nbpending ;
1773 listen( ( *netw ) -> link . sock, ( *netw ) -> nb_pending );
1774
1775 netw_set( (*netw), NETW_SERVER|NETW_RUN|NETW_THR_ENGINE_STOPPED );
1776
1777 return TRUE;
1778} /* netw_make_listening(...)*/
1779
1780
1781
1791NETWORK *netw_accept_from_ex( NETWORK *from, int send_list_limit, int recv_list_limit, int non_blocking, int *retval )
1792{
1793 int tmp = 0, error = 0;
1794 char *errmsg = NULL ;
1795
1796#if defined( __linux__ ) || defined( __sun ) || defined( _AIX )
1797 socklen_t sin_size = 0 ;
1798#else
1799 int sin_size = 0 ;
1800#endif
1801
1802 NETWORK *netw = NULL ;
1803
1804 /*checking WSA when under windows*/
1805 if( netw_init_wsa( 1, 2, 2 ) == FALSE )
1806 {
1807 n_log( LOG_ERR, "Unable to load WSA dll's" );
1808 return NULL ;
1809 }
1810
1811 __n_assert( from, return NULL );
1812
1813 netw = netw_new( send_list_limit, recv_list_limit );
1814
1815 sin_size = sizeof( netw -> link . raddr );
1816
1817 if( non_blocking > 0 )
1818 {
1819 int secs = non_blocking/1000 ;
1820 int usecs = (non_blocking%1000)*1000;
1821 struct timeval select_timeout = { secs, usecs };
1822
1823 fd_set accept_set ;
1824 FD_SET( from -> link . sock, &accept_set );
1825 FD_ZERO( &accept_set );
1826
1827 int ret = select( from -> link . sock + 1, &accept_set, NULL, NULL, &select_timeout );
1828 if( ret == -1 )
1829 {
1830 error = neterrno ;
1831 errmsg = netstrerror( error );
1832 if( retval != NULL )
1833 (*retval) = error ;
1834 n_log( LOG_ERR, "Error on select with timeout %ds (%d.%ds), neterrno: %s", non_blocking, secs, usecs, _str( errmsg ) );
1835 FreeNoLog( errmsg );
1836 netw_close( &netw );
1837 return NULL;
1838 }
1839 else if( ret == 0 )
1840 {
1841 /* that one produce waaaay too much logs under a lot of cases */
1842 /* n_log( LOG_DEBUG , "No connection waiting on %d" , from -> link . sock ); */
1843 netw_close( &netw );
1844 return NULL;
1845 }
1846 if( FD_ISSET( from -> link . sock, &accept_set ) )
1847 {
1848 //n_log( LOG_DEBUG, "select accept call on %d", from -> link . sock );
1849 tmp = accept( from -> link . sock, (struct sockaddr * )&netw -> link . raddr, &sin_size );
1850 if ( tmp < 0 )
1851 {
1852 error = neterrno ;
1853 errmsg = netstrerror( error );
1854 if( retval != NULL )
1855 (*retval) = error ;
1856 n_log( LOG_DEBUG, "error accepting on %d, %s", netw -> link . sock, _str( errmsg ) );
1857 FreeNoLog( errmsg );
1858 netw_close( &netw );
1859 return NULL;
1860 }
1861 }
1862 else
1863 {
1864 netw_close( &netw );
1865 return NULL;
1866 }
1867 netw -> link . is_blocking = 0 ;
1868 }
1869 else if( non_blocking == -1 )
1870 {
1871 if( from -> link . is_blocking == 1 )
1872 {
1873 netw_set_blocking( from, 0 );
1874 n_log( LOG_INFO, "changed to non blocking accept call on %d", from -> link . sock );
1875 }
1876 tmp = accept( from -> link . sock, (struct sockaddr *)&netw -> link . raddr, &sin_size );
1877 error = neterrno ;
1878 if( retval != NULL )
1879 (*retval) = error ;
1880
1881 if ( tmp < 0 )
1882 {
1883 netw_close( &netw );
1884 return NULL;
1885 }
1886 netw -> link . is_blocking = 0 ;
1887 }
1888 else
1889 {
1890 if( from -> link . is_blocking == 0 )
1891 {
1892 netw_set_blocking( from, 1 );
1893 n_log( LOG_DEBUG, "(default) blocking accept call on socket %d", from -> link . sock );
1894 }
1895 tmp = accept( from -> link . sock, (struct sockaddr *)&netw -> link . raddr, &sin_size );
1896 if ( tmp < 0 )
1897 {
1898 error = neterrno ;
1899 errmsg = netstrerror( error );
1900 n_log( LOG_ERR, "error accepting on socket %d, %s", netw -> link . sock, _str( errmsg ) );
1901 FreeNoLog( errmsg );
1902 netw_close( &netw );
1903 return NULL;
1904 }
1905 netw -> link . is_blocking = 0 ;
1906 }
1907 netw -> link . sock = tmp ;
1908 netw -> link . port = strdup( from -> link . port );
1909 Malloc( netw -> link . ip, char, 64 );
1910 if( !netw -> link . ip )
1911 {
1912 n_log( LOG_ERR, "Error allocating 64 bytes for ip" );
1913 netw_close( &netw );
1914 return FALSE ;
1915 }
1916 if( !inet_ntop( netw -> link . raddr . ss_family, get_in_addr( ((struct sockaddr *)&netw -> link . raddr) ), netw -> link . ip, 64 ) )
1917 {
1918 error = neterrno ;
1919 errmsg = netstrerror( error );
1920 n_log( LOG_ERR, "inet_ntop: %p , %s", netw -> link . raddr, _str( errmsg ) );
1921 FreeNoLog( errmsg );
1922 }
1923 netw_setsockopt( netw, SO_REUSEADDR, 1 );
1924
1925 netw_set( netw, NETW_SERVER|NETW_RUN|NETW_THR_ENGINE_STOPPED );
1926 n_log( LOG_DEBUG, "Connection accepted from %s:%s socket %d", netw-> link . ip, netw -> link . port , netw -> link . sock );
1927
1928 netw_set_blocking( netw , 1 );
1929
1930 return netw;
1931} /* netw_accept_from_ex(...) */
1932
1933
1934
1941{
1942 return netw_accept_from_ex( from, 0, 0, 0, NULL );
1943} /* network_accept_from( ... ) */
1944
1945
1946
1954{
1955 return netw_accept_from_ex( from, 0, 0, blocking, NULL );
1956} /* network_accept_from( ... ) */
1957
1958
1965int netw_add_msg( NETWORK *netw, N_STR *msg )
1966{
1967 __n_assert( netw, return FALSE );
1968 __n_assert( msg, return FALSE );
1969 __n_assert( msg -> data, return FALSE );
1970
1971 if( msg -> length <= 0 )
1972 {
1973 n_log( LOG_ERR, "Empty messages are not supported. msg(%p)->lenght=%d", msg, msg -> length );
1974 return FALSE;
1975 }
1976
1977 pthread_mutex_lock( &netw -> sendbolt );
1978
1979 if( list_push( netw -> send_buf, msg, free_nstr_ptr ) == FALSE )
1980 {
1981 pthread_mutex_unlock( &netw -> sendbolt );
1982 return FALSE;
1983 }
1984
1985 pthread_mutex_unlock( &netw -> sendbolt );
1986
1987 sem_post( &netw -> send_blocker );
1988
1989 return TRUE;
1990} /* netw_add_msg(...) */
1991
1992
1993
2001int netw_add_msg_ex( NETWORK *netw, char *str, unsigned int length )
2002{
2003 __n_assert( netw, return FALSE );
2004 __n_assert( str, return FALSE );
2005 if( length == 0 )
2006 {
2007 return FALSE ;
2008 }
2009
2010 N_STR *nstr = NULL ;
2011 Malloc( nstr, N_STR, 1 );
2012 __n_assert( nstr, return FALSE );
2013
2014 if( length == 0 )
2015 {
2016 n_log( LOG_ERR, "Empty messages are not supported. msg(%p)->lenght=%d", str, length );
2017 return FALSE;
2018 }
2019
2020 nstr -> data = str ;
2021 nstr -> written = nstr -> length = length ;
2022
2023 pthread_mutex_lock( &netw -> sendbolt );
2024 if( list_push( netw -> send_buf, nstr, free_nstr_ptr ) == FALSE )
2025 {
2026 pthread_mutex_unlock( &netw -> sendbolt );
2027 return FALSE;
2028 }
2029 pthread_mutex_unlock( &netw -> sendbolt );
2030
2031 sem_post( &netw -> send_blocker );
2032
2033 return TRUE;
2034} /* netw_add_msg_ex(...) */
2035
2036
2037
2038
2045{
2046 N_STR * ptr = NULL ;
2047
2048 __n_assert( netw, return NULL );
2049
2050 pthread_mutex_lock( &netw -> recvbolt );
2051
2052 ptr = list_shift( netw -> recv_buf, N_STR );
2053
2054 pthread_mutex_unlock( &netw -> recvbolt );
2055
2056 return ptr ;
2057} /* netw_get_msg(...)*/
2058
2059
2060
2068N_STR *netw_wait_msg( NETWORK *netw, size_t refresh, size_t timeout )
2069{
2070 N_STR *nstrptr = NULL ;
2071 size_t timed = 0 ;
2072 size_t secs = 0 ;
2073 size_t usecs = 0 ;
2074
2075 __n_assert( netw, return NULL );
2076
2077 usecs = refresh ;
2078 if( refresh > 999999 )
2079 {
2080 secs = refresh / 1000000 ;
2081 usecs = refresh % 1000000 ;
2082 }
2083
2084 if( timeout > 0 )
2085 timed = timeout ;
2086
2087 int state = NETW_RUN, thr_state = 0 ;
2088 do
2089 {
2090 nstrptr = netw_get_msg( netw );
2091 if( nstrptr )
2092 return nstrptr ;
2093
2094 if( timeout > 0 )
2095 {
2096 if( timed >= refresh )
2097 timed -= refresh ;
2098 if( timed == 0 || timed < refresh )
2099 {
2100 n_log( LOG_ERR, "netw %d, status: %s (%d), timeouted after waiting %zu msecs", netw -> link . sock, N_ENUM_ENTRY(__netw_code_type,toString)(state), state, timeout );
2101 return NULL ;
2102 }
2103 }
2104 if(secs > 0)
2105 sleep( secs );
2106 if( usecs > 0 )
2107 u_sleep( usecs );
2108
2109 netw_get_state( netw, &state, &thr_state );
2110 }
2111 while( state != NETW_EXITED && state != NETW_ERROR );
2112
2113 n_log( LOG_ERR, "got no answer and netw %d is no more running, state: %s (%d)" , netw -> link . sock, N_ENUM_ENTRY(__netw_code_type,toString)(state), state);
2114
2115 return NULL ;
2116} /* netw_wait_msg(...) */
2117
2118
2119
2126{
2127 __n_assert( netw, return FALSE );
2128
2129 pthread_mutex_lock( &netw -> eventbolt );
2130 if( netw -> threaded_engine_status == NETW_THR_ENGINE_STARTED )
2131 {
2132 n_log( LOG_ERR, "THR Engine already started for network %p (%s)", netw, _str( netw -> link . ip ) );
2133 pthread_mutex_unlock( &netw -> eventbolt );
2134 return FALSE ;
2135 }
2136
2137 if( pthread_create( &netw -> recv_thr, NULL, netw_recv_func, (void *) netw ) != 0 )
2138 {
2139 n_log( LOG_ERR, "Unable to create recv_thread for network %p (%s)", netw, _str( netw -> link . ip ) );
2140 pthread_mutex_unlock( &netw -> eventbolt );
2141 return FALSE ;
2142 }
2143 netw -> nb_running_threads ++ ;
2144 if( pthread_create( &netw -> send_thr, NULL, netw_send_func, (void *) netw ) != 0 )
2145 {
2146 n_log( LOG_ERR, "Unable to create send_thread for network %p (%s)", netw, _str( netw -> link . ip ) );
2147 pthread_mutex_unlock( &netw -> eventbolt );
2148 return FALSE ;
2149 }
2150 netw -> nb_running_threads ++ ;
2151
2152 netw -> threaded_engine_status = NETW_THR_ENGINE_STARTED ;
2153
2154 pthread_mutex_unlock( &netw -> eventbolt );
2155
2156 return TRUE ;
2157} /* netw_create_recv_thread(....) */
2158
2159
2160
2166void *netw_send_func( void *NET )
2167{
2168 int DONE = 0,
2169 state = 0,
2170 net_status = 0 ;
2171
2172 int32_t nboctet = 0 ;
2173
2174 char nboct[ 5 ] = "" ;
2175
2176 N_STR *ptr = NULL ;
2177
2178 NETWORK *netw = (NETWORK *) NET ;
2179
2180 __n_assert( netw, return NULL );
2181
2182 do
2183 {
2184 /* do not consume cpu for nothing, reduce delay */
2185 sem_wait( &netw -> send_blocker );
2186 int message_sent = 0 ;
2187 while( message_sent == 0 && !DONE )
2188 {
2189 netw_get_state( netw, &state, NULL );
2190 if( state&NETW_ERROR )
2191 {
2192 DONE = 666 ;
2193 }
2194 else if( state&NETW_EXITED )
2195 {
2196 DONE = 100 ;
2197 }
2198 else if( state&NETW_EXIT_ASKED )
2199 {
2200 DONE = 100 ;
2201 /* sending state */
2202 nboctet = htonl( NETW_EXIT_ASKED );
2203 memcpy( nboct, &nboctet, sizeof( int32_t ) );
2204 n_log( LOG_DEBUG, "%d Sending Quit !", netw -> link . sock );
2205 net_status = netw->send_data( netw -> link . sock, nboct, sizeof( int32_t ) );
2206 if( net_status < 0 )
2207 DONE = 4 ;
2208 n_log( LOG_DEBUG, "%d Quit sent!", netw -> link . sock );
2209 }
2210 else
2211 {
2212 pthread_mutex_lock( &netw -> sendbolt );
2213 ptr = list_shift( netw -> send_buf, N_STR ) ;
2214 pthread_mutex_unlock( &netw -> sendbolt );
2215 if( ptr && ptr -> length > 0 && ptr -> data )
2216 {
2217 n_log( LOG_DEBUG, "Sending ptr size %d written %d", ptr -> length, ptr -> written );
2218
2219 /* sending state */
2220 nboctet = htonl( state );
2221 memcpy( nboct, &nboctet, sizeof( int32_t ) );
2222 /* sending state */
2223 if ( !DONE )
2224 {
2225 net_status = netw->send_data( netw -> link . sock, nboct, sizeof( int32_t ) );
2226 if( net_status < 0 )
2227 DONE = 1 ;
2228 }
2229 if( !DONE )
2230 {
2231 /* sending number of octet */
2232 nboctet = htonl( ptr -> written );
2233 memcpy( nboct, &nboctet, sizeof( int32_t ) );
2234 /* sending the number of octet to receive on next message */
2235 net_status = netw->send_data( netw -> link . sock, nboct, sizeof( int32_t ) );
2236 if( net_status < 0 )
2237 DONE = 2 ;
2238 }
2239 /* sending the data itself */
2240 if ( !DONE )
2241 {
2242 net_status = netw->send_data( netw -> link . sock, ptr -> data, ptr -> written );
2243 if( net_status < 0 )
2244 DONE = 3 ;
2245 }
2246 free_nstr( &ptr );
2247 u_sleep( netw -> send_queue_consecutive_wait );
2248 message_sent = 1 ;
2249 }
2250 }
2251 }
2252 }
2253 while( !DONE );
2254
2255 if( DONE == 1 )
2256 n_log( LOG_ERR, "Error when sending state %d on socket %d (%s), network: %s", netw -> state, netw -> link . sock, _str( netw -> link . ip ), (net_status==-2)?"disconnected":"socket error" );
2257 else if( DONE == 2 )
2258 n_log( LOG_ERR, "Error when sending number of octet to socket %d (%s), network: %s", netw -> link . sock, _str( netw -> link . ip ), (net_status==-2)?"disconnected":"socket error" );
2259 else if( DONE == 3 )
2260 n_log( LOG_DEBUG, "Error when sending data on socket %d (%s), network: %s", netw -> link . sock, _str( netw -> link . ip ), (net_status==-2)?"disconnected":"socket error" );
2261 else if( DONE == 4 )
2262 n_log( LOG_ERR, "Error when sending state QUIT on socket %d (%s), network: %s", netw -> link . sock, _str( netw -> link . ip ), (net_status==-2)?"disconnected":"socket error" );
2263 else if( DONE == 5 )
2264 n_log( LOG_ERR, "Error when sending state QUIT number of octet (0) on socket %d (%s), network: %s", netw -> link . sock, _str( netw -> link . ip ), (net_status==-2)?"disconnected":"socket error" );
2265
2266 if( DONE == 100 )
2267 {
2268 n_log( LOG_DEBUG, "Socket %d: Sending thread exiting correctly", netw -> link . sock );
2269 netw_set( netw, NETW_EXIT_ASKED );
2270 }
2271 else
2272 {
2273 n_log( LOG_ERR, "Socket %d (%s): Sending thread exiting with error %d !", netw -> link . sock, _str( netw -> link . ip ),DONE );
2274 netw_set( netw, NETW_ERROR );
2275 }
2276
2277 pthread_mutex_lock( &netw -> eventbolt );
2278 netw -> nb_running_threads -- ;
2279 pthread_mutex_unlock( &netw -> eventbolt );
2280
2281 pthread_exit( 0 );
2282
2283 /* suppress compiler warning */
2284#if !defined( __linux__ )
2285 return NULL ;
2286#endif
2287} /* netw_send_func(...) */
2288
2289
2290
2296void *netw_recv_func( void *NET )
2297{
2298 int DONE = 0,
2299 state = 0,
2300 tmpstate = 0,
2301 net_status = 0 ;
2302
2303 int32_t nboctet = 0 ;
2304
2305 char nboct[ 5 ]= "" ;
2306
2307 N_STR *recvdmsg = NULL ;
2308
2309 NETWORK *netw = (NETWORK *) NET ;
2310
2311 __n_assert( netw, return NULL );
2312
2313 do
2314 {
2315 netw_get_state( netw, &state, NULL );
2316
2317 if( state&NETW_EXIT_ASKED || state&NETW_EXITED )
2318 {
2319 DONE = 100;
2320 }
2321 if( state&NETW_ERROR )
2322 {
2323 DONE = 666 ;
2324 }
2325 else
2326 {
2327 /*if( !DONE && !(state&NETW_EXIT_ASKED) && !(state&NETW_EXITED) ) */
2328 if( !DONE )
2329 {
2330 /* receiving state */
2331 net_status = netw->recv_data( netw -> link . sock, nboct, sizeof( int32_t ) );
2332 if( net_status < 0 )
2333 {
2334 DONE = 1 ;
2335 }
2336 else
2337 {
2338 memcpy( &nboctet, nboct, sizeof( int32_t ) );
2339 tmpstate = ntohl( nboctet );
2340 nboctet = tmpstate ;
2341 if( tmpstate==NETW_EXIT_ASKED )
2342 {
2343 n_log( LOG_DEBUG, "%d receiving order to QUIT, nboctet %d NETW_EXIT_ASKED %d !", netw -> link . sock, nboctet, NETW_EXIT_ASKED );
2344 DONE = 100 ;
2345 }
2346 else
2347 {
2348 /* receiving nboctet */
2349 net_status = netw->recv_data( netw -> link . sock, nboct, sizeof( int32_t ) );
2350 if( net_status < 0 )
2351 {
2352 DONE = 2 ;
2353 }
2354 else
2355 {
2356 memcpy( &nboctet, nboct, sizeof( int32_t ) );
2357 tmpstate = ntohl( nboctet );
2358 nboctet = tmpstate ;
2359
2360 Malloc( recvdmsg, N_STR, 1 );
2361 if( !recvdmsg )
2362 {
2363 DONE = 3;
2364 }
2365 else
2366 {
2367 n_log( LOG_DEBUG, "%d octets to receive...", nboctet );
2368 Malloc( recvdmsg -> data, char, nboctet + 1 );
2369 if( !recvdmsg -> data )
2370 {
2371 DONE = 4 ;
2372 }
2373 else
2374 {
2375 recvdmsg -> length = nboctet + 1 ;
2376 recvdmsg -> written = nboctet ;
2377
2378 /* receiving the data itself */
2379 net_status = netw->recv_data( netw -> link . sock, recvdmsg -> data, nboctet );
2380 if( net_status < 0 )
2381 {
2382 DONE = 5 ;
2383 }
2384 else
2385 {
2386 pthread_mutex_lock( &netw -> recvbolt );
2387 if( !DONE && list_push( netw -> recv_buf, recvdmsg, free_nstr_ptr ) == FALSE )
2388 DONE = 6 ;
2389 pthread_mutex_unlock( &netw -> recvbolt );
2390 n_log( LOG_DEBUG, "%d octets received !", nboctet );
2391 } /* recv data */
2392 } /* recv data allocation */
2393 } /* recv struct allocation */
2394 } /* recv nb octet*/
2395 } /* exit asked */
2396 } /* recv state */
2397 } /* if( !done) */
2398 } /* if !exit */
2399 }
2400 while( !DONE );
2401
2402 if( DONE == 1 )
2403 n_log( LOG_ERR, "Error when receiving state from socket %d (%s), net_status: %s", netw -> link . sock, _str( netw -> link . ip ), (net_status==-2)?"disconnected":"socket error" );
2404 else if( DONE == 2 )
2405 n_log( LOG_ERR, "Error when receiving nboctet from socket %d (%s), net_status: %s", netw -> link . sock, _str( netw -> link . ip ), (net_status==-2)?"disconnected":"socket error" );
2406 else if( DONE == 3 )
2407 n_log( LOG_ERR, "Error when receiving data from socket %d (%s), net_status: %s", netw -> link . sock, _str( netw -> link . ip ), (net_status==-2)?"disconnected":"socket error" );
2408 else if( DONE == 4 )
2409 n_log( LOG_ERR, "Error allocating received message struct from socket %d (%s), net_status: %s", netw -> link . sock, _str( netw -> link . ip ), (net_status==-2)?"disconnected":"socket error" );
2410 else if( DONE == 5 )
2411 n_log( LOG_ERR, "Error allocating received messages data array from socket %d (%s), net_status: %s", netw -> link . sock, _str( netw -> link . ip ), (net_status==-2)?"disconnected":"socket error" );
2412 else if( DONE == 6 )
2413 n_log( LOG_ERR, "Error adding receved message from socket %d (%s), net_status: %s", netw -> link . sock, _str( netw -> link . ip ), (net_status==-2)?"disconnected":"socket error" );
2414
2415
2416 if( DONE == 100 )
2417 {
2418 n_log( LOG_DEBUG, "Socket %d (%s): Receive thread exiting correctly", netw -> link . sock, _str( netw -> link . ip ) );
2419 netw_set( netw, NETW_EXIT_ASKED );
2420 }
2421 else
2422 {
2423 n_log( LOG_ERR, "Socket %d (%s): Receive thread exiting with code %d !", netw -> link . sock, _str( netw -> link . ip ), DONE );
2424 netw_set( netw, NETW_ERROR );
2425 }
2426
2427 pthread_mutex_lock( &netw -> eventbolt );
2428 netw -> nb_running_threads -- ;
2429 pthread_mutex_unlock( &netw -> eventbolt );
2430
2431 pthread_exit( 0 );
2432
2433 /* suppress compiler warning */
2434#if !defined( __linux__ )
2435 return NULL ;
2436#endif
2437} /* netw_recv_func(...) */
2438
2439
2440
2447{
2448 __n_assert( netw, return FALSE );
2449 int state = 0, thr_engine_status = 0 ;
2450
2451 n_log( LOG_DEBUG, "Network %d stop threads event", netw -> link . sock );
2452
2453 netw_get_state( netw, &state, &thr_engine_status );
2454
2455 if( thr_engine_status != NETW_THR_ENGINE_STARTED )
2456 {
2457 n_log( LOG_ERR, "Thread engine status already stopped for network %p", netw );
2458 return FALSE ;
2459 }
2460
2461 netw_set( netw, NETW_EXIT_ASKED );
2462
2463 n_log( LOG_DEBUG, "Network %d waits for send threads to stop", netw -> link . sock );
2464 for( int it = 0 ; it < 10 ; it ++ )
2465 {
2466 sem_post( &netw -> send_blocker );
2467 usleep( 1000 );
2468 }
2469 pthread_join( netw -> send_thr, NULL );
2470 n_log( LOG_DEBUG, "Network %d waits for recv threads to stop", netw -> link . sock );
2471 pthread_join( netw -> recv_thr, NULL );
2472
2473 netw_set( netw, NETW_EXITED|NETW_THR_ENGINE_STOPPED );
2474
2475 n_log( LOG_DEBUG, "Network %d threads Stopped !", netw -> link . sock );
2476
2477 return TRUE;
2478} /* Stop_Network( ... ) */
2479
2480
2481
2489int send_data( SOCKET s, char *buf, NSTRBYTE n )
2490{
2491 __n_assert( buf, return -1 );
2492
2493 int bcount = 0 ; /* counts bytes sent */
2494
2495 int error = 0 ;
2496 char *errmsg = NULL ;
2497
2498 if( n == 0 )
2499 {
2500 n_log( LOG_ERR, "Send of 0 is unsupported." );
2501 return -1 ;
2502 }
2503
2504 while( (NSTRBYTE)bcount < n ) /* loop until full buffer */
2505 {
2506 int br = 0 ; /* bytes sent this pass */
2507 br = send( s, buf, n - bcount, NETFLAGS );
2508 error = neterrno ;
2509 if( br > 0 )
2510 {
2511 bcount += br; /* increment byte counter */
2512 buf += br; /* move buffer ptr for next read */
2513 }
2514 else
2515 {
2516 if( error == ECONNRESET || error == ENOTCONN )
2517 {
2518 n_log( LOG_DEBUG, "socket %d disconnected !", s );
2519 return -2 ;
2520 }
2521 /* signal an error to the caller */
2522 errmsg = netstrerror( error );
2523 n_log( LOG_ERR, "Socket %d send Error: %d , %s", s, br, _str( errmsg ) );
2524 FreeNoLog( errmsg );
2525 return -1 ;
2526 }
2527 }
2528
2529 return bcount;
2530} /*send_data(...)*/
2531
2532
2533
2541int recv_data( SOCKET s, char *buf, NSTRBYTE n )
2542{
2543 __n_assert( buf, return -1 );
2544 int bcount = 0 ; /* counts bytes read */
2545
2546 int error = 0 ;
2547 char *errmsg = NULL ;
2548
2549 if( n == 0 )
2550 {
2551 n_log( LOG_ERR, "Recv of 0 is unsupported." );
2552 return -1 ;
2553 }
2554
2555 while( (NSTRBYTE)bcount < n )
2556 {
2557 int br = 0 ; /* bytes read this pass */
2558 /* loop until full buffer */
2559 CALL_RETRY( br, recv( s, buf, n - bcount, NETFLAGS ) );
2560 error = neterrno ;
2561 if( br > 0 )
2562 {
2563 bcount += br; /* increment byte counter */
2564 buf += br; /* move buffer ptr for next read */
2565 }
2566 else
2567 {
2568 if( br == 0 )
2569 {
2570 n_log( LOG_DEBUG, "socket %d disconnected !", s );
2571 return -2 ;
2572 }
2573
2574 /* signal an error to the caller */
2575 errmsg = netstrerror( error );
2576 n_log( LOG_ERR, "socket %d recv returned %d, error: %s", s, br, _str( errmsg ) );
2577 FreeNoLog( errmsg );
2578 return -1 ;
2579 }
2580 }
2581
2582 return bcount;
2583} /*recv_data(...)*/
2584
2585
2586
2596int send_php( SOCKET s, int _code, char *buf, int n )
2597{
2598 int bcount = 0 ; /* counts bytes read */
2599 int br = 0 ; /* bytes read this pass */
2600
2601 int error = 0 ;
2602 char *errmsg = NULL ;
2603
2604 char *ptr = NULL ; /* temp char ptr ;-) */
2605 char tmpstr[ HEAD_SIZE +1 ] = "";
2606 char head[ HEAD_SIZE +1 ] = "" ;
2607 char code[ HEAD_CODE +1 ] = "" ;
2608
2609 snprintf( tmpstr, HEAD_SIZE + 1, "%%0%dd", HEAD_SIZE );
2610 snprintf( head, HEAD_SIZE + 1, tmpstr, n );
2611 snprintf( tmpstr, HEAD_SIZE + 1, "%%0%dd", HEAD_CODE );
2612 snprintf( code, HEAD_CODE + 1, tmpstr, _code );
2613
2614 /* sending head */
2615 bcount = br = 0 ;
2616 ptr = head ;
2617 while ( bcount < HEAD_SIZE ) /* loop until full buffer */
2618 {
2619 CALL_RETRY( br, send( s, head, HEAD_SIZE - bcount, NETFLAGS ) );
2620 error = neterrno ;
2621 if( br > 0 )
2622 {
2623 bcount += br; /* increment byte counter */
2624 ptr += br; /* move buffer ptr for next read */
2625 }
2626 else
2627 {
2628 /* signal an error to the caller */
2629 errmsg = netstrerror( error );
2630 n_log( LOG_ERR, "Socket %d sending Error %d when sending head size, neterrno: %s", s, br, _str( errmsg ) );
2631 FreeNoLog( errmsg );
2632 return FALSE;
2633 }
2634 }
2635
2636 /* sending code */
2637 bcount = br = 0 ;
2638 ptr = code ;
2639 while ( bcount < HEAD_CODE ) /* loop until full buffer */
2640 {
2641 br = send( s, code, HEAD_CODE - bcount, NETFLAGS );
2642 error = neterrno ;
2643 if( br > 0 )
2644 {
2645 bcount += br; /* increment byte counter */
2646 ptr += br; /* move buffer ptr for next read */
2647 }
2648 else
2649 {
2650 errmsg = netstrerror( error );
2651 n_log( LOG_ERR, "Socket %d sending Error %d when sending head code, neterrno: %s", s, br, _str( errmsg ) );
2652 FreeNoLog( errmsg );
2653 return FALSE;
2654 }
2655 }
2656
2657 /* sending buf */
2658 bcount = 0;
2659 br = 0;
2660 while ( bcount < n ) /* loop until full buffer */
2661 {
2662 br = send( s, buf, n - bcount, NETFLAGS );
2663 error = neterrno ;
2664 if( br > 0 )
2665 {
2666 bcount += br; /* increment byte counter */
2667 buf += br; /* move buffer ptr for next read */
2668 }
2669 else
2670 {
2671 /* signal an error to the caller */
2672 errmsg = netstrerror( error );
2673 n_log( LOG_ERR, "Socket %d sending Error %d when sending message of size %d, neterrno: %S", s, br, n, _str( errmsg ) );
2674 FreeNoLog( errmsg );
2675 return FALSE;
2676 }
2677 }
2678
2679 return bcount;
2680
2681} /*send_php(...)*/
2682
2683
2684
2695int recv_php( SOCKET s, int *_code, char **buf )
2696{
2697 int bcount = 0 ; /* counts bytes read */
2698 int br = 0 ; /* bytes read this pass */
2699 long int tmpnb = 0, size = 0 ; /* size of message to receive */
2700 char *ptr = NULL ;
2701
2702 int error = 0 ;
2703 char *errmsg = NULL ;
2704
2705 char head[ HEAD_SIZE + 1 ] = "" ;
2706 char code[ HEAD_CODE + 1] = "" ;
2707
2708 /* Receiving total message size */
2709 bcount = br = 0 ;
2710 ptr = head;
2711 while ( bcount < HEAD_SIZE )
2712 {
2713 /* loop until full buffer */
2714 br = recv( s, ptr, HEAD_SIZE - bcount, NETFLAGS );
2715 error = neterrno ;
2716 if( br > 0 )
2717 {
2718 bcount += br; /* increment byte counter */
2719 ptr += br; /* move buffer ptr for next read */
2720 }
2721 else
2722 {
2723 if( br == 0 && bcount == ( HEAD_SIZE - bcount ) )
2724 break ;
2725 /* signal an error to the caller */
2726 errmsg = netstrerror( error );
2727 n_log( LOG_ERR, "Socket %d receive %d Error %s", s, br, _str( errmsg ) );
2728 FreeNoLog( errmsg );
2729 return FALSE;
2730 }
2731 }
2732
2733 tmpnb = strtol( head, NULL, 10 );
2734 if( tmpnb == LONG_MIN || tmpnb == LONG_MAX )
2735 {
2736 n_log( LOG_ERR, "Size received ( %ld ) can not be determined on socket %d", tmpnb, s );
2737 return FALSE ;
2738 }
2739
2740 size = tmpnb ;
2741
2742 /* receiving request code */
2743 bcount = br = 0 ;
2744 ptr = code;
2745 while ( bcount < HEAD_CODE )
2746 {
2747 /* loop until full buffer */
2748 br = recv( s, ptr, HEAD_CODE - bcount, NETFLAGS );
2749 error = neterrno ;
2750 if( br > 0 )
2751 {
2752 bcount += br; /* increment byte counter */
2753 ptr += br; /* move buffer ptr for next read */
2754 }
2755 else
2756 {
2757 if( br == 0 && bcount == ( HEAD_CODE - bcount ) )
2758 break ;
2759 /* signal an error to the caller */
2760 errmsg = netstrerror( error );
2761 n_log( LOG_ERR, "Socket %d receive %d Error , neterrno: %s", s, br, _str( errmsg ) );
2762 FreeNoLog( errmsg );
2763 return FALSE;
2764 }
2765 }
2766
2767 tmpnb = strtol( code, NULL, 10 );
2768 if( tmpnb == LONG_MIN || tmpnb == LONG_MAX )
2769 {
2770 n_log( LOG_ERR, "Code received ( %ld ) can not be determined on socket %d\n", tmpnb, s );
2771 return FALSE ;
2772 }
2773
2774 (*_code) = tmpnb ;
2775
2776 /* receving message */
2777 if( (*buf ) )
2778 {
2779 Free( (*buf ) );
2780 }
2781 Malloc( (*buf), char, (size+1) );
2782 if( !(*buf ) )
2783 {
2784 n_log( LOG_ERR, "Could not allocate PHP receive buf" );
2785 return FALSE ;
2786 }
2787
2788 bcount = 0;
2789 br = 0;
2790 ptr = (*buf);
2791 while ( bcount < size )
2792 {
2793 /* loop until full buffer */
2794 br = recv( s, ptr, size - bcount, NETFLAGS );
2795 error = neterrno ;
2796 if( br > 0 )
2797 {
2798 bcount += br; /* increment byte counter */
2799 ptr += br; /* move buffer ptr for next read */
2800 }
2801 else
2802 {
2803 if( br == 0 && bcount == ( size - bcount ) )
2804 break ;
2805 /* signal an error to the caller */
2806 errmsg = netstrerror( error );
2807 n_log( LOG_ERR, "Socket %d receive %d Error neterrno: %s", s, br, _str( errmsg ) );
2808 FreeNoLog( errmsg );
2809 return FALSE;
2810 }
2811 }
2812 return size ;
2813} /*recv_php(...)*/
2814
2815
2816
2825int netw_get_queue_status( NETWORK *netw, int *nb_to_send, int *nb_to_read )
2826{
2827 __n_assert( netw, return FALSE );
2828
2829 pthread_mutex_lock( &netw -> sendbolt );
2830 (*nb_to_send) = netw -> send_buf -> nb_items ;
2831 pthread_mutex_unlock( &netw -> sendbolt );
2832
2833 pthread_mutex_lock( &netw -> recvbolt );
2834 (*nb_to_read) = netw -> recv_buf -> nb_items ;
2835 pthread_mutex_unlock( &netw -> recvbolt );
2836
2837 return TRUE ;
2838} /* get queue states */
2839
2840
2841
2847NETWORK_POOL *netw_new_pool( int nb_min_element )
2848{
2849 NETWORK_POOL *netw_pool = NULL ;
2850
2851 Malloc( netw_pool, NETWORK_POOL, 1 );
2852 __n_assert( netw_pool, return NULL );
2853
2854 netw_pool -> pool = new_ht( nb_min_element );
2855 __n_assert( netw_pool -> pool, Free( netw_pool ) ; return NULL );
2856
2857 init_lock( netw_pool -> rwlock );
2858
2859 return netw_pool ;
2860} /* netw_new_pool() */
2861
2862
2863
2870{
2871 __n_assert( netw_pool&&(*netw_pool), return FALSE );
2872
2873 write_lock( (*netw_pool) -> rwlock );
2874 if( (*netw_pool) -> pool )
2875 destroy_ht( &(*netw_pool) -> pool );
2876 unlock( (*netw_pool) -> rwlock );
2877
2878 rw_lock_destroy( (*netw_pool) -> rwlock );
2879
2880 Free( (*netw_pool) );
2881
2882 return TRUE ;
2883} /* netw_destroy_pool() */
2884
2885
2886
2891void netw_pool_netw_close( void *netw_ptr )
2892{
2893 NETWORK *netw = (NETWORK *)netw_ptr ;
2894 __n_assert( netw, return );
2895 n_log( LOG_DEBUG, "Network pool %p: network id %d still active !!", netw, netw -> link . sock );
2896 return ;
2897} /* netw_pool_netw_close() */
2898
2899
2900
2907int netw_pool_add( NETWORK_POOL *netw_pool, NETWORK *netw )
2908{
2909 __n_assert( netw_pool, return FALSE );
2910 __n_assert( netw, return FALSE );
2911
2912 n_log( LOG_DEBUG, "Trying to add %lld to %p", (unsigned long long)netw -> link . sock, netw_pool -> pool );
2913
2914 /* write lock the pool */
2915 write_lock( netw_pool -> rwlock );
2916 /* test if not already added */
2917 N_STR *key = NULL ;
2918 nstrprintf( key, "%lld", (unsigned long long)netw -> link . sock );
2919 HASH_NODE *node = NULL ;
2920 if( ht_get_ptr( netw_pool -> pool, _nstr( key ), (void *)&node ) == TRUE )
2921 {
2922 n_log( LOG_ERR, "Network id %d already added !", netw -> link . sock );
2923 free_nstr( &key );
2924 unlock( netw_pool -> rwlock );
2925 return FALSE ;
2926 }
2927 int retval = FALSE ;
2928 /* add it */
2929 if( ( retval = ht_put_ptr( netw_pool -> pool, _nstr( key ), netw, &netw_pool_netw_close ) ) == TRUE )
2930 {
2931 if( ( retval = list_push( netw -> pools, netw_pool, NULL ) ) == TRUE )
2932 {
2933 n_log( LOG_DEBUG, "added netw %d to pool %p", netw -> link . sock, netw_pool );
2934 }
2935 else
2936 {
2937 n_log( LOG_ERR, "could not add netw %d to pool %p", netw -> link . sock, netw_pool );
2938 }
2939 }
2940 else
2941 {
2942 n_log( LOG_ERR, "could not add netw %d to pool %p", netw -> link . sock, netw_pool );
2943 }
2944 free_nstr( &key );
2945
2946 /* unlock the pool */
2947 unlock( netw_pool -> rwlock );
2948
2949 return retval ;
2950} /* netw_pool_add() */
2951
2952
2953
2960int netw_pool_remove( NETWORK_POOL *netw_pool, NETWORK *netw )
2961{
2962 __n_assert( netw_pool, return FALSE );
2963 __n_assert( netw, return FALSE );
2964
2965 /* write lock the pool */
2966 write_lock( netw_pool -> rwlock );
2967 /* test if present */
2968 N_STR *key = NULL ;
2969 nstrprintf( key, "%lld", (unsigned long long int)netw -> link . sock );
2970 if( ht_remove( netw_pool -> pool, _nstr( key ) ) == TRUE )
2971 {
2972 LIST_NODE *node = list_search( netw -> pools, netw );
2973 if( node )
2974 {
2975 if( !remove_list_node( netw -> pools, node, NETWORK_POOL ) )
2976 {
2977 n_log( LOG_ERR, "Network id %d could not be removed !", netw -> link . sock );
2978 }
2979 }
2980 unlock( netw_pool -> rwlock );
2981 n_log( LOG_DEBUG, "Network id %d removed !", netw -> link . sock );
2982
2983 return TRUE ;
2984 }
2985 free_nstr( &key );
2986 n_log( LOG_ERR, "Network id %d already removed !", netw -> link . sock );
2987 /* unlock the pool */
2988 unlock( netw_pool -> rwlock );
2989 return FALSE ;
2990} /* netw_pool_remove */
2991
2992
2993
3001int netw_pool_broadcast( NETWORK_POOL *netw_pool, NETWORK *from, N_STR *net_msg )
3002{
3003 __n_assert( netw_pool, return FALSE );
3004 __n_assert( net_msg, return FALSE );
3005
3006 /* write lock the pool */
3007 read_lock( netw_pool -> rwlock );
3008 ht_foreach( node, netw_pool -> pool )
3009 {
3010 NETWORK *netw = hash_val( node, NETWORK );
3011 if( from )
3012 {
3013 if( netw -> link . sock != from -> link . sock )
3014 netw_add_msg( netw, nstrdup( net_msg ) );
3015 }
3016 else
3017 {
3018 netw_add_msg( netw, nstrdup( net_msg ) );
3019 }
3020 }
3021 unlock( netw_pool -> rwlock );
3022 return TRUE ;
3023} /* netw_pool_broadcast */
3024
3025
3026
3033{
3034 __n_assert( netw_pool, return -1 );
3035
3036 int nb = -1 ;
3037 read_lock( netw_pool -> rwlock );
3038 nb = netw_pool -> pool -> nb_keys ;
3039 unlock( netw_pool -> rwlock );
3040
3041 return nb ;
3042} /* netw_pool_nbclients() */
3043
3044
3045
3052int netw_set_user_id( NETWORK *netw, int id )
3053{
3054 __n_assert( netw, return FALSE );
3055 netw -> user_id = id ;
3056 return TRUE ;
3057} /* netw_set_user_id() */
3058
3059
3060
3070int netw_send_ping( NETWORK *netw, int type, int id_from, int id_to, int time )
3071{
3072 N_STR *tmpstr = NULL ;
3073 __n_assert( netw, return FALSE );
3074
3075 tmpstr = netmsg_make_ping( type, id_from, id_to, time );
3076 __n_assert( tmpstr, return FALSE );
3077
3078 return netw_add_msg( netw, tmpstr );
3079} /* netw_send_ping( ... ) */
3080
3081
3082
3092int netw_send_ident( NETWORK *netw, int type, int id, N_STR *name, N_STR *passwd )
3093{
3094 N_STR *tmpstr = NULL ;
3095
3096 __n_assert( netw, return FALSE );
3097
3098 tmpstr = netmsg_make_ident( type, id, name, passwd );
3099 __n_assert( tmpstr, return FALSE );
3100
3101 return netw_add_msg( netw, tmpstr );
3102} /* netw_send_ident( ... ) */
3103
3104
3105
3119int netw_send_position( NETWORK *netw, int id, double X, double Y, double vx, double vy, double acc_x, double acc_y, int time_stamp )
3120{
3121 N_STR *tmpstr = NULL ;
3122
3123 __n_assert( netw, return FALSE );
3124
3125 tmpstr = netmsg_make_position_msg( id, X, Y, vx, vy, acc_x, acc_y, time_stamp );
3126
3127 __n_assert( tmpstr, return FALSE );
3128
3129 return netw_add_msg( netw, tmpstr );
3130} /* netw_send_position( ... ) */
3131
3132
3133
3144int netw_send_string_to( NETWORK *netw, int id_to, N_STR *name, N_STR *chan, N_STR *txt, int color )
3145{
3146 N_STR *tmpstr = NULL ;
3147
3148 __n_assert( netw, return FALSE );
3149
3150 tmpstr = netmsg_make_string_msg( netw -> user_id, id_to, name, chan, txt, color );
3151 __n_assert( tmpstr, return FALSE );
3152
3153 return netw_add_msg( netw, tmpstr );
3154} /* netw_send_string_to( ... ) */
3155
3156
3157
3167int netw_send_string_to_all( NETWORK *netw, N_STR *name, N_STR *chan, N_STR *txt, int color )
3168{
3169 N_STR *tmpstr = NULL ;
3170
3171 __n_assert( netw, return FALSE );
3172
3173 tmpstr = netmsg_make_string_msg( netw -> user_id, -1, name, chan, txt, color );
3174 __n_assert( tmpstr, return FALSE );
3175
3176 return netw_add_msg( netw, tmpstr );
3177} /* netw_send_string_to_all( ... ) */
3178
3179
3180
3187{
3188 __n_assert( netw, return FALSE );
3189
3190 N_STR *tmpstr = NULL ;
3191
3192 tmpstr = netmsg_make_quit_msg();
3193 __n_assert( tmpstr, return FALSE );
3194
3195 return netw_add_msg( netw, tmpstr );
3196} /* netw_send_quit( ... ) */
3197
3198
#define init_lock(__rwlock_mutex)
Macro for initializing a rwlock.
Definition: n_common.h:337
#define FreeNoLog(__ptr)
Free Handler without log.
Definition: n_common.h:268
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition: n_common.h:183
#define __n_assert(__ptr, __ret)
macro to assert things
Definition: n_common.h:276
#define _str(__PTR)
define true
Definition: n_common.h:172
#define rw_lock_destroy(__rwlock_mutex)
Macro to destroy rwlock mutex.
Definition: n_common.h:404
#define unlock(__rwlock_mutex)
Macro for releasing read/write lock a rwlock mutex.
Definition: n_common.h:389
#define write_lock(__rwlock_mutex)
Macro for acquiring a write lock on a rwlock mutex.
Definition: n_common.h:373
#define Free(__ptr)
Free Handler to get errors.
Definition: n_common.h:256
#define read_lock(__rwlock_mutex)
Macro for acquiring a read lock on a rwlock mutex.
Definition: n_common.h:357
#define _nstr(__PTR)
N_STR or "NULL" string for logging purposes.
Definition: n_common.h:178
#define CALL_RETRY(retvar, expression)
TEMP_FAILURE gnu macro portable version.
Definition: n_common.h:284
#define N_ENUM_DEFINE(MACRO_DEFINITION, enum_name)
Macro to define an N_ENUM.
Definition: n_enum.h:146
#define N_ENUM_ENTRY(class, method)
helper to build an N_ENUM
Definition: n_enum.h:26
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
Definition: n_hash.c:2282
#define ht_foreach(__ITEM_, __HASH_)
ForEach macro helper (classic / old)
Definition: n_hash.h:163
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
Definition: n_hash.c:2448
int ht_remove(HASH_TABLE *table, const char *key)
remove and delete node at key in table
Definition: n_hash.c:2394
HASH_TABLE * new_ht(size_t size)
Create a hash table with the given size.
Definition: n_hash.c:2167
int ht_put_ptr(HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr))
put a pointer to the string value with given key in the targeted hash table
Definition: n_hash.c:2347
#define hash_val(node, type)
Cast a HASH_NODE element.
Definition: n_hash.h:159
structure of a hash table node
Definition: n_hash.h:83
#define list_shift(__LIST_, __TYPE_)
Shift macro helper for void pointer casting.
Definition: n_list.h:81
int list_empty(LIST *list)
Empty a LIST list of pointers.
Definition: n_list.c:547
#define remove_list_node(__LIST_,__NODE_, __TYPE_)
Remove macro helper for void pointer casting.
Definition: n_list.h:83
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition: n_list.c:244
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper.
Definition: n_list.h:70
int list_destroy(LIST **list)
Empty and Free a list container.
Definition: n_list.c:603
LIST * new_generic_list(int max_items)
Initialiaze a generic list container to max_items pointers.
Definition: n_list.c:20
LIST_NODE * list_search(LIST *list, void *ptr)
search ptr in list
Definition: n_list.c:508
Structure of a generic list node.
Definition: n_list.h:27
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition: n_log.h:74
#define LOG_DEBUG
debug-level messages
Definition: n_log.h:66
#define LOG_ERR
error conditions
Definition: n_log.h:58
#define LOG_INFO
informational
Definition: n_log.h:64
void free_nstr_ptr(void *ptr)
Free a N_STR pointer structure.
Definition: n_str.c:55
size_t NSTRBYTE
N_STR base unit.
Definition: n_str.h:169
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition: n_str.h:222
#define nstrprintf(__nstr_var,...)
Macro to quickly allocate and sprintf to N_STR *.
Definition: n_str.h:97
N_STR * nstrdup(N_STR *str)
Duplicate a N_STR.
Definition: n_str.c:795
A box including a string and his lenght.
Definition: n_str.h:173
void u_sleep(unsigned int usec)
wrapper around usleep for API consistency
Definition: n_time.c:38
N_STR * netmsg_make_position_msg(int id, double X, double Y, double vx, double vy, double acc_x, double acc_y, int time_stamp)
make a network NETMSG_POSITION message with given parameters
N_STR * netmsg_make_ident(int type, int id, N_STR *name, N_STR *passwd)
Add a formatted NETWMSG_IDENT message to the specified network.
N_STR * netmsg_make_quit_msg(void)
make a generic network NETMSG_QUIT message
N_STR * netmsg_make_ping(int type, int id_from, int id_to, int time)
Make a ping message to send to a network.
N_STR * netmsg_make_string_msg(int id_from, int id_to, N_STR *name, N_STR *chan, N_STR *txt, int color)
make a network NETMSG_STRING message with given parameters
netw_func send_data
send func ptr
Definition: n_network.h:295
netw_func recv_data
receive func ptr
Definition: n_network.h:297
int netw_send_string_to_all(NETWORK *netw, N_STR *name, N_STR *chan, N_STR *txt, int color)
Add a string to the network, aiming all server-side users.
Definition: n_network.c:3167
int netw_pool_broadcast(NETWORK_POOL *netw_pool, NETWORK *from, N_STR *net_msg)
add net_msg to all network in netork pool
Definition: n_network.c:3001
N_STR * netw_get_msg(NETWORK *netw)
Get a message from aimed NETWORK.
Definition: n_network.c:2044
int send_php(SOCKET s, int _code, char *buf, int n)
send data onto the socket
Definition: n_network.c:2596
int netw_add_msg(NETWORK *netw, N_STR *msg)
Add a message to send in aimed NETWORK.
Definition: n_network.c:1965
N_STR * netw_wait_msg(NETWORK *netw, size_t refresh, size_t timeout)
Wait a message from aimed NETWORK.
Definition: n_network.c:2068
int netw_pool_nbclients(NETWORK_POOL *netw_pool)
return the number of networks in netw_pool
Definition: n_network.c:3032
int recv_data(SOCKET s, char *buf, NSTRBYTE n)
recv data from the socket
Definition: n_network.c:2541
int netw_init_wsa(int mode, int v1, int v2)
Do not directly use, internal api.
Definition: n_network.c:719
int netw_stop_thr_engine(NETWORK *netw)
Stop a NETWORK connection sending and receing thread.
Definition: n_network.c:2446
void * netw_send_func(void *NET)
Thread send function.
Definition: n_network.c:2166
NETWORK * netw_accept_nonblock_from(NETWORK *from, int blocking)
make a normal blocking 'accept' .
Definition: n_network.c:1953
#define NETWORK_IPV6
Flag to force IPV6
Definition: n_network.h:31
int netw_connect_ex(NETWORK **netw, char *host, char *port, int send_list_limit, int recv_list_limit, int ip_version)
Use this to connect a NETWORK to any listening one.
Definition: n_network.c:1226
int netw_set_user_id(NETWORK *netw, int id)
associate an id and a network
Definition: n_network.c:3052
int netw_make_listening(NETWORK **netw, char *addr, char *port, int nbpending, int ip_version)
Make a NETWORK be a Listening network.
Definition: n_network.c:1665
#define HEAD_SIZE
Size of a HEAD message.
Definition: n_network.h:37
int netw_start_thr_engine(NETWORK *netw)
Start the NETWORK netw Threaded Engine.
Definition: n_network.c:2125
int netw_destroy_pool(NETWORK_POOL **netw_pool)
free a NETWORK_POOL *pool
Definition: n_network.c:2869
#define NETWORK_IPV4
Flag to force IPV4
Definition: n_network.h:29
int netw_wait_close(NETWORK **netw)
Wait for peer closing a specified Network, destroy queues, free the structure.
Definition: n_network.c:1574
void * netw_recv_func(void *NET)
To Thread Receiving function.
Definition: n_network.c:2296
#define HEAD_CODE
Code of a HEAD message.
Definition: n_network.h:39
int netw_get_queue_status(NETWORK *netw, int *nb_to_send, int *nb_to_read)
retrieve network send queue status
Definition: n_network.c:2825
NETWORK * netw_accept_from_ex(NETWORK *from, int send_list_limit, int recv_list_limit, int non_blocking, int *retval)
make a normal 'accept' .
Definition: n_network.c:1791
int netw_setsockopt(NETWORK *netw, int optname, int value)
Modify common socket options on the given netw.
Definition: n_network.c:830
int netw_set(NETWORK *netw, int flag)
Restart or reset the specified network ability.
Definition: n_network.c:1403
void netw_pool_netw_close(void *netw_ptr)
close a network from a network pool
Definition: n_network.c:2891
NETWORK * netw_accept_from(NETWORK *from)
make a normal blocking 'accept' .
Definition: n_network.c:1940
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
Definition: n_network.c:1480
int netw_send_quit(NETWORK *netw)
Add a formatted NETMSG_QUIT message to the specified network.
Definition: n_network.c:3186
int netw_set_blocking(NETWORK *netw, unsigned long int is_blocking)
Modify blocking socket mode.
Definition: n_network.c:773
int netw_send_string_to(NETWORK *netw, int id_to, N_STR *name, N_STR *chan, N_STR *txt, int color)
Add a string to the network, aiming a specific user.
Definition: n_network.c:3144
int netw_send_ping(NETWORK *netw, int type, int id_from, int id_to, int time)
Add a ping reply to the network.
Definition: n_network.c:3070
NETWORK_POOL * netw_new_pool(int nb_min_element)
return a new network pool of nb_min_element
Definition: n_network.c:2847
#define NETWORK_CONSECUTIVE_SEND_TIMEOUT
Flag to set consecutive send waiting timeout
Definition: n_network.h:35
int netw_connect(NETWORK **netw, char *host, char *port, int ip_version)
Use this to connect a NETWORK to any listening one, unrestricted send/recv lists.
Definition: n_network.c:1361
#define NETWORK_DEPLETE_TIMEOUT
Flag to set send buffer depletion timeout
Definition: n_network.h:33
int netw_send_ident(NETWORK *netw, int type, int id, N_STR *name, N_STR *passwd)
Add a formatted NETWMSG_IDENT message to the specified network.
Definition: n_network.c:3092
int netw_pool_add(NETWORK_POOL *netw_pool, NETWORK *netw)
add a NETWORK *netw to a NETWORK_POOL *pool
Definition: n_network.c:2907
int netw_get_state(NETWORK *netw, int *state, int *thr_engine_status)
Get the state of a network.
Definition: n_network.c:1376
int send_data(SOCKET s, char *buf, NSTRBYTE n)
send data onto the socket
Definition: n_network.c:2489
int recv_php(SOCKET s, int *_code, char **buf)
recv data from the socket
Definition: n_network.c:2695
int netw_send_position(NETWORK *netw, int id, double X, double Y, double vx, double vy, double acc_x, double acc_y, int time_stamp)
Add a formatted NETWMSG_IDENT message to the specified network.
Definition: n_network.c:3119
int netw_pool_remove(NETWORK_POOL *netw_pool, NETWORK *netw)
remove a NETWORK *netw to a NETWORK_POOL *pool
Definition: n_network.c:2960
int netw_add_msg_ex(NETWORK *netw, char *str, unsigned int length)
Add a message to send in aimed NETWORK.
Definition: n_network.c:2001
int netw_wait_close_timed(NETWORK **netw, size_t timeout)
Wait for peer closing a specified Network, destroy queues, free the structure.
Definition: n_network.c:1589
#define SOCKET
socket macro shortcut
Definition: n_network.h:54
Structure of a NETWORK.
Definition: n_network.h:252
structure of a network pool
Definition: n_network.h:341
Hash functions and table.
Generic log system.
int deplete_send_buffer(int fd, size_t timeout)
wait until the socket is empty or timeout, checking each 100 msec.
Definition: n_network.c:1541
void netw_sigchld_handler(int sig)
signal handler to reap zombies when forking
Definition: n_network.c:581
N_ENUM_netw_code_type
network erro code
Definition: n_network.c:21
NETWORK * netw_new(int send_list_limit, int recv_list_limit)
Return an empty allocated network ready to be netw_closed.
Definition: n_network.c:598
#define netstrerror(code)
BSD style errno string NO WORKING ON REDHAT.
Definition: n_network.c:565
#define neterrno
Keep it compatible with bsd like.
Definition: n_network.c:550
char * get_in_addr(struct sockaddr *sa)
get sockaddr, IPv4 or IPv6
Definition: n_network.c:704
Network Engine.
Network messages , serialization tools.