Nilorea Library
C utilities for networking, threading, graphics
All Data Structures Files Functions Variables Typedefs Enumerations Macros Modules Pages
n_network.c
Go to the documentation of this file.
1
9#include <errno.h>
10#include <limits.h>
11#include <pthread.h>
12#include <unistd.h>
13#include <string.h>
14#include <ctype.h>
15#include <sys/types.h>
16
17#include "nilorea/n_network.h"
19#include "nilorea/n_log.h"
20#include "nilorea/n_hash.h"
21
24
25
30size_t htonst(size_t value) {
31#if __BYTE_ORDER == __LITTLE_ENDIAN
32 if (sizeof(size_t) == 4) {
33 return (size_t)htonl((uint32_t)value);
34 } else if (sizeof(size_t) == 8) {
35 return ((size_t)htonl((uint32_t)(value >> 32)) |
36 ((size_t)htonl((uint32_t)value) << 32));
37 }
38#endif
39 return value; // No conversion needed for big-endian
40}
41
47size_t ntohst(size_t value) {
48#if __BYTE_ORDER == __LITTLE_ENDIAN
49 if (sizeof(size_t) == 4) {
50 return (size_t)ntohl((uint32_t)value);
51 } else if (sizeof(size_t) == 8) {
52 return ((size_t)ntohl((uint32_t)(value >> 32)) |
53 ((size_t)ntohl((uint32_t)value) << 32));
54 }
55#endif
56 return value; // No conversion needed for big-endian
57}
58
59#ifdef __windows__
60
66char* wchar_to_char(const wchar_t* pwchar) {
67 // get the number of characters in the string.
68 int currentCharIndex = 0;
69 char currentChar = pwchar[currentCharIndex];
70 char* filePathC = NULL;
71
72 while (currentChar != '\0') {
73 currentCharIndex++;
74 currentChar = pwchar[currentCharIndex];
75 }
76
77 const int charCount = currentCharIndex + 1;
78
79 // allocate a new block of memory size char (1 byte) instead of wide char (2 bytes)
80 Malloc(filePathC, char, charCount);
81 __n_assert(filePathC, return NULL);
82
83 for (int i = 0; i < charCount; i++) {
84 // convert to char (1 byte)
85 char character = pwchar[i];
86
87 *filePathC = character;
88
89 filePathC += sizeof(char);
90 }
91 filePathC += '\0';
92
93 filePathC -= (sizeof(char) * charCount);
94
95 return filePathC;
96}
97
99#define neterrno WSAGetLastError()
100
102#define netstrerror(code) ({ \
103 wchar_t* s = NULL; \
104 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
105 NULL, code, \
106 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), \
107 (LPWSTR) & s, 0, NULL); \
108 char* netstr = wchar_to_char(s); \
109 LocalFree(s); \
110 netstr; \
111})
112
113#if __GNUC__ <= 6 && __GNUC_MINOR__ <= 3
114
115/*--------------------------------------------------------------------------------------
116 By Marco Ladino - mladinox.. jan/2016
117 MinGW 3.45 thru 4.5 versions, don't have the socket functions:
118 --> inet_ntop(..)
119 --> inet_pton(..)
120 But with this adapted code using the original functions from FreeBSD,
121 one can to use it in the C/C++ Applications, without problem..!
122 This implementation, include tests for IPV4 and IPV6 addresses,
123 and is full C/C++ compatible..
124 --------------------------------------------------------------------------------------*/
125/* OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp */
126/*-
127 * Copyright (c) 1998 Todd C. Miller <Todd.Miller at courtesan.com>
128 *
129 * Permission to use, copy, modify, and distribute this software for any
130 * purpose with or without fee is hereby granted, provided that the above
131 * copyright notice and this permission notice appear in all copies.
132 *
133 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
134 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
135 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
136 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
137 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
138 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
139 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
140 */
141
142/*
143 * Copy src to string dst of size siz. At most siz-1 characters
144 * will be copied. Always NUL terminates (unless siz == 0).
145 * Returns strlen(src); if retval >= siz, truncation occurred.
146 */
147size_t strlcpy(char* dst, const char* src, size_t siz) {
148 char* d = dst;
149 const char* s = src;
150 size_t n = siz;
151
152 /* Copy as many bytes as will fit */
153 if (n != 0) {
154 while (--n != 0) {
155 if ((*d++ = *s++) == '\0')
156 break;
157 }
158 }
159
160 /* Not enough room in dst, add NUL and traverse rest of src */
161 if (n == 0) {
162 if (siz != 0)
163 *d = '\0'; /* NUL-terminate dst */
164 while (*s++);
165 }
166
167 return (s - src - 1); /* count does not include NUL */
168}
169
170/*
171 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
172 * Copyright (c) 1996-1999 by Internet Software Consortium.
173 *
174 * Permission to use, copy, modify, and distribute this software for any
175 * purpose with or without fee is hereby granted, provided that the above
176 * copyright notice and this permission notice appear in all copies.
177 *
178 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
179 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
180 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
181 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
182 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
183 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
184 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
185 */
186
187/*
188 * WARNING: Don't even consider trying to compile this on a system where
189 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
190 */
191
192static char* inet_ntop4(const unsigned char* src, char* dst, socklen_t size);
193static char* inet_ntop6(const unsigned char* src, char* dst, socklen_t size);
194
195/* char *
196 * inet_ntop(af, src, dst, size)
197 * convert a network format address to presentation format.
198 * return:
199 * pointer to presentation format address (`dst'), or NULL (see errno).
200 * author:
201 * Paul Vixie, 1996.
202 */
203char* inet_ntop(int af, const void* src, char* dst, socklen_t size) {
204 switch (af) {
205 case AF_INET:
206 return (inet_ntop4((const unsigned char*)src, dst, size));
207 case AF_INET6:
208 return (inet_ntop6((const unsigned char*)src, dst, size));
209 default:
210 return (NULL);
211 }
212 /* NOTREACHED */
213}
214
215/* const char *
216 * inet_ntop4(src, dst, size)
217 * format an IPv4 address
218 * return:
219 * `dst' (as a const)
220 * notes:
221 * (1) uses no statics
222 * (2) takes a u_char* not an in_addr as input
223 * author:
224 * Paul Vixie, 1996.
225 */
226static char* inet_ntop4(const unsigned char* src, char* dst, socklen_t size) {
227 static const char fmt[] = "%u.%u.%u.%u";
228 char tmp[sizeof "255.255.255.255"];
229 int l;
230
231 l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
232 if (l <= 0 || (socklen_t)l >= size) {
233 return (NULL);
234 }
235 strlcpy(dst, tmp, size);
236 return (dst);
237}
238
239/* const char *
240 * inet_ntop6(src, dst, size)
241 * convert IPv6 binary address into presentation (printable) format
242 * author:
243 * Paul Vixie, 1996.
244 */
245static char* inet_ntop6(const unsigned char* src, char* dst, socklen_t size) {
246 /*
247 * Note that int32_t and int16_t need only be "at least" large enough
248 * to contain a value of the specified size. On some systems, like
249 * Crays, there is no such thing as an integer variable with 16 bits.
250 * Keep this in mind if you think this function should have been coded
251 * to use pointer overlays. All the world's not a VAX.
252 */
253 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
254 struct
255 {
256 int base, len;
257 } best, cur;
258#define NS_IN6ADDRSZ 16
259#define NS_INT16SZ 2
260 u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
261 int i;
262
263 /*
264 * Preprocess:
265 * Copy the input (bytewise) array into a wordwise array.
266 * Find the longest run of 0x00's in src[] for :: shorthanding.
267 */
268 memset(words, '\0', sizeof words);
269 for (i = 0; i < NS_IN6ADDRSZ; i++)
270 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
271 best.base = -1;
272 best.len = 0;
273 cur.base = -1;
274 cur.len = 0;
275 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
276 if (words[i] == 0) {
277 if (cur.base == -1)
278 cur.base = i, cur.len = 1;
279 else
280 cur.len++;
281 } else {
282 if (cur.base != -1) {
283 if (best.base == -1 || cur.len > best.len)
284 best = cur;
285 cur.base = -1;
286 }
287 }
288 }
289 if (cur.base != -1) {
290 if (best.base == -1 || cur.len > best.len)
291 best = cur;
292 }
293 if (best.base != -1 && best.len < 2)
294 best.base = -1;
295
296 /*
297 * Format the result.
298 */
299 tp = tmp;
300 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
301 /* Are we inside the best run of 0x00's? */
302 if (best.base != -1 && i >= best.base &&
303 i < (best.base + best.len)) {
304 if (i == best.base)
305 *tp++ = ':';
306 continue;
307 }
308 /* Are we following an initial run of 0x00s or any real hex? */
309 if (i != 0)
310 *tp++ = ':';
311 /* Is this address an encapsulated IPv4? */
312 if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 7 && words[7] != 0x0001) || (best.len == 5 && words[5] == 0xffff))) {
313 if (!inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
314 return (NULL);
315 tp += strlen(tp);
316 break;
317 }
318 tp += sprintf(tp, "%x", words[i]);
319 }
320 /* Was it a trailing run of 0x00's? */
321 if (best.base != -1 && (best.base + best.len) ==
322 (NS_IN6ADDRSZ / NS_INT16SZ))
323 *tp++ = ':';
324 *tp++ = '\0';
325
326 /*
327 * Check for overflow, copy, and we're done.
328 */
329 if ((socklen_t)(tp - tmp) > size) {
330 return (NULL);
331 }
332 strcpy(dst, tmp);
333 return (dst);
334}
335
336/*
337 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
338 * Copyright (c) 1996,1999 by Internet Software Consortium.
339 *
340 * Permission to use, copy, modify, and distribute this software for any
341 * purpose with or without fee is hereby granted, provided that the above
342 * copyright notice and this permission notice appear in all copies.
343 *
344 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
345 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
346 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
347 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
348 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
349 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
350 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
351 */
352
353/*
354 * WARNING: Don't even consider trying to compile this on a system where
355 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
356 */
357
358static int inet_pton4(const char* src, u_char* dst);
359static int inet_pton6(const char* src, u_char* dst);
360
361/* int
362 * inet_pton(af, src, dst)
363 * convert from presentation format (which usually means ASCII printable)
364 * to network format (which is usually some kind of binary format).
365 * return:
366 * 1 if the address was valid for the specified address family
367 * 0 if the address wasn't valid (`dst' is untouched in this case)
368 * -1 if some other error occurred (`dst' is untouched in this case, too)
369 * author:
370 * Paul Vixie, 1996.
371 */
372int inet_pton(int af, const char* src, void* dst) {
373 switch (af) {
374 case AF_INET:
375 return (inet_pton4(src, (unsigned char*)dst));
376 case AF_INET6:
377 return (inet_pton6(src, (unsigned char*)dst));
378 default:
379 return (-1);
380 }
381 /* NOTREACHED */
382}
383
384/* int
385 * inet_pton4(src, dst)
386 * like inet_aton() but without all the hexadecimal and shorthand.
387 * return:
388 * 1 if `src' is a valid dotted quad, else 0.
389 * notice:
390 * does not touch `dst' unless it's returning 1.
391 * author:
392 * Paul Vixie, 1996.
393 */
394static int inet_pton4(const char* src, u_char* dst) {
395 static const char digits[] = "0123456789";
396 int saw_digit, octets, ch;
397#define NS_INADDRSZ 4
398 u_char tmp[NS_INADDRSZ], *tp;
399
400 saw_digit = 0;
401 octets = 0;
402 *(tp = tmp) = 0;
403 while ((ch = *src++) != '\0') {
404 const char* pch;
405
406 if ((pch = strchr(digits, ch)) != NULL) {
407 u_int uiNew = *tp * 10 + (pch - digits);
408
409 if (saw_digit && *tp == 0)
410 return (0);
411 if (uiNew > 255)
412 return (0);
413 *tp = uiNew;
414 if (!saw_digit) {
415 if (++octets > 4)
416 return (0);
417 saw_digit = 1;
418 }
419 } else if (ch == '.' && saw_digit) {
420 if (octets == 4)
421 return (0);
422 *++tp = 0;
423 saw_digit = 0;
424 } else
425 return (0);
426 }
427 if (octets < 4)
428 return (0);
429 memcpy(dst, tmp, NS_INADDRSZ);
430 return (1);
431}
432
433/* int
434 * inet_pton6(src, dst)
435 * convert presentation level address to network order binary form.
436 * return:
437 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
438 * notice:
439 * (1) does not touch `dst' unless it's returning 1.
440 * (2) :: in a full address is silently ignored.
441 * credit:
442 * inspired by Mark Andrews.
443 * author:
444 * Paul Vixie, 1996.
445 */
446static int inet_pton6(const char* src, u_char* dst) {
447 static const char xdigits_l[] = "0123456789abcdef",
448 xdigits_u[] = "0123456789ABCDEF";
449#define NS_IN6ADDRSZ 16
450#define NS_INT16SZ 2
451 u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
452 const char* curtok;
453 int ch, seen_xdigits;
454 u_int val;
455
456 memset((tp = tmp), '\0', NS_IN6ADDRSZ);
457 endp = tp + NS_IN6ADDRSZ;
458 colonp = NULL;
459 /* Leading :: requires some special handling. */
460 if (*src == ':')
461 if (*++src != ':')
462 return (0);
463 curtok = src;
464 seen_xdigits = 0;
465 val = 0;
466 while ((ch = *src++) != '\0') {
467 const char* xdigits : 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 val <<= 4;
473 val |= (pch - xdigits);
474 if (++seen_xdigits > 4)
475 return (0);
476 continue;
477 }
478 if (ch == ':') {
479 curtok = src;
480 if (!seen_xdigits) {
481 if (colonp)
482 return (0);
483 colonp = tp;
484 continue;
485 } else if (*src == '\0') {
486 return (0);
487 }
488 if (tp + NS_INT16SZ > endp)
489 return (0);
490 *tp++ = (u_char)(val >> 8) & 0xff;
491 *tp++ = (u_char)val & 0xff;
492 seen_xdigits = 0;
493 val = 0;
494 continue;
495 }
496 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
497 inet_pton4(curtok, tp) > 0) {
498 tp += NS_INADDRSZ;
499 seen_xdigits = 0;
500 break; /* '\\0' was seen by inet_pton4(). */
501 }
502 return (0);
503 }
504 if (seen_xdigits) {
505 if (tp + NS_INT16SZ > endp)
506 return (0);
507 *tp++ = (u_char)(val >> 8) & 0xff;
508 *tp++ = (u_char)val & 0xff;
509 }
510 if (colonp != NULL) {
511 /*
512 * Since some memmove()'s erroneously fail to handle
513 * overlapping regions, we'll do the shift by hand.
514 */
515 const int n = tp - colonp;
516 int i;
517
518 if (tp == endp)
519 return (0);
520 for (i = 1; i <= n; i++) {
521 endp[-i] = colonp[n - i];
522 colonp[n - i] = 0;
523 }
524 tp = endp;
525 }
526 if (tp != endp)
527 return (0);
528 memcpy(dst, tmp, NS_IN6ADDRSZ);
529 return (1);
530}
531
532#endif /* if GCC_VERSION <= 4.5 */
533
534#else /* not __windows__ */
535
536#include <sys/types.h>
537#include <sys/wait.h>
538
540#define neterrno errno
541
543/* #define netstrerror( code )({ \
544 size_t errmsglen = 512 ; // strerrorlen_s( code ) + 1 ; \
545 char *errmsg = NULL ; \
546 Malloc( errmsg , char , errmsglen ); \
547 if( errmsg ) \
548 { \
549 strerror_s( errmsg , errmsglen , code ); \
550 } \
551 errmsg ; \
552 }) */
553
555#define netstrerror(code) ({ \
556 char* __errmsg = NULL; \
557 errno = 0; \
558 __errmsg = strdup(strerror(code)); \
559 if (errno == ENOMEM) { \
560 __errmsg = NULL; \
561 } \
562 __errmsg; \
563})
564
565#endif /* if not def windows */
566
573NETWORK* netw_new(size_t send_list_limit, size_t recv_list_limit) {
574 NETWORK* netw = NULL;
575
576 Malloc(netw, NETWORK, 1);
577 __n_assert(netw, return NULL);
578
579 /* netw itself */
580 netw->nb_pending = -1;
581 netw->mode = -1;
582 netw->user_id = -1;
583 netw->nb_running_threads = 0;
584 netw->state = NETW_EXITED;
585 netw->threaded_engine_status = NETW_THR_ENGINE_STOPPED;
586
587 /* netw -> link */
588 netw->link.sock = -1;
589 netw->link.port =
590 netw->link.ip = NULL;
591 memset(&netw->link.hints, 0, sizeof(struct addrinfo));
592 memset(&netw->link.raddr, 0, sizeof(struct sockaddr_storage));
593
594 /*initiliaze mutexs*/
595 if (pthread_mutex_init(&netw->sendbolt, NULL) != 0) {
596 n_log(LOG_ERR, "Error initializing netw -> sendbolt");
597 Free(netw);
598 return NULL;
599 }
600 /*initiliaze mutexs*/
601 if (pthread_mutex_init(&netw->recvbolt, NULL) != 0) {
602 n_log(LOG_ERR, "Error initializing netw -> recvbolt");
603 pthread_mutex_destroy(&netw->sendbolt);
604 Free(netw);
605 return NULL;
606 }
607 /*initiliaze mutexs*/
608 if (pthread_mutex_init(&netw->eventbolt, NULL) != 0) {
609 n_log(LOG_ERR, "Error initializing netw -> eventbolt");
610 pthread_mutex_destroy(&netw->sendbolt);
611 pthread_mutex_destroy(&netw->recvbolt);
612 Free(netw);
613 return NULL;
614 }
615 /* initialize send sem bolt */
616 if (sem_init(&netw->send_blocker, 0, 0) != 0) {
617 n_log(LOG_ERR, "Error initializing netw -> eventbolt");
618 pthread_mutex_destroy(&netw->eventbolt);
619 pthread_mutex_destroy(&netw->sendbolt);
620 pthread_mutex_destroy(&netw->recvbolt);
621 Free(netw);
622 return NULL;
623 }
624 /*initialize queues */
625 netw->recv_buf = new_generic_list(recv_list_limit);
626 if (!netw->recv_buf) {
627 n_log(LOG_ERR, "Error when creating receive list with %d item limit", recv_list_limit);
628 netw_close(&netw);
629 return NULL;
630 }
631 netw->send_buf = new_generic_list(send_list_limit);
632 if (!netw->send_buf) {
633 n_log(LOG_ERR, "Error when creating send list with %d item limit", send_list_limit);
634 netw_close(&netw);
635 return NULL;
636 }
637 netw->pools = new_generic_list(MAX_LIST_ITEMS);
638 if (!netw->pools) {
639 n_log(LOG_ERR, "Error when creating pools list");
640 netw_close(&netw);
641 return NULL;
642 }
643 netw->addr_infos_loaded = 0;
645 netw->so_reuseaddr = -1;
646 // netw -> so_reuseport = -1 ;
647 netw->so_keepalive = -1;
648 netw->tcpnodelay = -1;
649 netw->so_sndbuf = -1;
650 netw->so_rcvbuf = -1;
651 netw->so_rcvtimeo = -1;
652 netw->so_sndtimeo = -1;
653 netw->so_linger = -1;
654 netw->deplete_socket_timeout = -1;
655 netw->deplete_queues_timeout = -1;
656 netw->wait_close_timeout = -1;
657 netw->crypto_algo = NETW_ENCRYPT_NONE;
658
659 netw->send_data = &send_data;
660 netw->recv_data = &recv_data;
661
662#ifdef HAVE_OPENSSL
663 netw->method = NULL;
664 netw->ctx = NULL;
665 netw->ssl = NULL;
666 netw->key = NULL;
667 netw->certificate = NULL;
668#endif
669
670 netw->link.is_blocking = 0;
671 return netw;
672
673} /* netw_new() */
674
680char* get_in_addr(struct sockaddr* sa) {
681 return sa->sa_family == AF_INET
682 ? (char*)&(((struct sockaddr_in*)sa)->sin_addr)
683 : (char*)&(((struct sockaddr_in6*)sa)->sin6_addr);
684}
685
693int netw_init_wsa(int mode, int v1, int v2) {
694 int compiler_warning_suppressor = 0;
695#if !defined(__linux__) && !defined(__sun) && !defined(_AIX)
696 static WSADATA WSAdata; /*WSA world*/
697 static int WSA_IS_INITIALIZED = 0; /*status checking*/
698
699 switch (mode) {
700 default:
701 /*returning WSA status*/
702 case 2:
703 return WSA_IS_INITIALIZED;
704 break;
705 /*loading WSA dll*/
706 case 1:
707 if (WSA_IS_INITIALIZED == 1)
708 return TRUE; /*already loaded*/
709 if ((WSAStartup(MAKEWORD(v1, v2), &WSAdata)) != 0) {
710 WSA_IS_INITIALIZED = 0;
711 return FALSE;
712 } else {
713 WSA_IS_INITIALIZED = 1;
714 return TRUE;
715 }
716 break;
717 /*unloading (closing) WSA */
718 case 0:
719 if (WSA_IS_INITIALIZED == 0)
720 return TRUE; /*already CLEANED or not loaded */
721 if (WSACleanup() == 0) {
722 WSA_IS_INITIALIZED = 0;
723 return TRUE;
724 }
725 break;
726 } /*switch(...)*/
727#endif /* ifndef __linux__ __sun _AIX */
728 compiler_warning_suppressor = mode + v1 + v2;
729 compiler_warning_suppressor = TRUE;
730 return compiler_warning_suppressor;
731} /*netw_init_wsa(...)*/
732
739int netw_set_blocking(NETWORK* netw, unsigned long int is_blocking) {
740 __n_assert(netw, return FALSE);
741
742 int error = 0;
743 char* errmsg = NULL;
744
745#if defined(__linux__) || defined(__sun)
746 int flags = 0;
747 flags = fcntl(netw->link.sock, F_GETFL, 0);
748 if (netw->link.is_blocking != 0 && !is_blocking) {
749 if ((flags & O_NONBLOCK) && !is_blocking) {
750 n_log(LOG_DEBUG, "socket %d was already in non-blocking mode", netw->link.sock);
751 /* in case we missed it, let's update the link mode */
752 netw->link.is_blocking = 0;
753 return TRUE;
754 }
755 } else if (netw->link.is_blocking != 1 && is_blocking) {
756 if (!(flags & O_NONBLOCK) && is_blocking) {
757 n_log(LOG_DEBUG, "socket %d was already in blocking mode", netw->link.sock);
758 /* in case we missed it, let's update the link mode */
759 netw->link.is_blocking = 1;
760 return TRUE;
761 }
762 }
763 if (fcntl(netw->link.sock, F_SETFL, is_blocking ? flags ^ O_NONBLOCK : flags | O_NONBLOCK) == -1) {
764 error = neterrno;
765 errmsg = netstrerror(error);
766 n_log(LOG_ERR, "couldn't set blocking mode %d on %d: %s", is_blocking, netw->link.sock, _str(errmsg));
767 FreeNoLog(errmsg);
768 return FALSE;
769 }
770#else
771 unsigned long int blocking = 1 - is_blocking;
772 int res = ioctlsocket(netw->link.sock, FIONBIO, &blocking);
773 error = neterrno;
774 if (res != NO_ERROR) {
775 errmsg = netstrerror(error);
776 n_log(LOG_ERR, "ioctlsocket failed with error: %ld , neterrno: %s", res, _str(errmsg));
777 FreeNoLog(errmsg);
778 netw_close(&netw);
779 return FALSE;
780 }
781#endif
782 netw->link.is_blocking = is_blocking;
783 return TRUE;
784} /* netw_set_blocking */
785
794int netw_setsockopt(NETWORK* netw, int optname, int value) {
795 __n_assert(netw, return FALSE);
796
797 int error = 0;
798 char* errmsg = NULL;
799
800 switch (optname) {
801 case TCP_NODELAY:
802 if (value >= 0) {
803 /* disable naggle algorithm */
804 if (setsockopt(netw->link.sock, IPPROTO_TCP, TCP_NODELAY, (const char*)&value, sizeof(value)) == -1) {
805 error = neterrno;
806 errmsg = netstrerror(error);
807 n_log(LOG_ERR, "Error from setsockopt(TCP_NODELAY) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
808 FreeNoLog(errmsg);
809 return FALSE;
810 }
811 }
812 netw->tcpnodelay = value;
813 break;
814 case SO_SNDBUF:
815 /* socket sending buffer size */
816 if (value >= 0) {
817 if (setsockopt(netw->link.sock, SOL_SOCKET, SO_SNDBUF, (const char*)&value, sizeof(value)) == -1) {
818 error = neterrno;
819 errmsg = netstrerror(error);
820 n_log(LOG_ERR, "Error from setsockopt(SO_SNDBUF) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
821 return FALSE;
822 }
823 }
824 netw->so_sndbuf = value;
825 break;
826 case SO_RCVBUF:
827 /* socket receiving buffer */
828 if (value >= 0) {
829 if (setsockopt(netw->link.sock, SOL_SOCKET, SO_RCVBUF, (const char*)&value, sizeof(value)) == -1) {
830 error = neterrno;
831 errmsg = netstrerror(error);
832 n_log(LOG_ERR, "Error from setsockopt(SO_RCVBUF) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
833 FreeNoLog(errmsg);
834 return FALSE;
835 }
836 }
837 netw->so_rcvbuf = value;
838 break;
839 case SO_REUSEADDR:
840 /* lose the pesky "Address already in use" error message*/
841 if (setsockopt(netw->link.sock, SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(value)) == -1) {
842 error = neterrno;
843 errmsg = netstrerror(error);
844 n_log(LOG_ERR, "Error from setsockopt(SO_REUSEADDR) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
845 FreeNoLog(errmsg);
846 return FALSE;
847 }
848 netw->so_reuseaddr = value;
849 break;
850 /*case SO_REUSEPORT :
851 // lose the pesky "port already in use" error message
852 if ( setsockopt( netw -> link . sock, SOL_SOCKET, SO_REUSEPORT, (char *)&value, sizeof( value ) ) == -1 )
853 {
854 error=neterrno ;
855 errmsg = netstrerror( error );
856 n_log( LOG_ERR, "Error from setsockopt(SO_REUSEPORT) on socket %d. neterrno: %s", netw -> link . sock, _str( errmsg ) );
857 FreeNoLog( errmsg );
858 return FALSE ;
859 }
860 netw -> so_reuseport = value ;
861 break ;*/
862 case SO_LINGER: {
863 struct linger ling;
864 if (value < 0) {
865 ling.l_onoff = 0;
866 ling.l_linger = 0;
867 } else if (value == 0) {
868 ling.l_onoff = 1;
869 ling.l_linger = 0;
870 } else {
871 ling.l_onoff = 1;
872 ling.l_linger = value;
873 }
874#ifndef __windows__
875 if (setsockopt(netw->link.sock, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)) == -1) {
876 error = neterrno;
877 errmsg = netstrerror(error);
878 n_log(LOG_ERR, "Error from setsockopt(SO_LINGER) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
879 FreeNoLog(errmsg);
880 return FALSE;
881 }
882#else
883 if (setsockopt(netw->link.sock, SOL_SOCKET, SO_LINGER, (const char*)&ling, sizeof(ling)) == -1) {
884 error = neterrno;
885 errmsg = netstrerror(error);
886 n_log(LOG_ERR, "Error from setsockopt(SO_LINGER) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
887 FreeNoLog(errmsg);
888 return FALSE;
889 }
890#endif // __windows__
891 netw->so_linger = value;
892 } break;
893 case SO_RCVTIMEO:
894 if (value >= 0) {
895#ifndef __windows__
896 {
897 struct timeval tv;
898 tv.tv_sec = value;
899 tv.tv_usec = 0;
900 if (setsockopt(netw->link.sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv) == -1) {
901 error = neterrno;
902 errmsg = netstrerror(error);
903 n_log(LOG_ERR, "Error from setsockopt(SO_RCVTIMEO) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
904 FreeNoLog(errmsg);
905 return FALSE;
906 }
907 }
908#else
909 if (setsockopt(netw->link.sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&value, sizeof value) == -1) {
910 error = neterrno;
911 errmsg = netstrerror(error);
912 n_log(LOG_ERR, "Error from setsockopt(SO_RCVTIMEO) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
913 FreeNoLog(errmsg);
914 return FALSE;
915 }
916#endif
917 }
918 netw->so_rcvtimeo = value;
919 break;
920 case SO_SNDTIMEO:
921 if (value >= 0) {
922#ifndef __windows__
923 {
924 struct timeval tv;
925 tv.tv_sec = value;
926 tv.tv_usec = 0;
927
928 if (setsockopt(netw->link.sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof tv) == -1) {
929 error = neterrno;
930 errmsg = netstrerror(error);
931 n_log(LOG_ERR, "Error from setsockopt(SO_SNDTIMEO) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
932 FreeNoLog(errmsg);
933 return FALSE;
934 }
935 }
936#else
937 if (setsockopt(netw->link.sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&value, sizeof value) == -1) {
938 error = neterrno;
939 errmsg = netstrerror(error);
940 n_log(LOG_ERR, "Error from setsockopt(SO_SNDTIMEO) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
941 FreeNoLog(errmsg);
942 return FALSE;
943 }
944#endif
945 }
946 netw->so_sndtimeo = value;
947 break;
949 netw->deplete_socket_timeout = value;
950 break;
952 netw->deplete_queues_timeout = value;
953 break;
955 netw->wait_close_timeout = value;
956 break;
958 netw->send_queue_consecutive_wait = value;
959 break;
960#ifdef __linux__
961 case TCP_USER_TIMEOUT:
962 if (value >= 0) {
963 if (setsockopt(netw->link.sock, IPPROTO_TCP, TCP_USER_TIMEOUT, (const char*)&value, sizeof value) == -1) {
964 error = neterrno;
965 errmsg = netstrerror(error);
966 n_log(LOG_ERR, "Error from setsockopt(TCP_USER_TIMEOUT) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
967 FreeNoLog(errmsg);
968 return FALSE;
969 }
970 }
971 break;
972 case TCP_QUICKACK:
973 if (setsockopt(netw->link.sock, IPPROTO_TCP, TCP_QUICKACK, &value, sizeof(value)) < 0) {
974 error = neterrno;
975 errmsg = netstrerror(error);
976 n_log(LOG_ERR, "Error setting setsockopt(TCP_QUICKACK) to %d on sock %d. neterrno: %s", value, netw->link.sock, _str(errmsg));
977 FreeNoLog(errmsg);
978 return FALSE;
979 }
980 break;
981#endif
982 case SO_KEEPALIVE:
983 if (setsockopt(netw->link.sock, SOL_SOCKET, SO_KEEPALIVE, (const char*)&value, sizeof value) == -1) {
984 error = neterrno;
985 errmsg = netstrerror(error);
986 n_log(LOG_ERR, "Error from setsockopt(SO_KEEPALIVE) on socket %d. neterrno: %s", netw->link.sock, _str(errmsg));
987 FreeNoLog(errmsg);
988 return FALSE;
989 }
990 netw->so_keepalive = value;
991 break;
992
993 default:
994 n_log(LOG_ERR, "%d is not a supported setsockopt", optname);
995 return FALSE;
996 }
997 return TRUE;
998} /* netw_set_sock_opt */
999
1000#ifdef HAVE_OPENSSL
1001
1002char* netw_get_openssl_error_string() {
1003 BIO* bio = BIO_new(BIO_s_mem());
1004 if (!bio) {
1005 return NULL;
1006 }
1007
1008 ERR_print_errors(bio); // Write errors to the BIO
1009
1010 char* buf;
1011 size_t len = (size_t)BIO_get_mem_data(bio, &buf); // Get data from the BIO. Can return 0 if empty of failled
1012
1013 // Allocate memory for the error string and copy it
1014 char* error_str = malloc(len + 1);
1015 if (error_str) {
1016 memcpy(error_str, buf, len);
1017 error_str[len] = '\0'; // Null-terminate the string
1018 }
1019
1020 BIO_free(bio); // Free the BIO
1021
1022 return error_str;
1023}
1024
1025void netw_ssl_print_errors(SOCKET socket) {
1026 unsigned long error = 0;
1027 while ((error = ERR_get_error())) {
1028 n_log(LOG_ERR, "socket %d: %s", socket, ERR_reason_error_string(error));
1029 }
1030}
1031
1032/***************************************************************************
1033 * _ _ ____ _
1034 * Project ___| | | | _ \| |
1035 * / __| | | | |_) | |
1036 * | (__| |_| | _ <| |___
1037 * \___|\___/|_| \_\_____|
1038 *
1039 * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel at haxx.se>, et al.
1040 *
1041 * This software is licensed as described in the file COPYING, which
1042 * you should have received as part of this distribution. The terms
1043 * are also available at https://curl.haxx.se/docs/copyright.html.
1044 *
1045 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1046 * copies of the Software, and permit persons to whom the Software is
1047 * furnished to do so, under the terms of the COPYING file.
1048 *
1049 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1050 * KIND, either express or implied.
1051 *
1052 ***************************************************************************/
1053/* <DESC>
1054 * Show the required mutex callback setups for GnuTLS and OpenSSL when using
1055 * libcurl multi-threaded.
1056 * </DESC>
1057 */
1058/* A multi-threaded example that uses pthreads and fetches 4 remote files at
1059 * once over HTTPS. The lock callbacks and stuff assume OpenSSL <1.1 or GnuTLS
1060 * (libgcrypt) so far.
1061 *
1062 * OpenSSL docs for this:
1063 * https://www.openssl.org/docs/man1.0.2/man3/CRYPTO_num_locks.html
1064 * gcrypt docs for this:
1065 * https://gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html
1066 */
1067
1068/* we have this global to let the callback get easy access to it */
1069static pthread_mutex_t* netw_ssl_lockarray;
1070
1071__attribute__((unused)) static void netw_ssl_lock_callback(int mode, int type, char* file, int line) {
1072 (void)file;
1073 (void)line;
1074 if (mode & CRYPTO_LOCK) {
1075 pthread_mutex_lock(&(netw_ssl_lockarray[type]));
1076 } else {
1077 pthread_mutex_unlock(&(netw_ssl_lockarray[type]));
1078 }
1079}
1080
1081__attribute__((unused)) static unsigned long thread_id(void) {
1082 unsigned long ret;
1083
1084 ret = (unsigned long)pthread_self();
1085 return ret;
1086}
1087
1088static void netw_init_locks(void) {
1089 int i;
1090
1091 size_t lock_count = (size_t)CRYPTO_num_locks();
1092 netw_ssl_lockarray = (pthread_mutex_t*)OPENSSL_malloc((size_t)(lock_count * sizeof(pthread_mutex_t)));
1093
1094 for (i = 0; i < CRYPTO_num_locks(); i++) {
1095 pthread_mutex_init(&(netw_ssl_lockarray[i]), NULL);
1096 }
1097
1098 CRYPTO_set_id_callback((unsigned long (*)())thread_id);
1099 CRYPTO_set_locking_callback((void (*)())netw_ssl_lock_callback);
1100}
1101
1102static void netw_kill_locks(void) {
1103 int i;
1104
1105 CRYPTO_set_locking_callback(NULL);
1106 for (i = 0; i < CRYPTO_num_locks(); i++)
1107 pthread_mutex_destroy(&(netw_ssl_lockarray[i]));
1108
1109 OPENSSL_free(netw_ssl_lockarray);
1110}
1111
1117 static int OPENSSL_IS_INITIALIZED = 0; /*status checking*/
1118
1119 if (OPENSSL_IS_INITIALIZED == 1)
1120 return TRUE; /*already loaded*/
1121
1122 SSL_library_init();
1123 SSL_load_error_strings();
1124 // Before OpenSSL 1.1.0 (< 0x10100000L): ERR_load_BIO_strings(); was required to load error messages for BIO functions
1125#if OPENSSL_VERSION_NUMBER < 0x10100000L
1126 ERR_load_BIO_strings();
1127#endif
1128 OpenSSL_add_all_algorithms();
1129 netw_init_locks();
1130
1131 OPENSSL_IS_INITIALIZED = 1;
1132
1133 return TRUE;
1134} /*netw_init_openssl(...)*/
1135
1141 static int OPENSSL_IS_INITIALIZED = 0; /*status checking*/
1142
1143 if (OPENSSL_IS_INITIALIZED == 0)
1144 return TRUE; /*already unloaded*/
1145
1146 netw_kill_locks();
1147 EVP_cleanup();
1148
1149 OPENSSL_IS_INITIALIZED = 0;
1150
1151 return TRUE;
1152} /*netw_unload_openssl(...)*/
1153
1160int netw_set_crypto(NETWORK* netw, char* key, char* certificate) {
1161 __n_assert(netw, return FALSE);
1162
1163 if (key && strlen(key) > 0) {
1164 netw->key = strdup(key);
1165 }
1166 if (certificate && strlen(certificate) > 0) {
1167 netw->certificate = strdup(certificate);
1168 }
1169 if (key && certificate) {
1171#if OPENSSL_VERSION_NUMBER >= 0x10100000L // OpenSSL 1.1.0 or later
1172 netw->method = TLS_method(); // create new server-method instance
1173#else
1174 netw->method = TLSv1_2_method(); // create new server-method instance
1175#endif
1176 netw->ctx = SSL_CTX_new(netw->method); // create new context from method
1177 // SSL_CTX_set_verify(netw -> ctx, SSL_VERIFY_PEER, NULL); // Enable certificate verification
1178
1179 if (netw->ctx == NULL) {
1180 netw_ssl_print_errors(netw->link.sock);
1181 return FALSE;
1182 }
1183
1184 // Load default system certs
1185 if (SSL_CTX_load_verify_locations(netw->ctx, NULL, "/etc/ssl/certs/") != 1) {
1186 netw_ssl_print_errors(netw->link.sock);
1187 return FALSE;
1188 }
1189
1190 if (SSL_CTX_use_certificate_file(netw->ctx, certificate, SSL_FILETYPE_PEM) <= 0) {
1191 netw_ssl_print_errors(netw->link.sock);
1192 return FALSE;
1193 }
1194 if (SSL_CTX_use_PrivateKey_file(netw->ctx, key, SSL_FILETYPE_PEM) <= 0) {
1195 netw_ssl_print_errors(netw->link.sock);
1196 return FALSE;
1197 }
1198
1199 netw->send_data = &send_ssl_data;
1200 netw->recv_data = &recv_ssl_data;
1201
1202 netw->crypto_algo = NETW_ENCRYPT_OPENSSL;
1203 }
1204
1205 return TRUE;
1206} /* netw_set_crypto */
1207
1208#endif // HAVE_OPENSSL WIP
1209
1222int netw_connect_ex(NETWORK** netw, char* host, char* port, size_t send_list_limit, size_t recv_list_limit, int ip_version, char* ssl_key_file, char* ssl_cert_file) {
1223 // kill compilation warning when there is no openssl
1224 (void)ssl_key_file;
1225 (void)ssl_cert_file;
1226 int error = 0, net_status = 0;
1227 char* errmsg = NULL;
1228
1229 /*do not work over an already used netw*/
1230 if ((*netw)) {
1231 n_log(LOG_ERR, "Unable to allocate (*netw), already existing. You must use empty NETWORK *structs.");
1232 return FALSE;
1233 }
1234
1235 /*creating array*/
1236 (*netw) = netw_new(send_list_limit, recv_list_limit);
1237 __n_assert(netw && (*netw), return FALSE);
1238
1239 /*checking WSA when under windows*/
1240 if (netw_init_wsa(1, 2, 2) == FALSE) {
1241 n_log(LOG_ERR, "Unable to load WSA dll's");
1242 Free((*netw));
1243 return FALSE;
1244 }
1245
1246 /* choose ip version */
1247 if (ip_version == NETWORK_IPV4) {
1248 (*netw)->link.hints.ai_family = AF_INET; /* Allow IPv4 */
1249 } else if (ip_version == NETWORK_IPV6) {
1250 (*netw)->link.hints.ai_family = AF_INET6; /* Allow IPv6 */
1251 } else {
1252 /* NETWORK_ALL or unknown value */
1253 (*netw)->link.hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
1254 }
1255
1256 (*netw)->link.hints.ai_socktype = SOCK_STREAM;
1257 (*netw)->link.hints.ai_protocol = IPPROTO_TCP;
1258 (*netw)->link.hints.ai_flags = AI_PASSIVE;
1259 (*netw)->link.hints.ai_canonname = NULL;
1260 (*netw)->link.hints.ai_next = NULL;
1261
1262 /* Note: on some system, i.e Solaris, it WILL show leak in getaddrinfo.
1263 * Testing it inside a 1,100 loop showed not effect on the amount of leaked
1264 * memory */
1265 error = getaddrinfo(host, port, &(*netw)->link.hints, &(*netw)->link.rhost);
1266 if (error != 0) {
1267 n_log(LOG_ERR, "Error when resolving %s:%s getaddrinfo: %s", host, port, gai_strerror(error));
1268 netw_close(&(*netw));
1269 return FALSE;
1270 }
1271 (*netw)->addr_infos_loaded = 1;
1272 Malloc((*netw)->link.ip, char, 64);
1273 __n_assert((*netw)->link.ip, netw_close(&(*netw)); return FALSE);
1274
1275 /* 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. */
1276 struct addrinfo* rp = NULL;
1277 for (rp = (*netw)->link.rhost; rp != NULL; rp = rp->ai_next) {
1278 int sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
1279 if (sock == -1) {
1280 error = neterrno;
1281 errmsg = netstrerror(error);
1282 n_log(LOG_ERR, "Error while trying to make a socket: %s", _str(errmsg));
1283 FreeNoLog(errmsg);
1284 continue;
1285 }
1286
1287 (*netw)->link.sock = sock;
1288
1289 net_status = connect(sock, rp->ai_addr, rp->ai_addrlen);
1290 if (net_status == -1) {
1291 error = neterrno;
1292 errmsg = netstrerror(error);
1293 n_log(LOG_INFO, "connecting to %s:%s : %s", host, port, _str(errmsg));
1294 FreeNoLog(errmsg);
1295 closesocket(sock);
1296 (*netw)->link.sock = -1;
1297 continue;
1298 } else {
1299 /*storing connected port and ip address*/
1300 if (!inet_ntop(rp->ai_family, get_in_addr(rp->ai_addr), (*netw)->link.ip, 64)) {
1301 error = neterrno;
1302 errmsg = netstrerror(error);
1303 n_log(LOG_ERR, "inet_ntop: %p , %s", rp, _str(errmsg));
1304 FreeNoLog(errmsg);
1305 }
1306 break; /* Success */
1307 }
1308 }
1309 if (rp == NULL) {
1310 /* No address succeeded */
1311 n_log(LOG_ERR, "Couldn't connect to %s:%s : no address succeeded", host, port);
1312 netw_close(&(*netw));
1313 return FALSE;
1314 }
1315
1316 (*netw)->link.port = strdup(port);
1317 __n_assert((*netw)->link.port, netw_close(&(*netw)); return FALSE);
1318
1319 if (ssl_key_file && ssl_cert_file) {
1320#ifdef HAVE_OPENSSL
1321 if (netw_set_crypto((*netw), ssl_key_file, ssl_cert_file) == FALSE) {
1322 /* could not initialize SSL */
1323 n_log(LOG_ERR, "couldn't initialize SSL !");
1324 netw_close(&(*netw));
1325 return FALSE;
1326 }
1327
1328 (*netw)->ssl = SSL_new((*netw)->ctx);
1329 SSL_set_fd((*netw)->ssl, (*netw)->link.sock);
1330
1331 // Perform SSL Handshake
1332 if (SSL_connect((*netw)->ssl) <= 0) {
1333 /* could not connect with SSL */
1334 n_log(LOG_ERR, "SSL Handshake error !");
1335 netw_close(&(*netw));
1336 return FALSE;
1337 }
1338 n_log(LOG_DEBUG, "SSL-Connected to %s:%s", (*netw)->link.ip, (*netw)->link.port);
1339#else
1340 n_log(LOG_ERR, "%s:%s trying to configure SSL but application was compiled without SSL support !", (*netw)->link.ip, (*netw)->link.port);
1341#endif
1342 } else {
1343 n_log(LOG_DEBUG, "Connected to %s:%s", (*netw)->link.ip, (*netw)->link.port);
1344 }
1345
1346 netw_set((*netw), NETW_CLIENT | NETW_RUN | NETW_THR_ENGINE_STOPPED);
1347
1348 return TRUE;
1349} /* netw_connect_ex(...)*/
1350
1359int netw_connect(NETWORK** netw, char* host, char* port, int ip_version) {
1360 n_log(LOG_INFO, "Trying to connect to %s : %s", _str(host), _str(port));
1361 return netw_connect_ex(&(*netw), host, port, MAX_LIST_ITEMS, MAX_LIST_ITEMS, ip_version, NULL, NULL);
1362} /* netw_connect() */
1363
1364#ifdef HAVE_OPENSSL
1375int netw_ssl_connect(NETWORK** netw, char* host, char* port, int ip_version, char* ssl_key_file, char* ssl_cert_file) {
1376 n_log(LOG_INFO, "Trying to connect to %s : %s", _str(host), _str(port));
1377 return netw_connect_ex(&(*netw), host, port, MAX_LIST_ITEMS, MAX_LIST_ITEMS, ip_version, ssl_key_file, ssl_cert_file);
1378} /* netw_connect() */
1379#endif
1380
1388int netw_get_state(NETWORK* netw, uint32_t* state, int* thr_engine_status) {
1389 if (netw) {
1390 pthread_mutex_lock(&netw->sendbolt);
1391 if (state)
1392 (*state) = netw->state;
1393 if (thr_engine_status)
1394 (*thr_engine_status) = netw->threaded_engine_status;
1395 pthread_mutex_unlock(&netw->sendbolt);
1396 return TRUE;
1397 } else {
1398 n_log(LOG_ERR, "Can't get status of a NULL network");
1399 }
1400 return FALSE;
1401} /*netw_get_state() */
1402
1409int netw_set(NETWORK* netw, int flag) {
1410 if (flag & NETW_EMPTY_SENDBUF) {
1411 pthread_mutex_lock(&netw->sendbolt);
1412 if (netw->send_buf)
1413 list_empty(netw->send_buf);
1414 pthread_mutex_unlock(&netw->sendbolt);
1415 };
1416 if (flag & NETW_EMPTY_RECVBUF) {
1417 pthread_mutex_lock(&netw->recvbolt);
1418 if (netw->recv_buf)
1419 list_empty(netw->recv_buf);
1420 pthread_mutex_unlock(&netw->recvbolt);
1421 }
1422 if (flag & NETW_DESTROY_SENDBUF) {
1423 pthread_mutex_lock(&netw->sendbolt);
1424 if (netw->send_buf)
1425 list_destroy(&netw->send_buf);
1426 pthread_mutex_unlock(&netw->sendbolt);
1427 };
1428 if (flag & NETW_DESTROY_RECVBUF) {
1429 pthread_mutex_lock(&netw->recvbolt);
1430 if (netw->recv_buf)
1431 list_destroy(&netw->recv_buf);
1432 pthread_mutex_unlock(&netw->recvbolt);
1433 }
1434 pthread_mutex_lock(&netw->eventbolt);
1435 if (flag & NETW_CLIENT) {
1436 netw->mode = NETW_CLIENT;
1437 }
1438 if (flag & NETW_SERVER) {
1439 netw->mode = NETW_SERVER;
1440 }
1441 if (flag & NETW_RUN) {
1442 netw->state = NETW_RUN;
1443 }
1444 if (flag & NETW_EXITED) {
1445 netw->state = NETW_EXITED;
1446 }
1447 if (flag & NETW_ERROR) {
1448 netw->state = NETW_ERROR;
1449 }
1450 if (flag & NETW_EXIT_ASKED) {
1451 netw->state = NETW_EXIT_ASKED;
1452 }
1453 if (flag & NETW_THR_ENGINE_STARTED) {
1454 netw->threaded_engine_status = NETW_THR_ENGINE_STARTED;
1455 }
1456 if (flag & NETW_THR_ENGINE_STOPPED) {
1457 netw->threaded_engine_status = NETW_THR_ENGINE_STOPPED;
1458 }
1459 pthread_mutex_unlock(&netw->eventbolt);
1460
1461 sem_post(&netw->send_blocker);
1462
1463 return TRUE;
1464} /* netw_set(...) */
1465
1472int deplete_send_buffer(int fd, int timeout) {
1473#if defined(__linux__)
1474 int outstanding = 0;
1475 if (timeout <= 0) {
1476 return 0;
1477 }
1478 for (int it = 0; it < timeout; it += 100) {
1479 outstanding = 0;
1480 if (ioctl(fd, SIOCOUTQ, &outstanding) == -1) {
1481 int error = errno;
1482 n_log(LOG_ERR, "ioctl SIOCOUTQ returned -1: %s for socket %d", strerror(error), fd);
1483 return -1;
1484 }
1485 if (!outstanding) {
1486 break;
1487 }
1488 usleep(100000);
1489 }
1490 return outstanding;
1491#else
1492 (void)fd;
1493 (void)timeout;
1494 return 0;
1495#endif
1496}
1497
1503int netw_close(NETWORK** netw) {
1504 __n_assert(netw && (*netw), return FALSE);
1505 uint32_t state = 0;
1506 int thr_engine_status = 0;
1507 int countdown = 0;
1508 int nb_running = 0;
1509
1510 if ((*netw)->deplete_queues_timeout > 0) {
1511 countdown = (*netw)->deplete_queues_timeout * 1000000;
1512 netw_get_state((*netw), &state, &thr_engine_status);
1513 if (thr_engine_status == NETW_THR_ENGINE_STARTED) {
1514 do {
1515 pthread_mutex_lock(&(*netw)->eventbolt);
1516 nb_running = (*netw)->nb_running_threads;
1517 pthread_mutex_unlock(&(*netw)->eventbolt);
1518 usleep(100000);
1519 if (countdown < 100000)
1520 countdown = 0;
1521 else
1522 countdown -= 100000;
1523 } while (nb_running > 0 && countdown > 0);
1524 netw_get_state((*netw), &state, &thr_engine_status);
1525 if (countdown == 0 && nb_running > 0) {
1526 n_log(LOG_ERR, "netw %d: %d threads are still running after %d seconds, netw is in state %s (%" PRIu32 ")", (*netw)->link.sock, nb_running, (*netw)->deplete_queues_timeout, N_ENUM_ENTRY(__netw_code_type, toString)(state), state);
1527 }
1528 }
1529 }
1530
1531 if ((*netw)->link.sock != INVALID_SOCKET) {
1532 int remaining = deplete_send_buffer((*netw)->link.sock, (*netw)->deplete_socket_timeout);
1533 if (remaining > 0) {
1534 n_log(LOG_ERR, "socket %d (%s:%s) %d octets still in send buffer before closing after a wait of %d msecs", (*netw)->link.sock, (*netw)->link.ip, (*netw)->link.port, remaining, (*netw)->deplete_socket_timeout);
1535 }
1536 }
1537
1538 list_foreach(node, (*netw)->pools) {
1539 NETWORK_POOL* pool = (NETWORK_POOL*)node->ptr;
1540 netw_pool_remove(pool, (*netw));
1541 }
1542 list_destroy(&(*netw)->pools);
1543
1544 netw_get_state((*netw), &state, &thr_engine_status);
1545 if (thr_engine_status == NETW_THR_ENGINE_STARTED) {
1546 netw_stop_thr_engine((*netw));
1547 }
1548
1549 if ((*netw)->link.sock != INVALID_SOCKET) {
1550#ifdef HAVE_OPENSSL
1551 if ((*netw)->crypto_algo == NETW_ENCRYPT_OPENSSL) {
1552 if ((*netw)->ssl) {
1553 int shutdown_res = SSL_shutdown((*netw)->ssl);
1554 if (shutdown_res == 0) {
1555 // Try again to complete bidirectional shutdown
1556 shutdown_res = SSL_shutdown((*netw)->ssl);
1557 }
1558 if (shutdown_res < 0) {
1559 int err = SSL_get_error((*netw)->ssl, shutdown_res);
1560 n_log(LOG_ERR, "SSL_shutdown() failed: %d", err);
1561 }
1562 SSL_shutdown((*netw)->ssl);
1563 SSL_free((*netw)->ssl);
1564 } else {
1565 n_log(LOG_ERR, "SSL handle of socket %d was already NULL", (*netw)->link.sock);
1566 }
1567 }
1568#endif
1569
1570 /* inform peer that we have finished */
1571 shutdown((*netw)->link.sock, SHUT_WR);
1572
1573 if ((*netw)->wait_close_timeout > 0) {
1574 /* wait for fin ack */
1575 char buffer[4096] = "";
1576 /* default wait 30s for fin ack */
1577 for (int it = 0; it < ((*netw)->wait_close_timeout * 1000000); it += 100000) {
1578 ssize_t res = recv((*netw)->link.sock, buffer, 4096, NETFLAGS);
1579 if (!res)
1580 break;
1581 if (res < 0) {
1582 int error = neterrno;
1583 if (error != ENOTCONN && error != 10057 && error != EINTR && error != ECONNRESET) // no an error if already closed
1584 {
1585 char* errmsg = netstrerror(error);
1586 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));
1587 FreeNoLog(errmsg);
1588 } else {
1589 n_log(LOG_DEBUG, "wait close: connection gracefully closed on socket %d (%s:%s)", (*netw)->link.sock, _str((*netw)->link.ip), (*netw)->link.port);
1590 }
1591 break;
1592 }
1593 usleep(100000);
1594 }
1595 }
1596
1597 /* effectively close socket */
1598 closesocket((*netw)->link.sock);
1599
1600#ifdef HAVE_OPENSSL
1601 /* clean openssl state */
1602 if ((*netw)->crypto_algo == NETW_ENCRYPT_OPENSSL) {
1603 if ((*netw)->ctx) {
1604 SSL_CTX_free((*netw)->ctx);
1605 } else {
1606 n_log(LOG_ERR, "SSL context of socket %d was already NULL", (*netw)->link.sock);
1607 }
1608 }
1609 n_log(LOG_DEBUG, "socket %d closed", (*netw)->link.sock);
1610 FreeNoLog((*netw)->key);
1611 FreeNoLog((*netw)->certificate);
1612#endif
1613 }
1614
1615 FreeNoLog((*netw)->link.ip);
1616 FreeNoLog((*netw)->link.port);
1617
1618 if ((*netw)->link.rhost) {
1619 freeaddrinfo((*netw)->link.rhost);
1620 }
1621
1622 /*list freeing*/
1623 netw_set((*netw), NETW_DESTROY_SENDBUF | NETW_DESTROY_RECVBUF);
1624
1625 pthread_mutex_destroy(&(*netw)->recvbolt);
1626 pthread_mutex_destroy(&(*netw)->sendbolt);
1627 pthread_mutex_destroy(&(*netw)->eventbolt);
1628 sem_destroy(&(*netw)->send_blocker);
1629
1630 Free((*netw));
1631
1632 return TRUE;
1633} /* netw_close(...)*/
1634
1644int netw_make_listening(NETWORK** netw, char* addr, char* port, int nbpending, int ip_version) {
1645 __n_assert(port, return FALSE);
1646
1647 int error = 0;
1648 char* errmsg = NULL;
1649
1650 if (*netw) {
1651 n_log(LOG_ERR, "Cannot use an allocated network. Please pass a NULL network to modify");
1652 return FALSE;
1653 }
1654
1655 /*checking WSA when under windows*/
1656 if (netw_init_wsa(1, 2, 2) == FALSE) {
1657 n_log(LOG_ERR, "Unable to load WSA dll's");
1658 return FALSE;
1659 }
1660
1662 (*netw)->link.port = strdup(port);
1663 /*creating array*/
1664 if (ip_version == NETWORK_IPV4) {
1665 (*netw)->link.hints.ai_family = AF_INET; /* Allow IPv4 */
1666 } else if (ip_version == NETWORK_IPV6) {
1667 (*netw)->link.hints.ai_family = AF_INET6; /* Allow IPv6 */
1668 } else {
1669 /* NETWORK_ALL or unknown value */
1670 (*netw)->link.hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
1671 }
1672 if (!addr) {
1673 (*netw)->link.hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
1674 }
1675 (*netw)->link.hints.ai_socktype = SOCK_STREAM;
1676 (*netw)->link.hints.ai_protocol = IPPROTO_TCP;
1677 (*netw)->link.hints.ai_canonname = NULL;
1678 (*netw)->link.hints.ai_next = NULL;
1679
1680 error = getaddrinfo(addr, port, &(*netw)->link.hints, &(*netw)->link.rhost);
1681 if (error != 0) {
1682 n_log(LOG_ERR, "Error when resolving %s:%s getaddrinfo: %s", _str(addr), port, gai_strerror(error));
1683 netw_close(&(*netw));
1684 return FALSE;
1685 }
1686 (*netw)->addr_infos_loaded = 1;
1687
1688 /* getaddrinfo() returns a list of address structures.
1689 Try each address until we successfully connect(2).
1690 If socket(2) (or connect(2)) fails, we (close the socket
1691 and) try the next address. */
1692 struct addrinfo* rp = NULL;
1693 for (rp = (*netw)->link.rhost; rp != NULL; rp = rp->ai_next) {
1694 (*netw)->link.sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
1695 if ((*netw)->link.sock == INVALID_SOCKET) {
1696 error = neterrno;
1697 errmsg = netstrerror(error);
1698 n_log(LOG_ERR, "Error while trying to make a socket: %s", _str(errmsg));
1699 FreeNoLog(errmsg);
1700 continue;
1701 }
1702 netw_setsockopt((*netw), SO_REUSEADDR, 1);
1703 // netw_setsockopt( (*netw), SO_REUSEPORT, 1 );
1704 if (bind((*netw)->link.sock, rp->ai_addr, rp->ai_addrlen) == 0) {
1705 char* ip = NULL;
1706 Malloc(ip, char, 64);
1707 if (!ip) {
1708 n_log(LOG_ERR, "Error allocating 64 bytes for ip");
1709 netw_close(&(*netw));
1710 return FALSE;
1711 }
1712 if (!inet_ntop(rp->ai_family, get_in_addr(rp->ai_addr), ip, 64)) {
1713 error = neterrno;
1714 errmsg = netstrerror(error);
1715 n_log(LOG_ERR, "inet_ntop: %p , %s", (*netw)->link.raddr, _str(errmsg));
1716 FreeNoLog(errmsg);
1717 }
1718 /*n_log( LOG_DEBUG, "Socket %d successfully binded to %s %s", (*netw) -> link . sock, _str( ip ) , _str( port ) );*/
1719 (*netw)->link.ip = ip;
1720 break; /* Success */
1721 }
1722 error = neterrno;
1723 errmsg = netstrerror(error);
1724 n_log(LOG_ERR, "Error from bind() on port %s neterrno: %s", port, errmsg);
1725 FreeNoLog(errmsg);
1726 closesocket((*netw)->link.sock);
1727 }
1728 if (rp == NULL) {
1729 /* No address succeeded */
1730 n_log(LOG_ERR, "Couldn't get a socket for listening on port %s", port);
1731 netw_close(&(*netw));
1732 return FALSE;
1733 }
1734
1735 /* nb_pending connections*/
1736 (*netw)->nb_pending = nbpending;
1737 listen((*netw)->link.sock, (*netw)->nb_pending);
1738
1739 netw_set((*netw), NETW_SERVER | NETW_RUN | NETW_THR_ENGINE_STOPPED);
1740
1741 return TRUE;
1742} /* netw_make_listening(...)*/
1743
1753NETWORK* netw_accept_from_ex(NETWORK* from, size_t send_list_limit, size_t recv_list_limit, int blocking, int* retval) {
1754 int tmp = 0, error = 0;
1755 char* errmsg = NULL;
1756
1757#if defined(__linux__) || defined(__sun) || defined(_AIX)
1758 socklen_t sin_size = 0;
1759#else
1760 int sin_size = 0;
1761#endif
1762
1763 NETWORK* netw = NULL;
1764
1765 /*checking WSA when under windows*/
1766 if (netw_init_wsa(1, 2, 2) == FALSE) {
1767 n_log(LOG_ERR, "Unable to load WSA dll's");
1768 return NULL;
1769 }
1770
1771 __n_assert(from, return NULL);
1772
1773 netw = netw_new(send_list_limit, recv_list_limit);
1774
1775 sin_size = sizeof(netw->link.raddr);
1776
1777 if (blocking > 0) {
1778 int secs = blocking / 1000;
1779 int usecs = (blocking % 1000) * 1000;
1780 struct timeval select_timeout = {secs, usecs};
1781
1782 fd_set accept_set;
1783 FD_SET(from->link.sock, &accept_set);
1784 FD_ZERO(&accept_set);
1785
1786 int ret = select(from->link.sock + 1, &accept_set, NULL, NULL, &select_timeout);
1787 if (ret == -1) {
1788 error = neterrno;
1789 errmsg = netstrerror(error);
1790 if (retval != NULL)
1791 (*retval) = error;
1792 n_log(LOG_DEBUG, "error on select with timeout %ds (%d.%ds), neterrno: %s", blocking, secs, usecs, _str(errmsg));
1793 FreeNoLog(errmsg);
1794 netw_close(&netw);
1795 return NULL;
1796 } else if (ret == 0) {
1797 /* that one produce waaaay too much logs under a lot of cases */
1798 n_log(LOG_DEBUG, "No connection waiting on %d", from->link.sock);
1799 netw_close(&netw);
1800 return NULL;
1801 }
1802 if (FD_ISSET(from->link.sock, &accept_set)) {
1803 // n_log( LOG_DEBUG, "select accept call on %d", from -> link . sock );
1804 tmp = accept(from->link.sock, (struct sockaddr*)&netw->link.raddr, &sin_size);
1805 if (tmp < 0) {
1806 error = neterrno;
1807 errmsg = netstrerror(error);
1808 if (retval != NULL)
1809 (*retval) = error;
1810 n_log(LOG_DEBUG, "error accepting on %d, %s", netw->link.sock, _str(errmsg));
1811 FreeNoLog(errmsg);
1812 netw_close(&netw);
1813 return NULL;
1814 }
1815 } else {
1816 n_log(LOG_ERR, "FD_ISSET returned false on %d", from->link.sock);
1817 netw_close(&netw);
1818 return NULL;
1819 }
1820 netw->link.is_blocking = 0;
1821 } else if (blocking == -1) {
1822 if (from->link.is_blocking != 0) {
1823 netw_set_blocking(from, 0);
1824 }
1825 tmp = accept(from->link.sock, (struct sockaddr*)&netw->link.raddr, &sin_size);
1826 error = neterrno;
1827 if (retval != NULL)
1828 (*retval) = error;
1829 if (tmp < 0) {
1830 n_log(LOG_ERR, "accept returned an invalid socket (-1)");
1831 netw_close(&netw);
1832 return NULL;
1833 }
1834 netw->link.is_blocking = 0;
1835 } else {
1836 if (from->link.is_blocking == 0) {
1837 netw_set_blocking(from, 1);
1838 n_log(LOG_DEBUG, "(default) blocking accept call on socket %d", from->link.sock);
1839 }
1840 tmp = accept(from->link.sock, (struct sockaddr*)&netw->link.raddr, &sin_size);
1841 if (tmp < 0) {
1842 error = neterrno;
1843 errmsg = netstrerror(error);
1844 if (retval != NULL)
1845 (*retval) = error;
1846 n_log(LOG_DEBUG, "error accepting on socket %d, %s", netw->link.sock, _str(errmsg));
1847 FreeNoLog(errmsg);
1848 netw_close(&netw);
1849 return NULL;
1850 }
1851 netw->link.is_blocking = 1;
1852 }
1853 netw->link.sock = tmp;
1854 netw->link.port = strdup(from->link.port);
1855 Malloc(netw->link.ip, char, 64);
1856 if (!netw->link.ip) {
1857 n_log(LOG_ERR, "Error allocating 64 bytes for ip");
1858 netw_close(&netw);
1859 return FALSE;
1860 }
1861 if (!inet_ntop(netw->link.raddr.ss_family, get_in_addr(((struct sockaddr*)&netw->link.raddr)), netw->link.ip, 64)) {
1862 error = neterrno;
1863 errmsg = netstrerror(error);
1864 n_log(LOG_ERR, "inet_ntop: %p , %s", netw->link.raddr, _str(errmsg));
1865 FreeNoLog(errmsg);
1866 netw_close(&netw);
1867 return FALSE;
1868 }
1869
1870 netw_setsockopt(netw, SO_REUSEADDR, 1);
1871 // netw_setsockopt( netw, SO_REUSEPORT, 1 );
1872 netw_setsockopt(netw, SO_KEEPALIVE, 1);
1873 netw_set(netw, NETW_SERVER | NETW_RUN | NETW_THR_ENGINE_STOPPED);
1874 // netw_set_blocking(netw, 1);
1875
1876 n_log(LOG_DEBUG, "Connection accepted from %s:%s socket %d", netw->link.ip, netw->link.port, netw->link.sock);
1877
1878#ifdef HAVE_OPENSSL
1879 if (from->crypto_algo == NETW_ENCRYPT_OPENSSL) {
1880 netw->ssl = SSL_new(from->ctx);
1881 SSL_set_fd(netw->ssl, netw->link.sock);
1882
1883 netw->send_data = &send_ssl_data;
1884 netw->recv_data = &recv_ssl_data;
1885
1886 if (SSL_accept(netw->ssl) <= 0) {
1887 error = errno;
1888 n_log(LOG_ERR, "SSL error on %d", netw->link.sock);
1889 if (retval != NULL)
1890 (*retval) = error;
1891 netw_ssl_print_errors(netw->link.sock);
1892 netw_close(&netw);
1893 return FALSE;
1894 } else {
1895 n_log(LOG_DEBUG, " socket %d: SSL connection established", netw->link.sock);
1896 }
1897 }
1898#endif
1899
1900 return netw;
1901} /* netw_accept_from_ex(...) */
1902
1909 return netw_accept_from_ex(from, MAX_LIST_ITEMS, MAX_LIST_ITEMS, 0, NULL);
1910} /* network_accept_from( ... ) */
1911
1919 return netw_accept_from_ex(from, MAX_LIST_ITEMS, MAX_LIST_ITEMS, blocking, NULL);
1920} /* network_accept_from( ... ) */
1921
1928int netw_add_msg(NETWORK* netw, N_STR* msg) {
1929 __n_assert(netw, return FALSE);
1930 __n_assert(msg, return FALSE);
1931 __n_assert(msg->data, return FALSE);
1932
1933 if (msg->length <= 0) {
1934 n_log(LOG_ERR, "Empty messages are not supported. msg(%p)->lenght=%d", msg, msg->length);
1935 return FALSE;
1936 }
1937
1938 pthread_mutex_lock(&netw->sendbolt);
1939
1940 if (list_push(netw->send_buf, msg, free_nstr_ptr) == FALSE) {
1941 pthread_mutex_unlock(&netw->sendbolt);
1942 return FALSE;
1943 }
1944
1945 pthread_mutex_unlock(&netw->sendbolt);
1946
1947 sem_post(&netw->send_blocker);
1948
1949 return TRUE;
1950} /* netw_add_msg(...) */
1951
1959int netw_add_msg_ex(NETWORK* netw, char* str, unsigned int length) {
1960 __n_assert(netw, return FALSE);
1961 __n_assert(str, return FALSE);
1962 if (length == 0) {
1963 return FALSE;
1964 }
1965
1966 N_STR* nstr = NULL;
1967 Malloc(nstr, N_STR, 1);
1968 __n_assert(nstr, return FALSE);
1969
1970 if (length == 0) {
1971 n_log(LOG_ERR, "Empty messages are not supported. msg(%p)->lenght=%d", str, length);
1972 return FALSE;
1973 }
1974
1975 nstr->data = str;
1976 nstr->written = nstr->length = length;
1977
1978 pthread_mutex_lock(&netw->sendbolt);
1979 if (list_push(netw->send_buf, nstr, free_nstr_ptr) == FALSE) {
1980 pthread_mutex_unlock(&netw->sendbolt);
1981 return FALSE;
1982 }
1983 pthread_mutex_unlock(&netw->sendbolt);
1984
1985 sem_post(&netw->send_blocker);
1986
1987 return TRUE;
1988} /* netw_add_msg_ex(...) */
1989
1996 N_STR* ptr = NULL;
1997
1998 __n_assert(netw, return NULL);
1999
2000 pthread_mutex_lock(&netw->recvbolt);
2001
2002 ptr = list_shift(netw->recv_buf, N_STR);
2003
2004 pthread_mutex_unlock(&netw->recvbolt);
2005
2006 return ptr;
2007} /* netw_get_msg(...)*/
2008
2016N_STR* netw_wait_msg(NETWORK* netw, unsigned int refresh, size_t timeout) {
2017 N_STR* nstrptr = NULL;
2018 size_t timed = 0;
2019 unsigned int secs = 0;
2020 unsigned int usecs = 0;
2021
2022 __n_assert(netw, return NULL);
2023
2024 usecs = refresh;
2025 if (refresh > 999999) {
2026 secs = refresh / 1000000;
2027 usecs = refresh % 1000000;
2028 }
2029
2030 if (timeout > 0)
2031 timed = timeout;
2032
2033 n_log(LOG_DEBUG, "wait from socket %d, refresh: %zu usec (%zu secs, %zu usecs), timeout %zu usec", netw->link.sock, refresh, secs, usecs, timeout);
2034 uint32_t state = NETW_RUN;
2035 int thr_state = 0;
2036 do {
2037 nstrptr = netw_get_msg(netw);
2038 if (nstrptr)
2039 return nstrptr;
2040
2041 if (timeout > 0) {
2042 if (timed >= refresh)
2043 timed -= refresh;
2044 if (timed == 0 || timed < refresh) {
2045 n_log(LOG_ERR, "netw %d, status: %s (%" PRIu32 "), timeouted after waiting %zu msecs", netw->link.sock, N_ENUM_ENTRY(__netw_code_type, toString)(state), state, timeout);
2046 return NULL;
2047 }
2048 }
2049 if (secs > 0)
2050 sleep(secs);
2051 if (usecs > 0)
2052 u_sleep(usecs);
2053
2054 netw_get_state(netw, &state, &thr_state);
2055 } while (state != NETW_EXITED && state != NETW_ERROR);
2056
2057 n_log(LOG_ERR, "got no answer and netw %d is no more running, state: %s (%" PRIu32 ")", netw->link.sock, N_ENUM_ENTRY(__netw_code_type, toString)(state), state);
2058
2059 return NULL;
2060} /* netw_wait_msg(...) */
2061
2068 __n_assert(netw, return FALSE);
2069
2070 pthread_mutex_lock(&netw->eventbolt);
2071 if (netw->threaded_engine_status == NETW_THR_ENGINE_STARTED) {
2072 n_log(LOG_ERR, "THR Engine already started for network %p (%s)", netw, _str(netw->link.ip));
2073 pthread_mutex_unlock(&netw->eventbolt);
2074 return FALSE;
2075 }
2076
2077 if (pthread_create(&netw->recv_thr, NULL, netw_recv_func, (void*)netw) != 0) {
2078 n_log(LOG_ERR, "Unable to create recv_thread for network %p (%s)", netw, _str(netw->link.ip));
2079 pthread_mutex_unlock(&netw->eventbolt);
2080 return FALSE;
2081 }
2082 netw->nb_running_threads++;
2083 if (pthread_create(&netw->send_thr, NULL, netw_send_func, (void*)netw) != 0) {
2084 n_log(LOG_ERR, "Unable to create send_thread for network %p (%s)", netw, _str(netw->link.ip));
2085 pthread_mutex_unlock(&netw->eventbolt);
2086 return FALSE;
2087 }
2088 netw->nb_running_threads++;
2089
2090 netw->threaded_engine_status = NETW_THR_ENGINE_STARTED;
2091
2092 pthread_mutex_unlock(&netw->eventbolt);
2093
2094 return TRUE;
2095} /* netw_create_recv_thread(....) */
2096
2102void* netw_send_func(void* NET) {
2103 int DONE = 0;
2104
2105 ssize_t net_status = 0;
2106
2107 uint32_t state = 0,
2108 nboctet = 0;
2109
2110 char nboct[5] = "";
2111
2112 N_STR* ptr = NULL;
2113
2114 NETWORK* netw = (NETWORK*)NET;
2115 __n_assert(netw, return NULL);
2116
2117 do {
2118 /* do not consume cpu for nothing, reduce delay */
2119 sem_wait(&netw->send_blocker);
2120 int message_sent = 0;
2121 while (message_sent == 0 && !DONE) {
2122 netw_get_state(netw, &state, NULL);
2123 if (state & NETW_ERROR) {
2124 DONE = 666;
2125 } else if (state & NETW_EXITED) {
2126 DONE = 100;
2127 } else if (state & NETW_EXIT_ASKED) {
2128 DONE = 100;
2129 /* sending state */
2130 nboctet = htonl(NETW_EXIT_ASKED);
2131 memcpy(nboct, &nboctet, sizeof(uint32_t));
2132 n_log(LOG_DEBUG, "%d Sending Quit !", netw->link.sock);
2133 net_status = netw->send_data(netw, nboct, sizeof(int32_t));
2134 if (net_status < 0)
2135 DONE = 4;
2136 n_log(LOG_DEBUG, "%d Quit sent!", netw->link.sock);
2137 } else {
2138 pthread_mutex_lock(&netw->sendbolt);
2139 ptr = list_shift(netw->send_buf, N_STR);
2140 pthread_mutex_unlock(&netw->sendbolt);
2141 if (ptr && ptr->length > 0 && ptr->data) {
2142 if (ptr->written <= UINT_MAX) {
2143 n_log(LOG_DEBUG, "Sending ptr size %zu written %zu...", ptr->length, ptr->written);
2144
2145 /* sending state */
2146 nboctet = htonl(state);
2147 memcpy(nboct, &nboctet, sizeof(uint32_t));
2148 /* sending state */
2149 if (!DONE) {
2150 net_status = netw->send_data(netw, nboct, sizeof(int32_t));
2151 if (net_status < 0)
2152 DONE = 1;
2153 }
2154 if (!DONE) {
2155 /* sending number of octet */
2156 nboctet = htonl((uint32_t)ptr->written);
2157 memcpy(nboct, &nboctet, sizeof(uint32_t));
2158 /* sending the number of octet to receive on next message */
2159 net_status = netw->send_data(netw, nboct, sizeof(uint32_t));
2160 if (net_status < 0)
2161 DONE = 2;
2162 }
2163 /* sending the data itself */
2164 if (!DONE) {
2165 net_status = netw->send_data(netw, ptr->data, (uint32_t)ptr->written);
2166 if (net_status < 0)
2167 DONE = 3;
2168 }
2169 if (netw->send_queue_consecutive_wait >= 0) {
2170 u_sleep((unsigned int)netw->send_queue_consecutive_wait);
2171 }
2172 message_sent = 1;
2173 free_nstr(&ptr);
2174#ifdef __linux
2175 fsync(netw->link.sock);
2176#endif
2177 } else {
2178 n_log(LOG_ERR, "discarded packet of size %zu which is greater than %" PRIu32, ptr->written, UINT_MAX);
2179 message_sent = 1;
2180 free_nstr(&ptr);
2181 }
2182 }
2183 }
2184 }
2185 } while (!DONE);
2186
2187 if (DONE == 1)
2188 n_log(LOG_ERR, "Error when sending state %" PRIu32 " on socket %d (%s), network: %s", netw->state, netw->link.sock, _str(netw->link.ip), (net_status == NETW_SOCKET_DISCONNECTED) ? "disconnected" : "socket error");
2189 else if (DONE == 2)
2190 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 == NETW_SOCKET_DISCONNECTED) ? "disconnected" : "socket error");
2191 else if (DONE == 3)
2192 n_log(LOG_DEBUG, "Error when sending data on socket %d (%s), network: %s", netw->link.sock, _str(netw->link.ip), (net_status == NETW_SOCKET_DISCONNECTED) ? "disconnected" : "socket error");
2193 else if (DONE == 4)
2194 n_log(LOG_ERR, "Error when sending state QUIT on socket %d (%s), network: %s", netw->link.sock, _str(netw->link.ip), (net_status == NETW_SOCKET_DISCONNECTED) ? "disconnected" : "socket error");
2195 else if (DONE == 5)
2196 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 == NETW_SOCKET_DISCONNECTED) ? "disconnected" : "socket error");
2197
2198 if (DONE == 100) {
2199 n_log(LOG_DEBUG, "Socket %d: Sending thread exiting correctly", netw->link.sock);
2200 netw_set(netw, NETW_EXIT_ASKED);
2201 } else {
2202 n_log(LOG_ERR, "Socket %d (%s): Sending thread exiting with error %d !", netw->link.sock, _str(netw->link.ip), DONE);
2203 netw_set(netw, NETW_ERROR);
2204 }
2205
2206 pthread_mutex_lock(&netw->eventbolt);
2207 netw->nb_running_threads--;
2208 pthread_mutex_unlock(&netw->eventbolt);
2209
2210 pthread_exit(0);
2211
2212 /* suppress compiler warning */
2213#if !defined(__linux__)
2214 return NULL;
2215#endif
2216} /* netw_send_func(...) */
2217
2223void* netw_recv_func(void* NET) {
2224 int DONE = 0;
2225 ssize_t net_status = 0;
2226
2227 uint32_t nboctet = 0,
2228 tmpstate = 0,
2229 state = 0;
2230
2231 char nboct[5] = "";
2232
2233 N_STR* recvdmsg = NULL;
2234
2235 NETWORK* netw = (NETWORK*)NET;
2236
2237 __n_assert(netw, return NULL);
2238
2239 do {
2240 netw_get_state(netw, &state, NULL);
2241 if (state & NETW_EXIT_ASKED || state & NETW_EXITED) {
2242 DONE = 100;
2243 }
2244 if (state & NETW_ERROR) {
2245 DONE = 666;
2246 }
2247 if (!DONE) {
2248 n_log(LOG_DEBUG, "socket %d : waiting to receive status", netw->link.sock);
2249 /* receiving state */
2250 net_status = netw->recv_data(netw, nboct, sizeof(uint32_t));
2251 if (net_status < 0) {
2252 DONE = 1;
2253 } else {
2254 memcpy(&nboctet, nboct, sizeof(uint32_t));
2255 tmpstate = ntohl(nboctet);
2256 nboctet = tmpstate;
2257 if (tmpstate == NETW_EXIT_ASKED) {
2258 n_log(LOG_DEBUG, "socket %d : receiving order to QUIT !", netw->link.sock);
2259 DONE = 100;
2260 } else {
2261 n_log(LOG_DEBUG, "socket %d : waiting to receive next message nboctets", netw->link.sock);
2262 /* receiving nboctet */
2263 net_status = netw->recv_data(netw, nboct, sizeof(uint32_t));
2264 if (net_status < 0) {
2265 DONE = 2;
2266 } else {
2267 memcpy(&nboctet, nboct, sizeof(uint32_t));
2268 tmpstate = ntohl(nboctet);
2269 nboctet = tmpstate;
2270
2271 Malloc(recvdmsg, N_STR, 1);
2272 if (!recvdmsg) {
2273 DONE = 3;
2274 } else {
2275 n_log(LOG_DEBUG, "socket %d : %" PRIu32 " octets to receive...", netw->link.sock, nboctet);
2276 Malloc(recvdmsg->data, char, nboctet + 1);
2277 if (!recvdmsg->data) {
2278 DONE = 4;
2279 } else {
2280 recvdmsg->length = nboctet + 1;
2281 recvdmsg->written = nboctet;
2282
2283 /* receiving the data itself */
2284 net_status = netw->recv_data(netw, recvdmsg->data, nboctet);
2285 if (net_status < 0) {
2286 DONE = 5;
2287 } else {
2288 pthread_mutex_lock(&netw->recvbolt);
2289 if (list_push(netw->recv_buf, recvdmsg, free_nstr_ptr) == FALSE)
2290 DONE = 6;
2291 pthread_mutex_unlock(&netw->recvbolt);
2292 n_log(LOG_DEBUG, "socket %d : %" PRIu32 " octets received !", netw->link.sock, nboctet);
2293 } /* recv data */
2294 } /* recv data allocation */
2295 } /* recv struct allocation */
2296 } /* recv nb octet*/
2297 } /* exit asked */
2298 } /* recv state */
2299 } /* if( !done) */
2300 } while (!DONE);
2301
2302 if (DONE == 1)
2303 n_log(LOG_ERR, "Error when receiving state from socket %d (%s), net_status: %s", netw->link.sock, _str(netw->link.ip), (net_status == NETW_SOCKET_DISCONNECTED) ? "disconnected" : "socket error");
2304 else if (DONE == 2)
2305 n_log(LOG_ERR, "Error when receiving nboctet from socket %d (%s), net_status: %s", netw->link.sock, _str(netw->link.ip), (net_status == NETW_SOCKET_DISCONNECTED) ? "disconnected" : "socket error");
2306 else if (DONE == 3)
2307 n_log(LOG_ERR, "Error when receiving data from socket %d (%s), net_status: %s", netw->link.sock, _str(netw->link.ip), (net_status == NETW_SOCKET_DISCONNECTED) ? "disconnected" : "socket error");
2308 else if (DONE == 4)
2309 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 == NETW_SOCKET_DISCONNECTED) ? "disconnected" : "socket error");
2310 else if (DONE == 5)
2311 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 == NETW_SOCKET_DISCONNECTED) ? "disconnected" : "socket error");
2312 else if (DONE == 6)
2313 n_log(LOG_ERR, "Error adding receved message from socket %d (%s), net_status: %s", netw->link.sock, _str(netw->link.ip), (net_status == NETW_SOCKET_DISCONNECTED) ? "disconnected" : "socket error");
2314
2315 if (DONE == 100) {
2316 n_log(LOG_DEBUG, "Socket %d (%s): Receive thread exiting correctly", netw->link.sock, _str(netw->link.ip));
2317 netw_set(netw, NETW_EXIT_ASKED);
2318 } else {
2319 n_log(LOG_ERR, "Socket %d (%s): Receive thread exiting with code %d !", netw->link.sock, _str(netw->link.ip), DONE);
2320 netw_set(netw, NETW_ERROR);
2321 }
2322
2323 pthread_mutex_lock(&netw->eventbolt);
2324 netw->nb_running_threads--;
2325 pthread_mutex_unlock(&netw->eventbolt);
2326
2327 pthread_exit(0);
2328
2329 /* suppress compiler warning */
2330#if !defined(__linux__)
2331 return NULL;
2332#endif
2333} /* netw_recv_func(...) */
2334
2341 __n_assert(netw, return FALSE);
2342 uint32_t state = 0;
2343 int thr_engine_status = 0;
2344
2345 n_log(LOG_DEBUG, "Network %d stop threads event", netw->link.sock);
2346
2347 netw_get_state(netw, &state, &thr_engine_status);
2348
2349 if (thr_engine_status != NETW_THR_ENGINE_STARTED) {
2350 n_log(LOG_ERR, "Thread engine status already stopped for network %p", netw);
2351 return FALSE;
2352 }
2353
2354 netw_set(netw, NETW_EXIT_ASKED);
2355
2356 n_log(LOG_DEBUG, "Network %d waits for send threads to stop", netw->link.sock);
2357 for (int it = 0; it < 10; it++) {
2358 sem_post(&netw->send_blocker);
2359 usleep(1000);
2360 }
2361 pthread_join(netw->send_thr, NULL);
2362 n_log(LOG_DEBUG, "Network %d waits for recv threads to stop", netw->link.sock);
2363 pthread_join(netw->recv_thr, NULL);
2364
2365 netw_set(netw, NETW_EXITED | NETW_THR_ENGINE_STOPPED);
2366
2367 n_log(LOG_DEBUG, "Network %d threads Stopped !", netw->link.sock);
2368
2369 return TRUE;
2370} /* Stop_Network( ... ) */
2371
2379ssize_t send_data(void* netw, char* buf, uint32_t n) {
2380 __n_assert(netw, return NETW_SOCKET_ERROR);
2381 __n_assert(buf, return NETW_SOCKET_ERROR);
2382
2383 SOCKET s = ((NETWORK*)netw)->link.sock;
2384 ssize_t bcount = 0; /* counts bytes sent */
2385 int error = 0;
2386 char* errmsg = NULL;
2387
2388 if (n == 0) {
2389 n_log(LOG_ERR, "Send of 0 is unsupported.");
2390 return NETW_SOCKET_ERROR;
2391 }
2392
2393 char* tmp_buf = buf;
2394 while (bcount < n) // loop until all sent
2395 {
2396 ssize_t bs = 0; /* bytes sent this pass */
2397 // bs = send( s, tmp_buf, n - bcount, NETFLAGS );
2398 ssize_t retry_count = CALL_RETRY(bs, send(s, tmp_buf, (size_t)(n - bcount), NETFLAGS), NETW_MAX_RETRIES, 10);
2399 error = neterrno;
2400 if (retry_count == NETW_MAX_RETRIES) {
2401 n_log(LOG_ERR, "Maximum send retries (%d) reached for socket %d", NETW_MAX_RETRIES, s);
2402 return NETW_SOCKET_ERROR;
2403 }
2404 if (bs > 0) {
2405 bcount += bs; /* increment byte counter */
2406 tmp_buf += bs; /* move buffer ptr for next read */
2407 n_log(LOG_DEBUG, "socket %d sent %d/%d , retry %d/%d", s, bcount, n, retry_count, NETW_MAX_RETRIES);
2408 } else if (error == ECONNRESET || error == ENOTCONN) {
2409 n_log(LOG_DEBUG, "socket %d disconnected !", s);
2411 } else {
2412 /* signal an error to the caller */
2413 errmsg = netstrerror(error);
2414 n_log(LOG_ERR, "Socket %d send Error: %d , %s", s, bs, _str(errmsg));
2415 FreeNoLog(errmsg);
2416 return NETW_SOCKET_ERROR;
2417 }
2418 }
2419 send(s, NULL, 0, 0);
2420 return (int)bcount;
2421} /*send_data(...)*/
2422
2430ssize_t recv_data(void* netw, char* buf, uint32_t n) {
2431 __n_assert(netw, return NETW_SOCKET_ERROR);
2432 __n_assert(buf, return NETW_SOCKET_ERROR);
2433
2434 SOCKET s = ((NETWORK*)netw)->link.sock;
2435 ssize_t bcount = 0; /* counts bytes read */
2436 int error = 0;
2437 char* errmsg = NULL;
2438
2439 if (n == 0) {
2440 n_log(LOG_ERR, "Recv of 0 is unsupported.");
2441 return NETW_SOCKET_ERROR;
2442 }
2443
2444 char* tmp_buf = buf;
2445 while (bcount < n) // loop until all received
2446 {
2447 ssize_t br = 0; /* bytes read this pass */
2448 // br = recv( s, tmp_buf, n - bcount, NETFLAGS );
2449 ssize_t retry_count = CALL_RETRY(br, recv(s, tmp_buf, (size_t)(n - bcount), NETFLAGS), NETW_MAX_RETRIES, 10);
2450 error = neterrno;
2451 if (retry_count == NETW_MAX_RETRIES) {
2452 n_log(LOG_ERR, "Maximum recv retries (%d) reached for socket %d", NETW_MAX_RETRIES, s);
2453 return NETW_SOCKET_ERROR;
2454 }
2455 if (br > 0) {
2456 bcount += br; /* increment byte counter */
2457 tmp_buf += br; /* move buffer ptr for next read */
2458 n_log(LOG_DEBUG, "socket %d received %d/%d , retry %d/%d", s, bcount, n, retry_count, NETW_MAX_RETRIES);
2459 } else if (br == 0) {
2460 n_log(LOG_DEBUG, "socket %d disconnected !", s);
2462 } else {
2463 /* signal an error to the caller */
2464 errmsg = netstrerror(error);
2465 n_log(LOG_ERR, "socket %d recv returned %d, error: %s", s, br, _str(errmsg));
2466 FreeNoLog(errmsg);
2467 return NETW_SOCKET_ERROR;
2468 }
2469 }
2470 return (int)bcount;
2471} /*recv_data(...)*/
2472
2473#ifdef HAVE_OPENSSL
2481ssize_t send_ssl_data(void* netw, char* buf, uint32_t n) {
2482 __n_assert(netw, return -1);
2483 __n_assert(buf, return -1);
2484
2485 SSL* ssl = ((NETWORK*)netw)->ssl;
2486 __n_assert(ssl, return -1);
2487
2488 SOCKET s = ((NETWORK*)netw)->link.sock;
2489
2490 ssize_t bcount = 0; // counts bytes sent
2491 int error = 0;
2492 char* errmsg = NULL;
2493
2494 if (n == 0) {
2495 n_log(LOG_ERR, "Send of 0 is unsupported.");
2496 return -1;
2497 }
2498
2499 while (bcount < n) // loop until full buffer
2500 {
2501 size_t bs = 0; // bytes sent this pass
2502#if OPENSSL_VERSION_NUMBER < 0x1010107fL
2503 int status = SSL_write(ssl, buf, (int)(n - bcount)); // OpenSSL < 1.1.1
2504 bs = (status > 0) ? (size_t)status : 0;
2505#else
2506 int status = SSL_write_ex(ssl, buf, (size_t)(n - bcount), &bs); // OpenSSL >= 1.1.1
2507#endif
2508 error = neterrno;
2509 if (status > 0) {
2510 bcount += (ssize_t)bs; // increment byte counter
2511 buf += bs; // move buffer ptr for next read
2512 } else {
2513 int ssl_error = SSL_get_error(ssl, status);
2514 if (ssl_error == SSL_ERROR_WANT_READ || ssl_error == SSL_ERROR_WANT_WRITE) {
2515 usleep(0);
2516 continue;
2517 }
2518 errmsg = netstrerror(error);
2519 switch (ssl_error) {
2520 case SSL_ERROR_SYSCALL:
2521 // Handle syscall failure
2522 n_log(LOG_ERR, "socket %d SSL_read syscall error: connection closed by peer", s);
2523 break;
2524 case SSL_ERROR_SSL:
2525 // Handle SSL protocol failure
2526 n_log(LOG_ERR, "socket %d SSL_read returned %d, error: %s", s, bs, ERR_reason_error_string(ERR_get_error()));
2527 break;
2528 default:
2529 // Other errors
2530 n_log(LOG_ERR, "socket %d SSL_read returned %d, errno: %s", s, bs, _str(errmsg));
2531 break;
2532 }
2533 FreeNoLog(errmsg);
2534 return -1;
2535 }
2536 }
2537 return bcount;
2538} /*send_ssl_data(...)*/
2539
2547ssize_t recv_ssl_data(void* netw, char* buf, uint32_t n) {
2548 __n_assert(netw, return -1);
2549 __n_assert(buf, return -1);
2550
2551 SSL* ssl = ((NETWORK*)netw)->ssl;
2552 __n_assert(ssl, return -1);
2553
2554 SOCKET s = ((NETWORK*)netw)->link.sock;
2555 ssize_t bcount = 0; // counts bytes read
2556 int error = 0;
2557 char* errmsg = NULL;
2558
2559 if (n == 0) {
2560 n_log(LOG_ERR, "Recv of 0 is unsupported.");
2561 return -1;
2562 }
2563
2564 while (bcount < n) {
2565 size_t br = 0; // bytes read this pass
2566 // loop until full buffer
2567#if OPENSSL_VERSION_NUMBER < 0x10101000L
2568 int status = SSL_read(ssl, buf, (int)(n - bcount)); // OpenSSL < 1.1.1
2569 br = (status > 0) ? (size_t)status : 0;
2570#else
2571 int status = SSL_read_ex(ssl, buf, (size_t)(n - bcount), &br); // OpenSSL >= 1.1.1
2572#endif
2573 error = neterrno;
2574 if (status > 0) {
2575 bcount += (ssize_t)br; // increment byte counter
2576 buf += br; // move buffer ptr for next read
2577 } else {
2578 int ssl_error = SSL_get_error(ssl, status);
2579 if (ssl_error == SSL_ERROR_WANT_READ || ssl_error == SSL_ERROR_WANT_WRITE) {
2580 usleep(0);
2581 continue;
2582 }
2583 errmsg = netstrerror(error);
2584 switch (ssl_error) {
2585 case SSL_ERROR_SYSCALL:
2586 // Handle syscall failure
2587 n_log(LOG_ERR, "socket %d SSL_read syscall error: connection closed by peer", s);
2588 break;
2589 case SSL_ERROR_SSL:
2590 // Handle SSL protocol failure
2591 n_log(LOG_ERR, "socket %d SSL_read returned %d, error: %s", s, br, ERR_reason_error_string(ERR_get_error()));
2592 break;
2593 default:
2594 // Other errors
2595 n_log(LOG_ERR, "socket %d SSL_read returned %d, errno: %s", s, br, _str(errmsg));
2596 break;
2597 }
2598 FreeNoLog(errmsg);
2599 return -1;
2600 }
2601 }
2602 return bcount;
2603} /*recv_ssl_data(...)*/
2604#endif
2605
2614ssize_t send_php(SOCKET s, int _code, char* buf, int n) {
2615 ssize_t bcount = 0; /* counts bytes read */
2616 ssize_t bs = 0; /* bytes read this pass */
2617
2618 int error = 0;
2619 char* errmsg = NULL;
2620
2621 char* ptr = NULL; /* temp char ptr ;-) */
2622 char head[HEAD_SIZE + 1] = "";
2623 char code[HEAD_CODE + 1] = "";
2624
2625 // Format and assign to head
2626 snprintf(head, HEAD_SIZE + 1, "%0*d", HEAD_SIZE, n);
2627 // Format and assign to code
2628 snprintf(code, HEAD_CODE + 1, "%0*d", HEAD_CODE, _code);
2629
2630 /* sending head */
2631 bcount = bs = 0;
2632 ptr = head;
2633 while (bcount < HEAD_SIZE) /* loop until full buffer */
2634 {
2635 bs = send(s, ptr, (size_t)(HEAD_SIZE - bcount), NETFLAGS);
2636 error = neterrno;
2637 if (bs > 0) {
2638 bcount += bs; /* increment byte counter */
2639 ptr += bs; /* move buffer ptr for next read */
2640 } else {
2641 /* signal an error to the caller */
2642 errmsg = netstrerror(error);
2643 n_log(LOG_ERR, "Socket %d sending Error %d when sending head size, neterrno: %s", s, bs, _str(errmsg));
2644 FreeNoLog(errmsg);
2645 return -1;
2646 }
2647 }
2648
2649 /* sending code */
2650 bcount = bs = 0;
2651 ptr = code;
2652 while (bcount < HEAD_CODE) /* loop until full buffer */
2653 {
2654 bs = send(s, ptr, (size_t)(HEAD_CODE - bcount), NETFLAGS);
2655 error = neterrno;
2656 if (bs > 0) {
2657 bcount += bs; /* increment byte counter */
2658 ptr += bs; /* move buffer ptr for next read */
2659 } else {
2660 errmsg = netstrerror(error);
2661 n_log(LOG_ERR, "Socket %d sending Error %d when sending head code, neterrno: %s", s, bs, _str(errmsg));
2662 FreeNoLog(errmsg);
2663 return -1;
2664 }
2665 }
2666
2667 /* sending buf */
2668 bcount = 0;
2669 bs = 0;
2670 while (bcount < n) /* loop until full buffer */
2671 {
2672 bs = send(s, buf, (size_t)(n - bcount), NETFLAGS);
2673 error = neterrno;
2674 if (bs > 0) {
2675 bcount += bs; /* increment byte counter */
2676 buf += bs; /* move buffer ptr for next read */
2677 } else {
2678 /* signal an error to the caller */
2679 errmsg = netstrerror(error);
2680 n_log(LOG_ERR, "Socket %d sending Error %d when sending message of size %d, neterrno: %s", s, bs, n, _str(errmsg));
2681 FreeNoLog(errmsg);
2682 return -1;
2683 }
2684 }
2685
2686 return bcount;
2687
2688} /*send_php(...)*/
2689
2697ssize_t recv_php(SOCKET s, int* _code, char** buf) {
2698 ssize_t bcount = 0; /* counts bytes read */
2699 ssize_t br = 0; /* bytes read this pass */
2700 long int tmpnb = 0, size = 0; /* size of message to receive */
2701 char* ptr = NULL;
2702
2703 int error = 0;
2704 char* errmsg = NULL;
2705
2706 char head[HEAD_SIZE + 1] = "";
2707 char code[HEAD_CODE + 1] = "";
2708
2709 /* Receiving total message size */
2710 bcount = br = 0;
2711 ptr = head;
2712 while (bcount < HEAD_SIZE) {
2713 /* loop until full buffer */
2714 br = recv(s, ptr, (size_t)(HEAD_SIZE - bcount), NETFLAGS);
2715 error = neterrno;
2716 if (br > 0) {
2717 bcount += br; /* increment byte counter */
2718 ptr += br; /* move buffer ptr for next read */
2719 } else {
2720 if (br == 0 && bcount == (HEAD_SIZE - bcount))
2721 break;
2722 /* signal an error to the caller */
2723 errmsg = netstrerror(error);
2724 n_log(LOG_ERR, "Socket %d receive %d Error %s", s, br, _str(errmsg));
2725 FreeNoLog(errmsg);
2726 return FALSE;
2727 }
2728 }
2729
2730 tmpnb = strtol(head, NULL, 10);
2731 if (tmpnb == LONG_MIN || tmpnb == LONG_MAX) {
2732 n_log(LOG_ERR, "Size received ( %ld ) can not be determined on socket %d", tmpnb, s);
2733 return FALSE;
2734 }
2735
2736 size = tmpnb;
2737
2738 /* receiving request code */
2739 bcount = br = 0;
2740 ptr = code;
2741 while (bcount < HEAD_CODE) {
2742 /* loop until full buffer */
2743 br = recv(s, ptr, (size_t)(HEAD_CODE - bcount), NETFLAGS);
2744 error = neterrno;
2745 if (br > 0) {
2746 bcount += br; /* increment byte counter */
2747 ptr += br; /* move buffer ptr for next read */
2748 } else {
2749 if (br == 0 && bcount == (HEAD_CODE - bcount))
2750 break;
2751 /* signal an error to the caller */
2752 errmsg = netstrerror(error);
2753 n_log(LOG_ERR, "Socket %d receive %d Error , neterrno: %s", s, br, _str(errmsg));
2754 FreeNoLog(errmsg);
2755 return FALSE;
2756 }
2757 }
2758
2759 tmpnb = strtol(code, NULL, 10);
2760 if (tmpnb <= INT_MIN || tmpnb >= INT_MAX) {
2761 n_log(LOG_ERR, "Code received ( %ld ) too big or too little to be valid code on socket %d\n", tmpnb, s);
2762 return FALSE;
2763 }
2764
2765 (*_code) = (int)tmpnb;
2766
2767 /* receving message */
2768 if ((*buf)) {
2769 Free((*buf));
2770 }
2771 Malloc((*buf), char, (size_t)(size + 1));
2772 if (!(*buf)) {
2773 n_log(LOG_ERR, "Could not allocate PHP receive buf");
2774 return FALSE;
2775 }
2776
2777 bcount = 0;
2778 br = 0;
2779 ptr = (*buf);
2780 while (bcount < size) {
2781 /* loop until full buffer */
2782 br = recv(s, ptr, (size_t)(size - bcount), NETFLAGS);
2783 error = neterrno;
2784 if (br > 0) {
2785 bcount += br; /* increment byte counter */
2786 ptr += br; /* move buffer ptr for next read */
2787 } else {
2788 if (br == 0 && bcount == (size - bcount))
2789 break;
2790 /* signal an error to the caller */
2791 errmsg = netstrerror(error);
2792 n_log(LOG_ERR, "Socket %d receive %d Error neterrno: %s", s, br, _str(errmsg));
2793 FreeNoLog(errmsg);
2794 return FALSE;
2795 }
2796 }
2797 return size;
2798} /*recv_php(...)*/
2799
2808int netw_get_queue_status(NETWORK* netw, size_t* nb_to_send, size_t* nb_to_read) {
2809 __n_assert(netw, return FALSE);
2810
2811 pthread_mutex_lock(&netw->sendbolt);
2812 (*nb_to_send) = netw->send_buf->nb_items;
2813 pthread_mutex_unlock(&netw->sendbolt);
2814
2815 pthread_mutex_lock(&netw->recvbolt);
2816 (*nb_to_read) = netw->recv_buf->nb_items;
2817 pthread_mutex_unlock(&netw->recvbolt);
2818
2819 return TRUE;
2820} /* get queue states */
2821
2827NETWORK_POOL* netw_new_pool(size_t nb_min_element) {
2828 NETWORK_POOL* netw_pool = NULL;
2829
2830 Malloc(netw_pool, NETWORK_POOL, 1);
2831 __n_assert(netw_pool, return NULL);
2832
2833 netw_pool->pool = new_ht(nb_min_element);
2834 __n_assert(netw_pool->pool, Free(netw_pool); return NULL);
2835
2836 init_lock(netw_pool->rwlock);
2837
2838 return netw_pool;
2839} /* netw_new_pool() */
2840
2847 __n_assert(netw_pool && (*netw_pool), return FALSE);
2848
2849 write_lock((*netw_pool)->rwlock);
2850 if ((*netw_pool)->pool)
2851 destroy_ht(&(*netw_pool)->pool);
2852 unlock((*netw_pool)->rwlock);
2853
2854 rw_lock_destroy((*netw_pool)->rwlock);
2855
2856 Free((*netw_pool));
2857
2858 return TRUE;
2859} /* netw_destroy_pool() */
2860
2865void netw_pool_netw_close(void* netw_ptr) {
2866 NETWORK* netw = (NETWORK*)netw_ptr;
2867 __n_assert(netw, return);
2868 n_log(LOG_DEBUG, "Network pool %p: network id %d still active !!", netw, netw->link.sock);
2869 return;
2870} /* netw_pool_netw_close() */
2871
2878int netw_pool_add(NETWORK_POOL* netw_pool, NETWORK* netw) {
2879 __n_assert(netw_pool, return FALSE);
2880 __n_assert(netw, return FALSE);
2881
2882 n_log(LOG_DEBUG, "Trying to add %lld to %p", (unsigned long long)netw->link.sock, netw_pool->pool);
2883
2884 /* write lock the pool */
2885 write_lock(netw_pool->rwlock);
2886 /* test if not already added */
2887 N_STR* key = NULL;
2888 nstrprintf(key, "%lld", (unsigned long long)netw->link.sock);
2889 HASH_NODE* node = NULL;
2890 if (ht_get_ptr(netw_pool->pool, _nstr(key), (void*)&node) == TRUE) {
2891 n_log(LOG_ERR, "Network id %d already added !", netw->link.sock);
2892 free_nstr(&key);
2893 unlock(netw_pool->rwlock);
2894 return FALSE;
2895 }
2896 int retval = FALSE;
2897 /* add it */
2898 if ((retval = ht_put_ptr(netw_pool->pool, _nstr(key), netw, &netw_pool_netw_close)) == TRUE) {
2899 if ((retval = list_push(netw->pools, netw_pool, NULL)) == TRUE) {
2900 n_log(LOG_DEBUG, "added netw %d to pool %p", netw->link.sock, netw_pool);
2901 } else {
2902 n_log(LOG_ERR, "could not add netw %d to pool %p", netw->link.sock, netw_pool);
2903 }
2904 } else {
2905 n_log(LOG_ERR, "could not add netw %d to pool %p", netw->link.sock, netw_pool);
2906 }
2907 free_nstr(&key);
2908
2909 /* unlock the pool */
2910 unlock(netw_pool->rwlock);
2911
2912 return retval;
2913} /* netw_pool_add() */
2914
2921int netw_pool_remove(NETWORK_POOL* netw_pool, NETWORK* netw) {
2922 __n_assert(netw_pool, return FALSE);
2923 __n_assert(netw, return FALSE);
2924
2925 /* write lock the pool */
2926 write_lock(netw_pool->rwlock);
2927 /* test if present */
2928 N_STR* key = NULL;
2929 nstrprintf(key, "%lld", (unsigned long long int)netw->link.sock);
2930 if (ht_remove(netw_pool->pool, _nstr(key)) == TRUE) {
2931 LIST_NODE* node = list_search(netw->pools, netw);
2932 if (node) {
2933 if (!remove_list_node(netw->pools, node, NETWORK_POOL)) {
2934 n_log(LOG_ERR, "Network id %d could not be removed !", netw->link.sock);
2935 }
2936 }
2937 unlock(netw_pool->rwlock);
2938 n_log(LOG_DEBUG, "Network id %d removed !", netw->link.sock);
2939
2940 return TRUE;
2941 }
2942 free_nstr(&key);
2943 n_log(LOG_ERR, "Network id %d already removed !", netw->link.sock);
2944 /* unlock the pool */
2945 unlock(netw_pool->rwlock);
2946 return FALSE;
2947} /* netw_pool_remove */
2948
2956int netw_pool_broadcast(NETWORK_POOL* netw_pool, NETWORK* from, N_STR* net_msg) {
2957 __n_assert(netw_pool, return FALSE);
2958 __n_assert(net_msg, return FALSE);
2959
2960 /* write lock the pool */
2961 read_lock(netw_pool->rwlock);
2962 ht_foreach(node, netw_pool->pool) {
2963 NETWORK* netw = hash_val(node, NETWORK);
2964 if (from) {
2965 if (netw->link.sock != from->link.sock)
2966 netw_add_msg(netw, nstrdup(net_msg));
2967 } else {
2968 netw_add_msg(netw, nstrdup(net_msg));
2969 }
2970 }
2971 unlock(netw_pool->rwlock);
2972 return TRUE;
2973} /* netw_pool_broadcast */
2974
2981 __n_assert(netw_pool, return 0);
2982
2983 size_t nb = 0;
2984 read_lock(netw_pool->rwlock);
2985 nb = netw_pool->pool->nb_keys;
2986 unlock(netw_pool->rwlock);
2987
2988 return nb;
2989} /* netw_pool_nbclients() */
2990
2997int netw_set_user_id(NETWORK* netw, int id) {
2998 __n_assert(netw, return FALSE);
2999 netw->user_id = id;
3000 return TRUE;
3001} /* netw_set_user_id() */
3002
3012int netw_send_ping(NETWORK* netw, int type, int id_from, int id_to, int time) {
3013 N_STR* tmpstr = NULL;
3014 __n_assert(netw, return FALSE);
3015
3016 tmpstr = netmsg_make_ping(type, id_from, id_to, time);
3017 __n_assert(tmpstr, return FALSE);
3018
3019 return netw_add_msg(netw, tmpstr);
3020} /* netw_send_ping( ... ) */
3021
3031int netw_send_ident(NETWORK* netw, int type, int id, N_STR* name, N_STR* passwd) {
3032 N_STR* tmpstr = NULL;
3033
3034 __n_assert(netw, return FALSE);
3035
3036 tmpstr = netmsg_make_ident(type, id, name, passwd);
3037 __n_assert(tmpstr, return FALSE);
3038
3039 return netw_add_msg(netw, tmpstr);
3040} /* netw_send_ident( ... ) */
3041
3055int netw_send_position(NETWORK* netw, int id, double X, double Y, double vx, double vy, double acc_x, double acc_y, int time_stamp) {
3056 N_STR* tmpstr = NULL;
3057
3058 __n_assert(netw, return FALSE);
3059
3060 tmpstr = netmsg_make_position_msg(id, X, Y, vx, vy, acc_x, acc_y, time_stamp);
3061
3062 __n_assert(tmpstr, return FALSE);
3063
3064 return netw_add_msg(netw, tmpstr);
3065} /* netw_send_position( ... ) */
3066
3077int netw_send_string_to(NETWORK* netw, int id_to, N_STR* name, N_STR* chan, N_STR* txt, int color) {
3078 N_STR* tmpstr = NULL;
3079
3080 __n_assert(netw, return FALSE);
3081
3082 tmpstr = netmsg_make_string_msg(netw->user_id, id_to, name, chan, txt, color);
3083 __n_assert(tmpstr, return FALSE);
3084
3085 return netw_add_msg(netw, tmpstr);
3086} /* netw_send_string_to( ... ) */
3087
3097int netw_send_string_to_all(NETWORK* netw, N_STR* name, N_STR* chan, N_STR* txt, int color) {
3098 N_STR* tmpstr = NULL;
3099
3100 __n_assert(netw, return FALSE);
3101
3102 tmpstr = netmsg_make_string_msg(netw->user_id, -1, name, chan, txt, color);
3103 __n_assert(tmpstr, return FALSE);
3104
3105 return netw_add_msg(netw, tmpstr);
3106} /* netw_send_string_to_all( ... ) */
3107
3114 __n_assert(netw, return FALSE);
3115
3116 N_STR* tmpstr = NULL;
3117
3118 tmpstr = netmsg_make_quit_msg();
3119 __n_assert(tmpstr, return FALSE);
3120
3121 return netw_add_msg(netw, tmpstr);
3122} /* netw_send_quit( ... ) */
3123
3130size_t netw_calculate_urlencoded_size(const char* str, size_t len) {
3131 __n_assert(str, return 0);
3132
3133 size_t encoded_size = 0;
3134
3135 for (size_t i = 0; i < len; i++) {
3136 unsigned char c = (unsigned char)str[i];
3137 if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
3138 encoded_size += 1; // Safe character, no encoding needed
3139 } else {
3140 encoded_size += 3; // Unsafe character, will be encoded as %XX
3141 }
3142 }
3143
3144 return encoded_size;
3145}
3146
3153char* netw_urlencode(const char* str, size_t len) {
3154 __n_assert(str, return NULL);
3155
3156 static const char* hex = "0123456789ABCDEF";
3157 size_t encoded_size = netw_calculate_urlencoded_size(str, len);
3158 char* encoded = (char*)malloc(encoded_size + 1); // Allocate memory for the encoded string (+1 for the null terminator)
3159
3160 if (!encoded) {
3161 return NULL; // Return NULL if memory allocation fails
3162 }
3163
3164 char* pbuf = encoded;
3165
3166 for (size_t i = 0; i < len; i++) {
3167 unsigned char c = (unsigned char)str[i];
3168 if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
3169 *pbuf++ = (char)c; // Copy safe characters directly
3170 } else {
3171 *pbuf++ = '%'; // Encode unsafe characters as %XX
3172 *pbuf++ = hex[c >> 4];
3173 *pbuf++ = hex[c & 0xF];
3174 }
3175 }
3176
3177 *pbuf = '\0'; // Null-terminate the encoded string
3178 return encoded;
3179}
3180
3186char* netw_extract_http_request_type(const char* request) {
3187 __n_assert(request, return NULL);
3188 // Find the first space in the request string
3189 const char* space = strchr(request, ' ');
3190
3191 if (space == NULL) {
3192 // No space found, invalid request format
3193 return NULL;
3194 }
3195
3196 // Calculate the length of the request type
3197 size_t method_length = (size_t)(space - request);
3198
3199 // Allocate memory for the method string (+1 for the null terminator)
3200 char* method = (char*)malloc(method_length + 1);
3201
3202 if (method == NULL) {
3203 // Memory allocation failed
3204 return NULL;
3205 }
3206
3207 // Copy the request method to the allocated memory
3208 strncpy(method, request, method_length);
3209 method[method_length] = '\0'; // Null-terminate the string
3210
3211 return method;
3212}
3213
3220 NETWORK_HTTP_INFO info;
3221 info.content_length = 0;
3222 info.body = NULL;
3223 memset(info.content_type, 0, sizeof(info.content_type));
3224
3225 __n_assert(request, return info);
3226
3227 // Find Request-Type
3228 info.type = netw_extract_http_request_type(request);
3229
3230 // Find Content-Type header (Optional)
3231 const char* content_type_header = strstr(request, "Content-Type:");
3232 if (content_type_header) {
3233 const char* start = content_type_header + strlen("Content-Type: ");
3234 const char* end = strstr(start, "\r\n");
3235 if (end) {
3236 size_t length = (size_t)(end - start);
3237 strncpy(info.content_type, start, length);
3238 info.content_type[length] = '\0';
3239 }
3240 } else {
3241 // If no Content-Type header found, set default
3242 strncpy(info.content_type, "text/plain", sizeof(info.content_type) - 1);
3243 }
3244
3245 // Find Content-Length header (Optional)
3246 const char* content_length_header = strstr(request, "Content-Length:");
3247 if (content_length_header) {
3248 const char* start = content_length_header + strlen("Content-Length: ");
3249 errno = 0;
3250 unsigned long tmp_cl = strtoul(start, NULL, 10); /* parse once */
3251 int error = errno;
3252 // Handle out-of-range error (e.g., set a safe default or return an error)
3253 // Only when ULONG_MAX is larger than SIZE_MAX, to prevent a constant false comparison warning
3254#if ULONG_MAX > SIZE_MAX
3255 if (error == ERANGE || tmp_cl > SIZE_MAX) {
3256#else
3257 if (error == ERANGE) {
3258#endif
3259 n_log(LOG_ERR, "could not get content_length for request %p, returned %s", request, strerror(error));
3260 info.content_length = SIZE_MAX; /* clamp to the maximum supported value */
3261 } else {
3262 info.content_length = (size_t)tmp_cl;
3263 }
3264 }
3265
3266 // Find the start of the body (after \r\n\r\n)
3267 const char* body_start = strstr(request, "\r\n\r\n");
3268 if (body_start) {
3269 body_start += 4; // Skip the \r\n\r\n
3270
3271 // If there is a Content-Length, and it's greater than 0, copy the body
3272 if (info.content_length > 0) {
3273 info.body = malloc(info.content_length + 1); // Allocate memory for body
3274 if (info.body) {
3275 strncpy(info.body, body_start, info.content_length);
3276 info.body[info.content_length] = '\0'; // Null-terminate the body
3277 }
3278 }
3279 }
3280 return info;
3281}
3282
3289 FreeNoLog(http_request.body);
3290 FreeNoLog(http_request.type);
3291 return TRUE;
3292}
3293
3301int netw_get_url_from_http_request(const char* request, char* url, size_t size) {
3302 __n_assert(request && strlen(request) > 0, return FALSE);
3303 __n_assert(url && size > 1, return FALSE);
3304
3305 /* Default output */
3306 strncpy(url, "/", size - 1);
3307 url[size - 1] = '\0';
3308
3309 /* Example request line: "GET /path/to/resource HTTP/1.1" */
3310 const char* first_space = strchr(request, ' ');
3311 if (!first_space) {
3312 /* Malformed request, return default '/' */
3313 return FALSE;
3314 }
3315
3316 const char* second_space = strchr(first_space + 1, ' ');
3317 if (!second_space) {
3318 /* Malformed request, return default '/' */
3319 return FALSE;
3320 }
3321
3322 size_t len = (size_t)(second_space - first_space - 1);
3323 if (len >= size) {
3324 len = size - 1;
3325 }
3326
3327 strncpy(url, first_space + 1, len);
3328 url[len] = '\0'; /* Null-terminate the URL */
3329
3330 return TRUE;
3331}
3332
3338char* netw_urldecode(const char* str) {
3339 __n_assert(str, return NULL);
3340 char* decoded = malloc(strlen(str) + 1);
3341 __n_assert(decoded, return NULL);
3342
3343 char* p = decoded;
3344 while (*str) {
3345 if (*str == '%') {
3346 if (isxdigit((unsigned char)str[1]) && isxdigit((unsigned char)str[2])) {
3347 int value;
3348 if (sscanf(str + 1, "%2x", &value) >= 1) {
3349 *p++ = (char)value;
3350 str += 3;
3351 } else {
3352 n_log(LOG_ERR, "sscanf could not parse char *str (%p) for a %%2x", str);
3353 Free(decoded);
3354 return NULL;
3355 }
3356 } else {
3357 *p++ = *str++;
3358 }
3359 } else if (*str == '+') {
3360 *p++ = ' ';
3361 str++;
3362 } else {
3363 *p++ = *str++;
3364 }
3365 }
3366 *p = '\0';
3367 return decoded;
3368}
3369
3375HASH_TABLE* netw_parse_post_data(const char* post_data) {
3376 __n_assert(post_data, return NULL);
3377
3378 // Create a copy of the post_data string because strtok modifies the string
3379 char* data = strdup(post_data);
3380 __n_assert(data, return NULL);
3381
3382 char* pair = data;
3383 char* ampersand_pos;
3384
3385 HASH_TABLE* post_data_table = new_ht(32);
3386
3387 while (pair != NULL) {
3388 // Find the next key-value pair separated by '&'
3389 ampersand_pos = strchr(pair, '&');
3390
3391 // If found, replace it with '\0' to isolate the current pair
3392 if (ampersand_pos != NULL) {
3393 *ampersand_pos = '\0';
3394 }
3395
3396 // Now split each pair by '=' to get the key and value
3397 char* equal_pos = strchr(pair, '=');
3398 if (equal_pos != NULL) {
3399 *equal_pos = '\0'; // Terminate the key string
3400 char* key = pair;
3401 char* value = equal_pos + 1;
3402
3403 // Decode the value since POST data is URL-encoded
3404 char* decoded_value = netw_urldecode(value);
3405 ht_put_string(post_data_table, key, decoded_value);
3406 // printf("Key: %s, Value: %s\n", key, decoded_value);
3407 free(decoded_value);
3408 }
3409 // Move to the next key-value pair (if any)
3410 pair = (ampersand_pos != NULL) ? (ampersand_pos + 1) : NULL;
3411 }
3412 // Free the duplicated string
3413 free(data);
3414 return post_data_table;
3415}
3416
3422const char* netw_guess_http_content_type(const char* url) {
3423 __n_assert(url, return NULL);
3424
3425 // Create a copy of the URL to work on (to avoid modifying the original string)
3426 char url_copy[1024];
3427 strncpy(url_copy, url, sizeof(url_copy) - 1);
3428 url_copy[sizeof(url_copy) - 1] = '\0';
3429
3430 // Find if there is a '?' (indicating GET parameters) and terminate the string there
3431 char* query_start = strchr(url_copy, '?');
3432 if (query_start) {
3433 *query_start = '\0'; // Terminate the string before the query parameters
3434 }
3435
3436 // Find the last occurrence of a dot in the URL (file extension)
3437 const char* ext = strrchr(url_copy, '.');
3438
3439 // If no extension is found, return "unknown"
3440 if (!ext) {
3441 return "unknown";
3442 }
3443
3444 // Compare the extension to known content types
3445 if (strcmp(ext, ".html") == 0 || strcmp(ext, ".htm") == 0) {
3446 return "text/html";
3447 } else if (strcmp(ext, ".txt") == 0) {
3448 return "text/plain";
3449 } else if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0) {
3450 return "image/jpeg";
3451 } else if (strcmp(ext, ".png") == 0) {
3452 return "image/png";
3453 } else if (strcmp(ext, ".gif") == 0) {
3454 return "image/gif";
3455 } else if (strcmp(ext, ".css") == 0) {
3456 return "text/css";
3457 } else if (strcmp(ext, ".js") == 0) {
3458 return "application/javascript";
3459 } else if (strcmp(ext, ".json") == 0) {
3460 return "application/json";
3461 } else if (strcmp(ext, ".xml") == 0) {
3462 return "application/xml";
3463 } else if (strcmp(ext, ".pdf") == 0) {
3464 return "application/pdf";
3465 } else if (strcmp(ext, ".zip") == 0) {
3466 return "application/zip";
3467 } else if (strcmp(ext, ".mp4") == 0) {
3468 return "video/mp4";
3469 } else if (strcmp(ext, ".mp3") == 0) {
3470 return "audio/mpeg";
3471 } else if (strcmp(ext, ".wav") == 0) {
3472 return "audio/wav";
3473 } else if (strcmp(ext, ".ogg") == 0) {
3474 return "audio/ogg";
3475 }
3476
3477 // Return unknown for other types
3478 return "unknown";
3479}
3480
3486const char* netw_get_http_status_message(int status_code) {
3487 switch (status_code) {
3488 case 200:
3489 return "OK";
3490 case 204:
3491 return "No Content";
3492 case 304:
3493 return "Not Modified";
3494 case 404:
3495 return "Not Found";
3496 case 500:
3497 return "Internal Server Error";
3498 // Add more status codes as needed
3499 default:
3500 return "Unknown";
3501 }
3502}
3503
3510int netw_get_http_date(char* buffer, size_t buffer_size) {
3511 __n_assert(buffer, return FALSE);
3512 const time_t now = time(NULL);
3513 struct tm gmt;
3514#ifdef _WIN32
3515 if (gmtime_s(&gmt, &now) != 0) {
3516 n_log(LOG_ERR, "gmtime_s failed");
3517 return FALSE;
3518 }
3519#else
3520 if (!gmtime_r(&now, &gmt)) {
3521 n_log(LOG_ERR, "gmtime_r returned NULL");
3522 return FALSE;
3523 }
3524#endif
3525 if (strftime(buffer, buffer_size, "%a, %d %b %Y %H:%M:%S GMT", &gmt) == 0) {
3526 n_log(LOG_ERR, "strftime failed: buffer too small");
3527 return FALSE;
3528 }
3529 return TRUE;
3530}
3531
3542int netw_build_http_response(N_STR** http_response, int status_code, const char* server_name, const char* content_type, char* additional_headers, N_STR* body) {
3543 __n_assert(server_name, return FALSE);
3544 __n_assert(content_type, return FALSE);
3545 __n_assert(additional_headers, return FALSE);
3546
3547 const char* status_message = netw_get_http_status_message(status_code);
3548 const char* connection_type = "close";
3549
3550 // Buffer for the date header
3551 char date_buffer[128] = "";
3552 netw_get_http_date(date_buffer, sizeof(date_buffer));
3553
3554 if ((*http_response)) {
3555 (*http_response)->written = 0;
3556 }
3557
3558 if (!body || body->written == 0) {
3559 // Handle the case where there is no body
3560 nstrprintf((*http_response),
3561 "HTTP/1.1 %d %s\r\n"
3562 "Date: %s\r\n"
3563 "Server: %s\r\n"
3564 "Content-Length: 0\r\n"
3565 "%s"
3566 "Connection: %s\r\n\r\n",
3567 status_code, status_message, date_buffer, server_name, additional_headers, connection_type);
3568 n_log(LOG_DEBUG, "empty response");
3569 } else {
3570 // Build the response with body
3571 nstrprintf((*http_response),
3572 "HTTP/1.1 %d %s\r\n"
3573 "Date: %s\r\n"
3574 "Server: %s\r\n"
3575 "Content-Type: %s\r\n"
3576 "Content-Length: %zu\r\n"
3577 "%s"
3578 "Connection: %s\r\n\r\n",
3579 status_code, status_message, date_buffer, server_name, content_type, body->written, additional_headers, connection_type);
3580 nstrcat((*http_response), body);
3581 n_log(LOG_DEBUG, "body response");
3582 }
3583 return TRUE;
3584}
#define init_lock(__rwlock_mutex)
Macro for initializing a rwlock.
Definition n_common.h:331
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:251
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:187
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:258
#define _str(__PTR)
define true
Definition n_common.h:176
#define rw_lock_destroy(__rwlock_mutex)
Macro to destroy rwlock mutex.
Definition n_common.h:390
#define CALL_RETRY(__retvar, __expression, __max_tries, __delay)
TEMP_FAILURE gnu macro portable version.
Definition n_common.h:265
#define unlock(__rwlock_mutex)
Macro for releasing read/write lock a rwlock mutex.
Definition n_common.h:377
#define write_lock(__rwlock_mutex)
Macro for acquiring a write lock on a rwlock mutex.
Definition n_common.h:363
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:242
#define read_lock(__rwlock_mutex)
Macro for acquiring a read lock on a rwlock mutex.
Definition n_common.h:349
#define _nstr(__PTR)
N_STR or "NULL" string for logging purposes.
Definition n_common.h:182
#define N_ENUM_DEFINE(MACRO_DEFINITION, enum_name)
Macro to define an N_ENUM.
Definition n_enum.h:143
#define N_ENUM_ENTRY(class, method)
helper to build an N_ENUM
Definition n_enum.h:26
size_t nb_keys
total number of used keys in the table
Definition n_hash.h:118
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
Definition n_hash.c:2047
#define ht_foreach(__ITEM_, __HASH_)
ForEach macro helper (classic / old)
Definition n_hash.h:168
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
Definition n_hash.c:2180
int ht_remove(HASH_TABLE *table, const char *key)
remove and delete node at key in table
Definition n_hash.c:2138
HASH_TABLE * new_ht(size_t size)
Create a hash table with the given size.
Definition n_hash.c:1948
int ht_put_string(HASH_TABLE *table, const char *key, char *string)
put a string value (copy/dup) with given key in the targeted hash table
Definition n_hash.c:2113
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:2100
#define hash_val(node, type)
Cast a HASH_NODE element.
Definition n_hash.h:164
structure of a hash table node
Definition n_hash.h:90
structure of a hash table
Definition n_hash.h:114
size_t nb_items
number of item currently in the list
Definition n_list.h:41
#define list_shift(__LIST_, __TYPE_)
Shift macro helper for void pointer casting.
Definition n_list.h:74
int list_empty(LIST *list)
Empty a LIST list of pointers.
Definition n_list.c:471
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:199
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper.
Definition n_list.h:65
#define remove_list_node(__LIST_, __NODE_, __TYPE_)
Remove macro helper for void pointer casting.
Definition n_list.h:76
int list_destroy(LIST **list)
Empty and Free a list container.
Definition n_list.c:518
LIST_NODE * list_search(LIST *list, void *ptr)
search ptr in list
Definition n_list.c:440
#define MAX_LIST_ITEMS
flag to pass to new_generic_list for the maximum possible number of item in a list
Definition n_list.h:55
Structure of a generic list node.
Definition n_list.h:24
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:69
#define LOG_DEBUG
debug-level messages
Definition n_log.h:64
#define LOG_ERR
error conditions
Definition n_log.h:56
#define LOG_INFO
informational
Definition n_log.h:62
size_t written
size of the written data inside the string
Definition n_str.h:45
char * data
the string
Definition n_str.h:41
size_t length
length of string (in case we wanna keep information after the 0 end of string value)
Definition n_str.h:43
void free_nstr_ptr(void *ptr)
Free a N_STR pointer structure.
Definition n_str.c:49
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:176
#define nstrcat(__nstr_dst, __nstr_src)
Macro to quickly concatenate two N_STR.
Definition n_str.h:102
N_STR * nstrdup(N_STR *str)
Duplicate a N_STR.
Definition n_str.c:670
#define nstrprintf(__nstr_var, __format,...)
Macro to quickly allocate and sprintf to N_STR.
Definition n_str.h:94
A box including a string and his lenght.
Definition n_str.h:39
void u_sleep(unsigned int usec)
wrapper around usleep for API consistency
Definition n_time.c:35
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
char * ip
ip of the connected socket
Definition n_network.h:222
N_SOCKET link
networking socket
Definition n_network.h:302
char * certificate
openssl certificate file
Definition n_network.h:296
int threaded_engine_status
Threaded network engine state for this network.
Definition n_network.h:242
pthread_t send_thr
sending thread
Definition n_network.h:310
int nb_pending
Nb pending connection,if listening.
Definition n_network.h:238
int so_reuseaddr
so reuseaddr state
Definition n_network.h:248
pthread_t recv_thr
receiving thread
Definition n_network.h:312
pthread_rwlock_t rwlock
thread safety
Definition n_network.h:334
struct sockaddr_storage raddr
connected remote addr
Definition n_network.h:232
pthread_mutex_t eventbolt
mutex for threaded access of state event
Definition n_network.h:319
const SSL_METHOD * method
SSL method container.
Definition n_network.h:290
int deplete_socket_timeout
deplete socket send buffer timeout ( 0 disabled, > 0 wait for timeout and check unset/unack datas)
Definition n_network.h:276
int deplete_queues_timeout
deplete network queues timeout ( 0 disabled, > 0 wait for timeout and check unset/unack datas)
Definition n_network.h:274
int nb_running_threads
nb running threads, if > 0 thread engine is still running
Definition n_network.h:272
pthread_mutex_t recvbolt
mutex for threaded access of recv buf
Definition n_network.h:317
pthread_mutex_t sendbolt
mutex for threaded access of send_buf
Definition n_network.h:315
int send_queue_consecutive_wait
send queue consecutive pool interval, used when there are still items to send, in usec
Definition n_network.h:246
int so_rcvtimeo
send timeout value
Definition n_network.h:262
int tcpnodelay
state of naggle algorythm, 0 untouched, 1 forcibly disabled
Definition n_network.h:254
SOCKET sock
a normal socket
Definition n_network.h:220
char * port
port of socket
Definition n_network.h:218
LIST * recv_buf
reveicing buffer (for incomming usage)
Definition n_network.h:307
int user_id
if part of a user property, id of the user
Definition n_network.h:270
sem_t send_blocker
block sending func
Definition n_network.h:321
SSL_CTX * ctx
SSL context holder.
Definition n_network.h:292
int so_sndbuf
size of the socket send buffer, 0 untouched, else size in bytes
Definition n_network.h:256
int so_sndtimeo
send timeout value
Definition n_network.h:260
struct addrinfo hints
address of local machine
Definition n_network.h:228
int so_keepalive
so keepalive state
Definition n_network.h:252
netw_func send_data
send func ptr
Definition n_network.h:284
int addr_infos_loaded
Internal flag to know if we have to free addr infos.
Definition n_network.h:244
uint32_t state
state of the connection , NETW_RUN, NETW_QUIT, NETW_STOP , NETW_ERR
Definition n_network.h:281
LIST * pools
pointers to network pools if members of any
Definition n_network.h:324
char * key
openssl key file
Definition n_network.h:298
SSL * ssl
SSL handle.
Definition n_network.h:294
int so_linger
close lingering value (-1 disabled, 0 force close, >0 linger )
Definition n_network.h:264
unsigned long int is_blocking
flag to quickly check socket mode
Definition n_network.h:225
int crypto_algo
if encryption is on, which one (flags NETW_ENCRYPT_*)
Definition n_network.h:268
HASH_TABLE * pool
table of clients
Definition n_network.h:331
LIST * send_buf
sending buffer (for outgoing queuing )
Definition n_network.h:305
int mode
NETWORK mode , 1 listening, 0 connecting.
Definition n_network.h:240
int so_rcvbuf
size of the socket recv buffer, 0 untouched, else size in bytes
Definition n_network.h:258
netw_func recv_data
receive func ptr
Definition n_network.h:286
int wait_close_timeout
network wait close timeout value ( < 1 disabled, >= 1 timeout sec )
Definition n_network.h:278
#define NETW_SOCKET_ERROR
code for a socekt error
Definition n_network.h:44
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:3097
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:2956
N_STR * netw_get_msg(NETWORK *netw)
Get a message from aimed NETWORK.
Definition n_network.c:1995
int netw_add_msg(NETWORK *netw, N_STR *msg)
Add a message to send in aimed NETWORK.
Definition n_network.c:1928
ssize_t send_ssl_data(void *netw, char *buf, uint32_t n)
send data onto the socket
Definition n_network.c:2481
char * netw_extract_http_request_type(const char *request)
function to extract the request method from an http request
Definition n_network.c:3186
int netw_get_queue_status(NETWORK *netw, size_t *nb_to_send, size_t *nb_to_read)
retrieve network send queue status
Definition n_network.c:2808
int netw_init_wsa(int mode, int v1, int v2)
Do not directly use, internal api.
Definition n_network.c:693
ssize_t send_php(SOCKET s, int _code, char *buf, int n)
send data onto the socket
Definition n_network.c:2614
int netw_stop_thr_engine(NETWORK *netw)
Stop a NETWORK connection sending and receing thread.
Definition n_network.c:2340
char * netw_urlencode(const char *str, size_t len)
function to perform URL encoding
Definition n_network.c:3153
void * netw_send_func(void *NET)
Thread send function.
Definition n_network.c:2102
NETWORK * netw_accept_nonblock_from(NETWORK *from, int blocking)
make a normal blocking 'accept' .
Definition n_network.c:1918
int netw_get_url_from_http_request(const char *request, char *url, size_t size)
Helper function to extract the URL from the HTTP request line.
Definition n_network.c:3301
#define N_ENUM_netw_code_type(_)
Network codes definition.
Definition n_network.h:192
int netw_set_crypto(NETWORK *netw, char *key, char *certificate)
activate SSL encryption on selected network, using key and certificate
Definition n_network.c:1160
#define NETWORK_IPV6
Flag to force IPV6
Definition n_network.h:30
int netw_get_http_date(char *buffer, size_t buffer_size)
helper function to generate the current date in HTTP format
Definition n_network.c:3510
NETWORK_POOL * netw_new_pool(size_t nb_min_element)
return a new network pool of nb_min_element
Definition n_network.c:2827
int netw_set_user_id(NETWORK *netw, int id)
associate an id and a network
Definition n_network.c:2997
ssize_t recv_data(void *netw, char *buf, uint32_t n)
recv data from the socket
Definition n_network.c:2430
int netw_init_openssl(void)
Do not directly use, internal api.
Definition n_network.c:1116
ssize_t recv_ssl_data(void *netw, char *buf, uint32_t n)
recv data from the socket
Definition n_network.c:2547
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:1644
#define HEAD_SIZE
Size of a HEAD message.
Definition n_network.h:40
int netw_start_thr_engine(NETWORK *netw)
Start the NETWORK netw Threaded Engine.
Definition n_network.c:2067
int netw_destroy_pool(NETWORK_POOL **netw_pool)
free a NETWORK_POOL *pool
Definition n_network.c:2846
#define NETWORK_IPV4
Flag to force IPV4
Definition n_network.h:28
int netw_build_http_response(N_STR **http_response, int status_code, const char *server_name, const char *content_type, char *additional_headers, N_STR *body)
function to dynamically generate an HTTP response
Definition n_network.c:3542
void * netw_recv_func(void *NET)
To Thread Receiving function.
Definition n_network.c:2223
size_t htonst(size_t value)
host to network size_t
Definition n_network.c:30
int netw_unload_openssl(void)
Do not directly use, internal api.
Definition n_network.c:1140
#define HEAD_CODE
Code of a HEAD message.
Definition n_network.h:42
#define NETWORK_CONSECUTIVE_SEND_WAIT
Flag to set consecutive send waiting timeout
Definition n_network.h:36
size_t netw_pool_nbclients(NETWORK_POOL *netw_pool)
return the number of networks in netw_pool
Definition n_network.c:2980
NETWORK * netw_accept_from_ex(NETWORK *from, size_t send_list_limit, size_t recv_list_limit, int blocking, int *retval)
make a normal 'accept' .
Definition n_network.c:1753
int SOCKET
default socket declaration
Definition n_network.h:61
#define NETW_SOCKET_DISCONNECTED
Code for a disconnected recv.
Definition n_network.h:46
#define NETWORK_WAIT_CLOSE_TIMEOUT
Flag to set network closing wait timeout.
Definition n_network.h:38
int netw_setsockopt(NETWORK *netw, int optname, int value)
Modify common socket options on the given netw.
Definition n_network.c:794
int netw_set(NETWORK *netw, int flag)
Restart or reset the specified network ability.
Definition n_network.c:1409
ssize_t send_data(void *netw, char *buf, uint32_t n)
send data onto the socket
Definition n_network.c:2379
int netw_get_state(NETWORK *netw, uint32_t *state, int *thr_engine_status)
Get the state of a network.
Definition n_network.c:1388
void netw_pool_netw_close(void *netw_ptr)
close a network from a network pool
Definition n_network.c:2865
size_t netw_calculate_urlencoded_size(const char *str, size_t len)
function to calculate the required size for the URL-encoded string
Definition n_network.c:3130
int deplete_send_buffer(int fd, int timeout)
wait until the socket is empty or timeout, checking each 100 msec.
Definition n_network.c:1472
NETWORK * netw_accept_from(NETWORK *from)
make a normal blocking 'accept' .
Definition n_network.c:1908
#define NETW_MAX_RETRIES
Send or recv max number of retries.
Definition n_network.h:48
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
Definition n_network.c:1503
int netw_send_quit(NETWORK *netw)
Add a formatted NETMSG_QUIT message to the specified network.
Definition n_network.c:3113
const char * netw_get_http_status_message(int status_code)
helper function to convert status code to a human-readable message
Definition n_network.c:3486
int netw_set_blocking(NETWORK *netw, unsigned long int is_blocking)
Modify blocking socket mode.
Definition n_network.c:739
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:3077
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:3012
int netw_ssl_connect(NETWORK **netw, char *host, char *port, int ip_version, char *ssl_key_file, char *ssl_cert_file)
Use this to connect a NETWORK to any listening one, unrestricted send/recv lists.
Definition n_network.c:1375
NETWORK_HTTP_INFO netw_extract_http_info(char *request)
extract a lot of informations, mostly as pointers, and populate a NETWORK_HTTP_INFO structure
Definition n_network.c:3219
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:1359
__netw_code_type
Network codes declaration.
Definition n_network.h:210
#define NETWORK_DEPLETE_SOCKET_TIMEOUT
Flag to set send buffer depletion timeout
Definition n_network.h:32
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:3031
char * netw_urldecode(const char *str)
Function to decode URL-encoded data.
Definition n_network.c:3338
#define NETWORK_DEPLETE_QUEUES_TIMEOUT
Flag to set network queues depletion timeout
Definition n_network.h:34
int netw_pool_add(NETWORK_POOL *netw_pool, NETWORK *netw)
add a NETWORK *netw to a NETWORK_POOL *pool
Definition n_network.c:2878
int netw_info_destroy(NETWORK_HTTP_INFO http_request)
destroy a NETWORK_HTTP_INFO loaded informations
Definition n_network.c:3288
HASH_TABLE * netw_parse_post_data(const char *post_data)
Function to parse POST data.
Definition n_network.c:3375
const char * netw_guess_http_content_type(const char *url)
function to guess the content type based on URL extension
Definition n_network.c:3422
ssize_t recv_php(SOCKET s, int *_code, char **buf)
recv data from the socket
Definition n_network.c:2697
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:3055
int netw_pool_remove(NETWORK_POOL *netw_pool, NETWORK *netw)
remove a NETWORK *netw to a NETWORK_POOL *pool
Definition n_network.c:2921
int netw_add_msg_ex(NETWORK *netw, char *str, unsigned int length)
Add a message to send in aimed NETWORK.
Definition n_network.c:1959
Structure of a NETWORK.
Definition n_network.h:236
structure for splitting HTTP requests
Definition n_network.h:339
structure of a network pool
Definition n_network.h:329
Hash functions and table.
Generic log system.
NETWORK * netw_new(size_t send_list_limit, size_t recv_list_limit)
Return an empty allocated network ready to be netw_closed.
Definition n_network.c:573
#define netstrerror(code)
BSD style errno string NO WORKING ON REDHAT.
Definition n_network.c:555
#define neterrno
get last socket error code, linux version
Definition n_network.c:540
char * get_in_addr(struct sockaddr *sa)
get sockaddr, IPv4 or IPv6
Definition n_network.c:680
Network Engine.
Network messages , serialization tools.