Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
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;
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);
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);
635 return NULL;
636 }
638 if (!netw->pools) {
639 n_log(LOG_ERR, "Error when creating pools list");
641 return NULL;
642 }
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;
658
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);
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;
950 break;
953 break;
955 netw->wait_close_timeout = value;
956 break;
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
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
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();
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
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) {
1181 return FALSE;
1182 }
1183
1184 // Load default system certs
1185 if (SSL_CTX_load_verify_locations(netw->ctx, NULL, "/etc/ssl/certs/") != 1) {
1187 return FALSE;
1188 }
1189
1190 if (SSL_CTX_use_certificate_file(netw->ctx, certificate, SSL_FILETYPE_PEM) <= 0) {
1192 return FALSE;
1193 }
1194 if (SSL_CTX_use_PrivateKey_file(netw->ctx, key, SSL_FILETYPE_PEM) <= 0) {
1196 return FALSE;
1197 }
1198
1201
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
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)
1414 pthread_mutex_unlock(&netw->sendbolt);
1415 };
1416 if (flag & NETW_EMPTY_RECVBUF) {
1417 pthread_mutex_lock(&netw->recvbolt);
1418 if (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)
1426 pthread_mutex_unlock(&netw->sendbolt);
1427 };
1428 if (flag & NETW_DESTROY_RECVBUF) {
1429 pthread_mutex_lock(&netw->recvbolt);
1430 if (netw->recv_buf)
1432 pthread_mutex_unlock(&netw->recvbolt);
1433 }
1434 pthread_mutex_lock(&netw->eventbolt);
1435 if (flag & NETW_CLIENT) {
1437 }
1438 if (flag & NETW_SERVER) {
1440 }
1441 if (flag & NETW_RUN) {
1442 netw->state = NETW_RUN;
1443 }
1444 if (flag & NETW_EXITED) {
1446 }
1447 if (flag & NETW_ERROR) {
1449 }
1450 if (flag & NETW_EXIT_ASKED) {
1452 }
1453 if (flag & NETW_THR_ENGINE_STARTED) {
1455 }
1456 if (flag & 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
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) {
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*/
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
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 if (error != EINTR) {
1831 n_log(LOG_ERR, "accept returned an invalid socket (-1), neterrno: %s", strerror(error));
1832 }
1833 netw_close(&netw);
1834 return NULL;
1835 }
1836 netw->link.is_blocking = 0;
1837 } else {
1838 if (from->link.is_blocking == 0) {
1839 netw_set_blocking(from, 1);
1840 n_log(LOG_DEBUG, "(default) blocking accept call on socket %d", from->link.sock);
1841 }
1842 tmp = accept(from->link.sock, (struct sockaddr*)&netw->link.raddr, &sin_size);
1843 if (tmp < 0) {
1844 error = neterrno;
1845 errmsg = netstrerror(error);
1846 if (retval != NULL)
1847 (*retval) = error;
1848 n_log(LOG_DEBUG, "error accepting on socket %d, %s", netw->link.sock, _str(errmsg));
1849 FreeNoLog(errmsg);
1850 netw_close(&netw);
1851 return NULL;
1852 }
1853 netw->link.is_blocking = 1;
1854 }
1855 netw->link.sock = tmp;
1856 netw->link.port = strdup(from->link.port);
1857 Malloc(netw->link.ip, char, 64);
1858 if (!netw->link.ip) {
1859 n_log(LOG_ERR, "Error allocating 64 bytes for ip");
1860 netw_close(&netw);
1861 return NULL;
1862 }
1863 if (!inet_ntop(netw->link.raddr.ss_family, get_in_addr(((struct sockaddr*)&netw->link.raddr)), netw->link.ip, 64)) {
1864 error = neterrno;
1865 errmsg = netstrerror(error);
1866 n_log(LOG_ERR, "inet_ntop: %p , %s", netw->link.raddr, _str(errmsg));
1867 FreeNoLog(errmsg);
1868 netw_close(&netw);
1869 return NULL;
1870 }
1871
1872 netw_setsockopt(netw, SO_REUSEADDR, 1);
1873 // netw_setsockopt( netw, SO_REUSEPORT, 1 );
1874 netw_setsockopt(netw, SO_KEEPALIVE, 1);
1876 // netw_set_blocking(netw, 1);
1877
1878 n_log(LOG_DEBUG, "Connection accepted from %s:%s socket %d", netw->link.ip, netw->link.port, netw->link.sock);
1879
1880#ifdef HAVE_OPENSSL
1881 if (from->crypto_algo == NETW_ENCRYPT_OPENSSL) {
1882 netw->ssl = SSL_new(from->ctx);
1883 SSL_set_fd(netw->ssl, netw->link.sock);
1884
1887
1888 if (SSL_accept(netw->ssl) <= 0) {
1889 error = errno;
1890 n_log(LOG_ERR, "SSL error on %d", netw->link.sock);
1891 if (retval != NULL)
1892 (*retval) = error;
1894 netw_close(&netw);
1895 return NULL;
1896 } else {
1897 n_log(LOG_DEBUG, " socket %d: SSL connection established", netw->link.sock);
1898 }
1899 }
1900#endif
1901
1902 return netw;
1903} /* netw_accept_from_ex(...) */
1904
1911 return netw_accept_from_ex(from, MAX_LIST_ITEMS, MAX_LIST_ITEMS, 0, NULL);
1912} /* network_accept_from( ... ) */
1913
1921 return netw_accept_from_ex(from, MAX_LIST_ITEMS, MAX_LIST_ITEMS, blocking, NULL);
1922} /* network_accept_from( ... ) */
1923
1931 __n_assert(netw, return FALSE);
1932 __n_assert(msg, return FALSE);
1933 __n_assert(msg->data, return FALSE);
1934
1935 if (msg->length <= 0) {
1936 n_log(LOG_ERR, "Empty messages are not supported. msg(%p)->lenght=%d", msg, msg->length);
1937 return FALSE;
1938 }
1939
1940 pthread_mutex_lock(&netw->sendbolt);
1941
1942 if (list_push(netw->send_buf, msg, free_nstr_ptr) == FALSE) {
1943 pthread_mutex_unlock(&netw->sendbolt);
1944 return FALSE;
1945 }
1946
1947 pthread_mutex_unlock(&netw->sendbolt);
1948
1949 sem_post(&netw->send_blocker);
1950
1951 return TRUE;
1952} /* netw_add_msg(...) */
1953
1961int netw_add_msg_ex(NETWORK* netw, char* str, unsigned int length) {
1962 __n_assert(netw, return FALSE);
1963 __n_assert(str, return FALSE);
1964 if (length == 0) {
1965 return FALSE;
1966 }
1967
1968 N_STR* nstr = NULL;
1969 Malloc(nstr, N_STR, 1);
1970 __n_assert(nstr, return FALSE);
1971
1972 if (length == 0) {
1973 n_log(LOG_ERR, "Empty messages are not supported. msg(%p)->lenght=%d", str, length);
1974 return FALSE;
1975 }
1976
1977 nstr->data = str;
1978 nstr->written = nstr->length = length;
1979
1980 pthread_mutex_lock(&netw->sendbolt);
1981 if (list_push(netw->send_buf, nstr, free_nstr_ptr) == FALSE) {
1982 pthread_mutex_unlock(&netw->sendbolt);
1983 return FALSE;
1984 }
1985 pthread_mutex_unlock(&netw->sendbolt);
1986
1987 sem_post(&netw->send_blocker);
1988
1989 return TRUE;
1990} /* netw_add_msg_ex(...) */
1991
1998 N_STR* ptr = NULL;
1999
2000 __n_assert(netw, return NULL);
2001
2002 pthread_mutex_lock(&netw->recvbolt);
2003
2004 ptr = list_shift(netw->recv_buf, N_STR);
2005
2006 pthread_mutex_unlock(&netw->recvbolt);
2007
2008 return ptr;
2009} /* netw_get_msg(...)*/
2010
2018N_STR* netw_wait_msg(NETWORK* netw, unsigned int refresh, size_t timeout) {
2019 N_STR* nstrptr = NULL;
2020 size_t timed = 0;
2021 unsigned int secs = 0;
2022 unsigned int usecs = 0;
2023
2024 __n_assert(netw, return NULL);
2025
2026 usecs = refresh;
2027 if (refresh > 999999) {
2028 secs = refresh / 1000000;
2029 usecs = refresh % 1000000;
2030 }
2031
2032 if (timeout > 0)
2033 timed = timeout;
2034
2035 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);
2036 uint32_t state = NETW_RUN;
2037 int thr_state = 0;
2038 do {
2039 nstrptr = netw_get_msg(netw);
2040 if (nstrptr)
2041 return nstrptr;
2042
2043 if (timeout > 0) {
2044 if (timed >= refresh)
2045 timed -= refresh;
2046 if (timed == 0 || timed < refresh) {
2047 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);
2048 return NULL;
2049 }
2050 }
2051 if (secs > 0)
2052 sleep(secs);
2053 if (usecs > 0)
2054 u_sleep(usecs);
2055
2056 netw_get_state(netw, &state, &thr_state);
2057 } while (state != NETW_EXITED && state != NETW_ERROR);
2058
2059 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);
2060
2061 return NULL;
2062} /* netw_wait_msg(...) */
2063
2070 __n_assert(netw, return FALSE);
2071
2072 pthread_mutex_lock(&netw->eventbolt);
2074 n_log(LOG_ERR, "THR Engine already started for network %p (%s)", netw, _str(netw->link.ip));
2075 pthread_mutex_unlock(&netw->eventbolt);
2076 return FALSE;
2077 }
2078
2079 if (pthread_create(&netw->recv_thr, NULL, netw_recv_func, (void*)netw) != 0) {
2080 n_log(LOG_ERR, "Unable to create recv_thread for network %p (%s)", netw, _str(netw->link.ip));
2081 pthread_mutex_unlock(&netw->eventbolt);
2082 return FALSE;
2083 }
2085 if (pthread_create(&netw->send_thr, NULL, netw_send_func, (void*)netw) != 0) {
2086 n_log(LOG_ERR, "Unable to create send_thread for network %p (%s)", netw, _str(netw->link.ip));
2087 pthread_mutex_unlock(&netw->eventbolt);
2088 return FALSE;
2089 }
2091
2093
2094 pthread_mutex_unlock(&netw->eventbolt);
2095
2096 return TRUE;
2097} /* netw_create_recv_thread(....) */
2098
2104void* netw_send_func(void* NET) {
2105 int DONE = 0;
2106
2107 ssize_t net_status = 0;
2108
2109 uint32_t state = 0,
2110 nboctet = 0;
2111
2112 char nboct[5] = "";
2113
2114 N_STR* ptr = NULL;
2115
2116 NETWORK* netw = (NETWORK*)NET;
2117 __n_assert(netw, return NULL);
2118
2119 do {
2120 /* do not consume cpu for nothing, reduce delay */
2121 sem_wait(&netw->send_blocker);
2122 int message_sent = 0;
2123 while (message_sent == 0 && !DONE) {
2124 netw_get_state(netw, &state, NULL);
2125 if (state & NETW_ERROR) {
2126 DONE = 666;
2127 } else if (state & NETW_EXITED) {
2128 DONE = 100;
2129 } else if (state & NETW_EXIT_ASKED) {
2130 DONE = 100;
2131 /* sending state */
2132 nboctet = htonl(NETW_EXIT_ASKED);
2133 memcpy(nboct, &nboctet, sizeof(uint32_t));
2134 n_log(LOG_DEBUG, "%d Sending Quit !", netw->link.sock);
2135 net_status = netw->send_data(netw, nboct, sizeof(int32_t));
2136 if (net_status < 0)
2137 DONE = 4;
2138 n_log(LOG_DEBUG, "%d Quit sent!", netw->link.sock);
2139 } else {
2140 pthread_mutex_lock(&netw->sendbolt);
2141 ptr = list_shift(netw->send_buf, N_STR);
2142 pthread_mutex_unlock(&netw->sendbolt);
2143 if (ptr && ptr->length > 0 && ptr->data) {
2144 if (ptr->written <= UINT_MAX) {
2145 n_log(LOG_DEBUG, "Sending ptr size %zu written %zu...", ptr->length, ptr->written);
2146
2147 /* sending state */
2148 nboctet = htonl(state);
2149 memcpy(nboct, &nboctet, sizeof(uint32_t));
2150 /* sending state */
2151 if (!DONE) {
2152 net_status = netw->send_data(netw, nboct, sizeof(int32_t));
2153 if (net_status < 0)
2154 DONE = 1;
2155 }
2156 if (!DONE) {
2157 /* sending number of octet */
2158 nboctet = htonl((uint32_t)ptr->written);
2159 memcpy(nboct, &nboctet, sizeof(uint32_t));
2160 /* sending the number of octet to receive on next message */
2161 net_status = netw->send_data(netw, nboct, sizeof(uint32_t));
2162 if (net_status < 0)
2163 DONE = 2;
2164 }
2165 /* sending the data itself */
2166 if (!DONE) {
2167 net_status = netw->send_data(netw, ptr->data, (uint32_t)ptr->written);
2168 if (net_status < 0)
2169 DONE = 3;
2170 }
2173 }
2174 message_sent = 1;
2175 free_nstr(&ptr);
2176#ifdef __linux
2177 fsync(netw->link.sock);
2178#endif
2179 } else {
2180 n_log(LOG_ERR, "discarded packet of size %zu which is greater than %" PRIu32, ptr->written, UINT_MAX);
2181 message_sent = 1;
2182 free_nstr(&ptr);
2183 }
2184 }
2185 }
2186 }
2187 } while (!DONE);
2188
2189 if (DONE == 1)
2190 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");
2191 else if (DONE == 2)
2192 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");
2193 else if (DONE == 3)
2194 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");
2195 else if (DONE == 4)
2196 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");
2197 else if (DONE == 5)
2198 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");
2199
2200 if (DONE == 100) {
2201 n_log(LOG_DEBUG, "Socket %d: Sending thread exiting correctly", netw->link.sock);
2203 } else {
2204 n_log(LOG_ERR, "Socket %d (%s): Sending thread exiting with error %d !", netw->link.sock, _str(netw->link.ip), DONE);
2206 }
2207
2208 pthread_mutex_lock(&netw->eventbolt);
2210 pthread_mutex_unlock(&netw->eventbolt);
2211
2212 pthread_exit(0);
2213
2214 /* suppress compiler warning */
2215#if !defined(__linux__)
2216 return NULL;
2217#endif
2218} /* netw_send_func(...) */
2219
2225void* netw_recv_func(void* NET) {
2226 int DONE = 0;
2227 ssize_t net_status = 0;
2228
2229 uint32_t nboctet = 0,
2230 tmpstate = 0,
2231 state = 0;
2232
2233 char nboct[5] = "";
2234
2235 N_STR* recvdmsg = NULL;
2236
2237 NETWORK* netw = (NETWORK*)NET;
2238
2239 __n_assert(netw, return NULL);
2240
2241 do {
2242 netw_get_state(netw, &state, NULL);
2243 if (state & NETW_EXIT_ASKED || state & NETW_EXITED) {
2244 DONE = 100;
2245 }
2246 if (state & NETW_ERROR) {
2247 DONE = 666;
2248 }
2249 if (!DONE) {
2250 n_log(LOG_DEBUG, "socket %d : waiting to receive status", netw->link.sock);
2251 /* receiving state */
2252 net_status = netw->recv_data(netw, nboct, sizeof(uint32_t));
2253 if (net_status < 0) {
2254 DONE = 1;
2255 } else {
2256 memcpy(&nboctet, nboct, sizeof(uint32_t));
2257 tmpstate = ntohl(nboctet);
2258 nboctet = tmpstate;
2259 if (tmpstate == NETW_EXIT_ASKED) {
2260 n_log(LOG_DEBUG, "socket %d : receiving order to QUIT !", netw->link.sock);
2261 DONE = 100;
2262 } else {
2263 n_log(LOG_DEBUG, "socket %d : waiting to receive next message nboctets", netw->link.sock);
2264 /* receiving nboctet */
2265 net_status = netw->recv_data(netw, nboct, sizeof(uint32_t));
2266 if (net_status < 0) {
2267 DONE = 2;
2268 } else {
2269 memcpy(&nboctet, nboct, sizeof(uint32_t));
2270 tmpstate = ntohl(nboctet);
2271 nboctet = tmpstate;
2272
2273 Malloc(recvdmsg, N_STR, 1);
2274 if (!recvdmsg) {
2275 DONE = 3;
2276 } else {
2277 n_log(LOG_DEBUG, "socket %d : %" PRIu32 " octets to receive...", netw->link.sock, nboctet);
2278 Malloc(recvdmsg->data, char, nboctet + 1);
2279 if (!recvdmsg->data) {
2280 DONE = 4;
2281 } else {
2282 recvdmsg->length = nboctet + 1;
2283 recvdmsg->written = nboctet;
2284
2285 /* receiving the data itself */
2286 net_status = netw->recv_data(netw, recvdmsg->data, nboctet);
2287 if (net_status < 0) {
2288 DONE = 5;
2289 } else {
2290 pthread_mutex_lock(&netw->recvbolt);
2291 if (list_push(netw->recv_buf, recvdmsg, free_nstr_ptr) == FALSE)
2292 DONE = 6;
2293 pthread_mutex_unlock(&netw->recvbolt);
2294 n_log(LOG_DEBUG, "socket %d : %" PRIu32 " octets received !", netw->link.sock, nboctet);
2295 } /* recv data */
2296 } /* recv data allocation */
2297 } /* recv struct allocation */
2298 } /* recv nb octet*/
2299 } /* exit asked */
2300 } /* recv state */
2301 } /* if( !done) */
2302 } while (!DONE);
2303
2304 if (DONE == 1)
2305 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");
2306 else if (DONE == 2)
2307 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");
2308 else if (DONE == 3)
2309 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");
2310 else if (DONE == 4)
2311 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");
2312 else if (DONE == 5)
2313 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");
2314 else if (DONE == 6)
2315 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");
2316
2317 if (DONE == 100) {
2318 n_log(LOG_DEBUG, "Socket %d (%s): Receive thread exiting correctly", netw->link.sock, _str(netw->link.ip));
2320 } else {
2321 n_log(LOG_ERR, "Socket %d (%s): Receive thread exiting with code %d !", netw->link.sock, _str(netw->link.ip), DONE);
2323 }
2324
2325 pthread_mutex_lock(&netw->eventbolt);
2327 pthread_mutex_unlock(&netw->eventbolt);
2328
2329 pthread_exit(0);
2330
2331 /* suppress compiler warning */
2332#if !defined(__linux__)
2333 return NULL;
2334#endif
2335} /* netw_recv_func(...) */
2336
2343 __n_assert(netw, return FALSE);
2344 uint32_t state = 0;
2345 int thr_engine_status = 0;
2346
2347 n_log(LOG_DEBUG, "Network %d stop threads event", netw->link.sock);
2348
2349 netw_get_state(netw, &state, &thr_engine_status);
2350
2351 if (thr_engine_status != NETW_THR_ENGINE_STARTED) {
2352 n_log(LOG_ERR, "Thread engine status already stopped for network %p", netw);
2353 return FALSE;
2354 }
2355
2357
2358 n_log(LOG_DEBUG, "Network %d waits for send threads to stop", netw->link.sock);
2359 for (int it = 0; it < 10; it++) {
2360 sem_post(&netw->send_blocker);
2361 usleep(1000);
2362 }
2363 pthread_join(netw->send_thr, NULL);
2364 n_log(LOG_DEBUG, "Network %d waits for recv threads to stop", netw->link.sock);
2365 pthread_join(netw->recv_thr, NULL);
2366
2368
2369 n_log(LOG_DEBUG, "Network %d threads Stopped !", netw->link.sock);
2370
2371 return TRUE;
2372} /* Stop_Network( ... ) */
2373
2381ssize_t send_data(void* netw, char* buf, uint32_t n) {
2383 __n_assert(buf, return NETW_SOCKET_ERROR);
2384
2385 SOCKET s = ((NETWORK*)netw)->link.sock;
2386 ssize_t bcount = 0; /* counts bytes sent */
2387 int error = 0;
2388 char* errmsg = NULL;
2389
2390 if (n == 0) {
2391 n_log(LOG_ERR, "Send of 0 is unsupported.");
2392 return NETW_SOCKET_ERROR;
2393 }
2394
2395 char* tmp_buf = buf;
2396 while (bcount < n) // loop until all sent
2397 {
2398 ssize_t bs = 0; /* bytes sent this pass */
2399 // bs = send( s, tmp_buf, n - bcount, NETFLAGS );
2400 ssize_t retry_count = CALL_RETRY(bs, send(s, tmp_buf, (size_t)(n - bcount), NETFLAGS), NETW_MAX_RETRIES, NETW_RETRY_DELAY);
2401 error = neterrno;
2402 if (retry_count == NETW_MAX_RETRIES) {
2403 n_log(LOG_ERR, "Maximum send retries (%d) reached for socket %d", NETW_MAX_RETRIES, s);
2404 return NETW_SOCKET_ERROR;
2405 }
2406 if (bs > 0) {
2407 bcount += bs; /* increment byte counter */
2408 tmp_buf += bs; /* move buffer ptr for next read */
2409 // n_log(LOG_DEBUG, "socket %d sent %d/%d , retry %d/%d", s, bcount, n, retry_count, NETW_MAX_RETRIES);
2410 } else if (error == ECONNRESET || error == ENOTCONN) {
2411 n_log(LOG_DEBUG, "socket %d disconnected !", s);
2413 } else {
2414 /* signal an error to the caller */
2415 errmsg = netstrerror(error);
2416 n_log(LOG_ERR, "Socket %d send Error: %d , %s", s, bs, _str(errmsg));
2417 FreeNoLog(errmsg);
2418 return NETW_SOCKET_ERROR;
2419 }
2420 }
2421 send(s, NULL, 0, 0);
2422 return (int)bcount;
2423} /*send_data(...)*/
2424
2432ssize_t recv_data(void* netw, char* buf, uint32_t n) {
2434 __n_assert(buf, return NETW_SOCKET_ERROR);
2435
2436 SOCKET s = ((NETWORK*)netw)->link.sock;
2437 ssize_t bcount = 0; /* counts bytes read */
2438 int error = 0;
2439 char* errmsg = NULL;
2440
2441 if (n == 0) {
2442 n_log(LOG_ERR, "Recv of 0 is unsupported.");
2443 return NETW_SOCKET_ERROR;
2444 }
2445
2446 char* tmp_buf = buf;
2447 while (bcount < n) // loop until all received
2448 {
2449 ssize_t br = 0; /* bytes read this pass */
2450 // br = recv( s, tmp_buf, n - bcount, NETFLAGS );
2451 ssize_t retry_count = CALL_RETRY(br, recv(s, tmp_buf, (size_t)(n - bcount), NETFLAGS), NETW_MAX_RETRIES, NETW_RETRY_DELAY);
2452 error = neterrno;
2453 if (retry_count == NETW_MAX_RETRIES) {
2454 n_log(LOG_ERR, "Maximum recv retries (%d) reached for socket %d", NETW_MAX_RETRIES, s);
2455 return NETW_SOCKET_ERROR;
2456 }
2457 if (br > 0) {
2458 bcount += br; /* increment byte counter */
2459 tmp_buf += br; /* move buffer ptr for next read */
2460 // n_log(LOG_DEBUG, "socket %d received %d/%d , retry %d/%d", s, bcount, n, retry_count, NETW_MAX_RETRIES);
2461 } else if (br == 0) {
2462 n_log(LOG_DEBUG, "socket %d disconnected !", s);
2464 } else {
2465 /* signal an error to the caller */
2466 errmsg = netstrerror(error);
2467 n_log(LOG_ERR, "socket %d recv returned %d, error: %s", s, br, _str(errmsg));
2468 FreeNoLog(errmsg);
2469 return NETW_SOCKET_ERROR;
2470 }
2471 }
2472 return (int)bcount;
2473} /*recv_data(...)*/
2474
2475#ifdef HAVE_OPENSSL
2483ssize_t send_ssl_data(void* netw, char* buf, uint32_t n) {
2484 __n_assert(netw, return -1);
2485 __n_assert(buf, return -1);
2486
2487 SSL* ssl = ((NETWORK*)netw)->ssl;
2488 __n_assert(ssl, return -1);
2489
2490 SOCKET s = ((NETWORK*)netw)->link.sock;
2491
2492 ssize_t bcount = 0; // counts bytes sent
2493 int error = 0;
2494 char* errmsg = NULL;
2495
2496 if (n == 0) {
2497 n_log(LOG_ERR, "Send of 0 is unsupported.");
2498 return -1;
2499 }
2500
2501 while (bcount < n) // loop until full buffer
2502 {
2503 size_t bs = 0; // bytes sent this pass
2504#if OPENSSL_VERSION_NUMBER < 0x1010107fL
2505 int status = SSL_write(ssl, buf, (int)(n - bcount)); // OpenSSL < 1.1.1
2506 bs = (status > 0) ? (size_t)status : 0;
2507#else
2508 int status = SSL_write_ex(ssl, buf, (size_t)(n - bcount), &bs); // OpenSSL >= 1.1.1
2509#endif
2510 error = neterrno;
2511 if (status > 0) {
2512 bcount += (ssize_t)bs; // increment byte counter
2513 buf += bs; // move buffer ptr for next read
2514 } else {
2515 int ssl_error = SSL_get_error(ssl, status);
2516 if (ssl_error == SSL_ERROR_WANT_READ || ssl_error == SSL_ERROR_WANT_WRITE) {
2517 usleep(0);
2518 continue;
2519 }
2520 errmsg = netstrerror(error);
2521 switch (ssl_error) {
2522 case SSL_ERROR_SYSCALL:
2523 // Handle syscall failure
2524 n_log(LOG_ERR, "socket %d SSL_read syscall error: connection closed by peer", s);
2525 break;
2526 case SSL_ERROR_SSL:
2527 // Handle SSL protocol failure
2528 n_log(LOG_ERR, "socket %d SSL_read returned %d, error: %s", s, bs, ERR_reason_error_string(ERR_get_error()));
2529 break;
2530 default:
2531 // Other errors
2532 n_log(LOG_ERR, "socket %d SSL_read returned %d, errno: %s", s, bs, _str(errmsg));
2533 break;
2534 }
2535 FreeNoLog(errmsg);
2536 return -1;
2537 }
2538 }
2539 return bcount;
2540} /*send_ssl_data(...)*/
2541
2549ssize_t recv_ssl_data(void* netw, char* buf, uint32_t n) {
2550 __n_assert(netw, return -1);
2551 __n_assert(buf, return -1);
2552
2553 SSL* ssl = ((NETWORK*)netw)->ssl;
2554 __n_assert(ssl, return -1);
2555
2556 SOCKET s = ((NETWORK*)netw)->link.sock;
2557 ssize_t bcount = 0; // counts bytes read
2558 int error = 0;
2559 char* errmsg = NULL;
2560
2561 if (n == 0) {
2562 n_log(LOG_ERR, "Recv of 0 is unsupported.");
2563 return -1;
2564 }
2565
2566 while (bcount < n) {
2567 size_t br = 0; // bytes read this pass
2568 // loop until full buffer
2569#if OPENSSL_VERSION_NUMBER < 0x10101000L
2570 int status = SSL_read(ssl, buf, (int)(n - bcount)); // OpenSSL < 1.1.1
2571 br = (status > 0) ? (size_t)status : 0;
2572#else
2573 int status = SSL_read_ex(ssl, buf, (size_t)(n - bcount), &br); // OpenSSL >= 1.1.1
2574#endif
2575 error = neterrno;
2576 if (status > 0) {
2577 bcount += (ssize_t)br; // increment byte counter
2578 buf += br; // move buffer ptr for next read
2579 } else {
2580 int ssl_error = SSL_get_error(ssl, status);
2581 if (ssl_error == SSL_ERROR_WANT_READ || ssl_error == SSL_ERROR_WANT_WRITE) {
2582 usleep(0);
2583 continue;
2584 }
2585 errmsg = netstrerror(error);
2586 switch (ssl_error) {
2587 case SSL_ERROR_SYSCALL:
2588 // Handle syscall failure
2589 n_log(LOG_ERR, "socket %d SSL_read syscall error: connection closed by peer", s);
2590 break;
2591 case SSL_ERROR_SSL:
2592 // Handle SSL protocol failure
2593 n_log(LOG_ERR, "socket %d SSL_read returned %d, error: %s", s, br, ERR_reason_error_string(ERR_get_error()));
2594 break;
2595 default:
2596 // Other errors
2597 n_log(LOG_ERR, "socket %d SSL_read returned %d, errno: %s", s, br, _str(errmsg));
2598 break;
2599 }
2600 FreeNoLog(errmsg);
2601 return -1;
2602 }
2603 }
2604 return bcount;
2605} /*recv_ssl_data(...)*/
2606#endif
2607
2616ssize_t send_php(SOCKET s, int _code, char* buf, int n) {
2617 ssize_t bcount = 0; /* counts bytes read */
2618 ssize_t bs = 0; /* bytes read this pass */
2619
2620 int error = 0;
2621 char* errmsg = NULL;
2622
2623 char* ptr = NULL; /* temp char ptr ;-) */
2624 char head[HEAD_SIZE + 1] = "";
2625 char code[HEAD_CODE + 1] = "";
2626
2627 // Format and assign to head
2628 snprintf(head, HEAD_SIZE + 1, "%0*d", HEAD_SIZE, n);
2629 // Format and assign to code
2630 snprintf(code, HEAD_CODE + 1, "%0*d", HEAD_CODE, _code);
2631
2632 /* sending head */
2633 bcount = bs = 0;
2634 ptr = head;
2635 while (bcount < HEAD_SIZE) /* loop until full buffer */
2636 {
2637 bs = send(s, ptr, (size_t)(HEAD_SIZE - bcount), NETFLAGS);
2638 error = neterrno;
2639 if (bs > 0) {
2640 bcount += bs; /* increment byte counter */
2641 ptr += bs; /* move buffer ptr for next read */
2642 } else {
2643 /* signal an error to the caller */
2644 errmsg = netstrerror(error);
2645 n_log(LOG_ERR, "Socket %d sending Error %d when sending head size, neterrno: %s", s, bs, _str(errmsg));
2646 FreeNoLog(errmsg);
2647 return -1;
2648 }
2649 }
2650
2651 /* sending code */
2652 bcount = bs = 0;
2653 ptr = code;
2654 while (bcount < HEAD_CODE) /* loop until full buffer */
2655 {
2656 bs = send(s, ptr, (size_t)(HEAD_CODE - bcount), NETFLAGS);
2657 error = neterrno;
2658 if (bs > 0) {
2659 bcount += bs; /* increment byte counter */
2660 ptr += bs; /* move buffer ptr for next read */
2661 } else {
2662 errmsg = netstrerror(error);
2663 n_log(LOG_ERR, "Socket %d sending Error %d when sending head code, neterrno: %s", s, bs, _str(errmsg));
2664 FreeNoLog(errmsg);
2665 return -1;
2666 }
2667 }
2668
2669 /* sending buf */
2670 bcount = 0;
2671 bs = 0;
2672 while (bcount < n) /* loop until full buffer */
2673 {
2674 bs = send(s, buf, (size_t)(n - bcount), NETFLAGS);
2675 error = neterrno;
2676 if (bs > 0) {
2677 bcount += bs; /* increment byte counter */
2678 buf += bs; /* move buffer ptr for next read */
2679 } else {
2680 /* signal an error to the caller */
2681 errmsg = netstrerror(error);
2682 n_log(LOG_ERR, "Socket %d sending Error %d when sending message of size %d, neterrno: %s", s, bs, n, _str(errmsg));
2683 FreeNoLog(errmsg);
2684 return -1;
2685 }
2686 }
2687
2688 return bcount;
2689
2690} /*send_php(...)*/
2691
2699ssize_t recv_php(SOCKET s, int* _code, char** buf) {
2700 ssize_t bcount = 0; /* counts bytes read */
2701 ssize_t br = 0; /* bytes read this pass */
2702 long int tmpnb = 0, size = 0; /* size of message to receive */
2703 char* ptr = NULL;
2704
2705 int error = 0;
2706 char* errmsg = NULL;
2707
2708 char head[HEAD_SIZE + 1] = "";
2709 char code[HEAD_CODE + 1] = "";
2710
2711 /* Receiving total message size */
2712 bcount = br = 0;
2713 ptr = head;
2714 while (bcount < HEAD_SIZE) {
2715 /* loop until full buffer */
2716 br = recv(s, ptr, (size_t)(HEAD_SIZE - bcount), NETFLAGS);
2717 error = neterrno;
2718 if (br > 0) {
2719 bcount += br; /* increment byte counter */
2720 ptr += br; /* move buffer ptr for next read */
2721 } else {
2722 if (br == 0 && bcount == (HEAD_SIZE - bcount))
2723 break;
2724 /* signal an error to the caller */
2725 errmsg = netstrerror(error);
2726 n_log(LOG_ERR, "Socket %d receive %d Error %s", s, br, _str(errmsg));
2727 FreeNoLog(errmsg);
2728 return FALSE;
2729 }
2730 }
2731
2732 tmpnb = strtol(head, NULL, 10);
2733 if (tmpnb == LONG_MIN || tmpnb == LONG_MAX) {
2734 n_log(LOG_ERR, "Size received ( %ld ) can not be determined on socket %d", tmpnb, s);
2735 return FALSE;
2736 }
2737
2738 size = tmpnb;
2739
2740 /* receiving request code */
2741 bcount = br = 0;
2742 ptr = code;
2743 while (bcount < HEAD_CODE) {
2744 /* loop until full buffer */
2745 br = recv(s, ptr, (size_t)(HEAD_CODE - bcount), NETFLAGS);
2746 error = neterrno;
2747 if (br > 0) {
2748 bcount += br; /* increment byte counter */
2749 ptr += br; /* move buffer ptr for next read */
2750 } else {
2751 if (br == 0 && bcount == (HEAD_CODE - bcount))
2752 break;
2753 /* signal an error to the caller */
2754 errmsg = netstrerror(error);
2755 n_log(LOG_ERR, "Socket %d receive %d Error , neterrno: %s", s, br, _str(errmsg));
2756 FreeNoLog(errmsg);
2757 return FALSE;
2758 }
2759 }
2760
2761 tmpnb = strtol(code, NULL, 10);
2762 if (tmpnb <= INT_MIN || tmpnb >= INT_MAX) {
2763 n_log(LOG_ERR, "Code received ( %ld ) too big or too little to be valid code on socket %d", tmpnb, s);
2764 return FALSE;
2765 }
2766
2767 (*_code) = (int)tmpnb;
2768
2769 /* receving message */
2770 if ((*buf)) {
2771 Free((*buf));
2772 }
2773 Malloc((*buf), char, (size_t)(size + 1));
2774 if (!(*buf)) {
2775 n_log(LOG_ERR, "Could not allocate PHP receive buf");
2776 return FALSE;
2777 }
2778
2779 bcount = 0;
2780 br = 0;
2781 ptr = (*buf);
2782 while (bcount < size) {
2783 /* loop until full buffer */
2784 br = recv(s, ptr, (size_t)(size - bcount), NETFLAGS);
2785 error = neterrno;
2786 if (br > 0) {
2787 bcount += br; /* increment byte counter */
2788 ptr += br; /* move buffer ptr for next read */
2789 } else {
2790 if (br == 0 && bcount == (size - bcount))
2791 break;
2792 /* signal an error to the caller */
2793 errmsg = netstrerror(error);
2794 n_log(LOG_ERR, "Socket %d receive %d Error neterrno: %s", s, br, _str(errmsg));
2795 FreeNoLog(errmsg);
2796 return FALSE;
2797 }
2798 }
2799 return size;
2800} /*recv_php(...)*/
2801
2810int netw_get_queue_status(NETWORK* netw, size_t* nb_to_send, size_t* nb_to_read) {
2811 __n_assert(netw, return FALSE);
2812
2813 pthread_mutex_lock(&netw->sendbolt);
2814 (*nb_to_send) = netw->send_buf->nb_items;
2815 pthread_mutex_unlock(&netw->sendbolt);
2816
2817 pthread_mutex_lock(&netw->recvbolt);
2818 (*nb_to_read) = netw->recv_buf->nb_items;
2819 pthread_mutex_unlock(&netw->recvbolt);
2820
2821 return TRUE;
2822} /* get queue states */
2823
2829NETWORK_POOL* netw_new_pool(size_t nb_min_element) {
2830 NETWORK_POOL* netw_pool = NULL;
2831
2832 Malloc(netw_pool, NETWORK_POOL, 1);
2833 __n_assert(netw_pool, return NULL);
2834
2835 netw_pool->pool = new_ht(nb_min_element);
2836 __n_assert(netw_pool->pool, Free(netw_pool); return NULL);
2837
2838 init_lock(netw_pool->rwlock);
2839
2840 return netw_pool;
2841} /* netw_new_pool() */
2842
2849 __n_assert(netw_pool && (*netw_pool), return FALSE);
2850
2851 write_lock((*netw_pool)->rwlock);
2852 if ((*netw_pool)->pool)
2853 destroy_ht(&(*netw_pool)->pool);
2854 unlock((*netw_pool)->rwlock);
2855
2856 rw_lock_destroy((*netw_pool)->rwlock);
2857
2858 Free((*netw_pool));
2859
2860 return TRUE;
2861} /* netw_destroy_pool() */
2862
2867void netw_pool_netw_close(void* netw_ptr) {
2868 NETWORK* netw = (NETWORK*)netw_ptr;
2869 __n_assert(netw, return);
2870 n_log(LOG_DEBUG, "Network pool %p: network id %d still active !!", netw, netw->link.sock);
2871 return;
2872} /* netw_pool_netw_close() */
2873
2881 __n_assert(netw_pool, return FALSE);
2882 __n_assert(netw, return FALSE);
2883
2884 n_log(LOG_DEBUG, "Trying to add %lld to %p", (unsigned long long)netw->link.sock, netw_pool->pool);
2885
2886 /* write lock the pool */
2887 write_lock(netw_pool->rwlock);
2888 /* test if not already added */
2889 N_STR* key = NULL;
2890 nstrprintf(key, "%lld", (unsigned long long)netw->link.sock);
2891 HASH_NODE* node = NULL;
2892 if (ht_get_ptr(netw_pool->pool, _nstr(key), (void*)&node) == TRUE) {
2893 n_log(LOG_ERR, "Network id %d already added !", netw->link.sock);
2894 free_nstr(&key);
2895 unlock(netw_pool->rwlock);
2896 return FALSE;
2897 }
2898 int retval = FALSE;
2899 /* add it */
2900 if ((retval = ht_put_ptr(netw_pool->pool, _nstr(key), netw, &netw_pool_netw_close)) == TRUE) {
2901 if ((retval = list_push(netw->pools, netw_pool, NULL)) == TRUE) {
2902 n_log(LOG_DEBUG, "added netw %d to pool %p", netw->link.sock, netw_pool);
2903 } else {
2904 n_log(LOG_ERR, "could not add netw %d to pool %p", netw->link.sock, netw_pool);
2905 }
2906 } else {
2907 n_log(LOG_ERR, "could not add netw %d to pool %p", netw->link.sock, netw_pool);
2908 }
2909 free_nstr(&key);
2910
2911 /* unlock the pool */
2912 unlock(netw_pool->rwlock);
2913
2914 return retval;
2915} /* netw_pool_add() */
2916
2924 __n_assert(netw_pool, return FALSE);
2925 __n_assert(netw, return FALSE);
2926
2927 /* write lock the pool */
2928 write_lock(netw_pool->rwlock);
2929 /* test if present */
2930 N_STR* key = NULL;
2931 nstrprintf(key, "%lld", (unsigned long long int)netw->link.sock);
2932 if (ht_remove(netw_pool->pool, _nstr(key)) == TRUE) {
2933 LIST_NODE* node = list_search(netw->pools, netw);
2934 if (node) {
2935 if (!remove_list_node(netw->pools, node, NETWORK_POOL)) {
2936 n_log(LOG_ERR, "Network id %d could not be removed !", netw->link.sock);
2937 }
2938 }
2939 unlock(netw_pool->rwlock);
2940 n_log(LOG_DEBUG, "Network id %d removed !", netw->link.sock);
2941
2942 return TRUE;
2943 }
2944 free_nstr(&key);
2945 n_log(LOG_ERR, "Network id %d already removed !", netw->link.sock);
2946 /* unlock the pool */
2947 unlock(netw_pool->rwlock);
2948 return FALSE;
2949} /* netw_pool_remove */
2950
2958int netw_pool_broadcast(NETWORK_POOL* netw_pool, NETWORK* from, N_STR* net_msg) {
2959 __n_assert(netw_pool, return FALSE);
2960 __n_assert(net_msg, return FALSE);
2961
2962 /* write lock the pool */
2963 read_lock(netw_pool->rwlock);
2964 ht_foreach(node, netw_pool->pool) {
2965 NETWORK* netw = hash_val(node, NETWORK);
2966 if (from) {
2967 if (netw->link.sock != from->link.sock)
2968 netw_add_msg(netw, nstrdup(net_msg));
2969 } else {
2970 netw_add_msg(netw, nstrdup(net_msg));
2971 }
2972 }
2973 unlock(netw_pool->rwlock);
2974 return TRUE;
2975} /* netw_pool_broadcast */
2976
2983 __n_assert(netw_pool, return 0);
2984
2985 size_t nb = 0;
2986 read_lock(netw_pool->rwlock);
2987 nb = netw_pool->pool->nb_keys;
2988 unlock(netw_pool->rwlock);
2989
2990 return nb;
2991} /* netw_pool_nbclients() */
2992
3000 __n_assert(netw, return FALSE);
3001 netw->user_id = id;
3002 return TRUE;
3003} /* netw_set_user_id() */
3004
3014int netw_send_ping(NETWORK* netw, int type, int id_from, int id_to, int time) {
3015 N_STR* tmpstr = NULL;
3016 __n_assert(netw, return FALSE);
3017
3018 tmpstr = netmsg_make_ping(type, id_from, id_to, time);
3019 __n_assert(tmpstr, return FALSE);
3020
3021 return netw_add_msg(netw, tmpstr);
3022} /* netw_send_ping( ... ) */
3023
3033int netw_send_ident(NETWORK* netw, int type, int id, N_STR* name, N_STR* passwd) {
3034 N_STR* tmpstr = NULL;
3035
3036 __n_assert(netw, return FALSE);
3037
3038 tmpstr = netmsg_make_ident(type, id, name, passwd);
3039 __n_assert(tmpstr, return FALSE);
3040
3041 return netw_add_msg(netw, tmpstr);
3042} /* netw_send_ident( ... ) */
3043
3057int netw_send_position(NETWORK* netw, int id, double X, double Y, double vx, double vy, double acc_x, double acc_y, int time_stamp) {
3058 N_STR* tmpstr = NULL;
3059
3060 __n_assert(netw, return FALSE);
3061
3062 tmpstr = netmsg_make_position_msg(id, X, Y, vx, vy, acc_x, acc_y, time_stamp);
3063
3064 __n_assert(tmpstr, return FALSE);
3065
3066 return netw_add_msg(netw, tmpstr);
3067} /* netw_send_position( ... ) */
3068
3079int netw_send_string_to(NETWORK* netw, int id_to, N_STR* name, N_STR* chan, N_STR* txt, int color) {
3080 N_STR* tmpstr = NULL;
3081
3082 __n_assert(netw, return FALSE);
3083
3084 tmpstr = netmsg_make_string_msg(netw->user_id, id_to, name, chan, txt, color);
3085 __n_assert(tmpstr, return FALSE);
3086
3087 return netw_add_msg(netw, tmpstr);
3088} /* netw_send_string_to( ... ) */
3089
3099int netw_send_string_to_all(NETWORK* netw, N_STR* name, N_STR* chan, N_STR* txt, int color) {
3100 N_STR* tmpstr = NULL;
3101
3102 __n_assert(netw, return FALSE);
3103
3104 tmpstr = netmsg_make_string_msg(netw->user_id, -1, name, chan, txt, color);
3105 __n_assert(tmpstr, return FALSE);
3106
3107 return netw_add_msg(netw, tmpstr);
3108} /* netw_send_string_to_all( ... ) */
3109
3116 __n_assert(netw, return FALSE);
3117
3118 N_STR* tmpstr = NULL;
3119
3120 tmpstr = netmsg_make_quit_msg();
3121 __n_assert(tmpstr, return FALSE);
3122
3123 return netw_add_msg(netw, tmpstr);
3124} /* netw_send_quit( ... ) */
3125
3132size_t netw_calculate_urlencoded_size(const char* str, size_t len) {
3133 __n_assert(str, return 0);
3134
3135 size_t encoded_size = 0;
3136
3137 for (size_t i = 0; i < len; i++) {
3138 unsigned char c = (unsigned char)str[i];
3139 if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
3140 encoded_size += 1; // Safe character, no encoding needed
3141 } else {
3142 encoded_size += 3; // Unsafe character, will be encoded as %XX
3143 }
3144 }
3145
3146 return encoded_size;
3147}
3148
3155char* netw_urlencode(const char* str, size_t len) {
3156 __n_assert(str, return NULL);
3157
3158 static const char* hex = "0123456789ABCDEF";
3159 size_t encoded_size = netw_calculate_urlencoded_size(str, len);
3160 char* encoded = (char*)malloc(encoded_size + 1); // Allocate memory for the encoded string (+1 for the null terminator)
3161
3162 if (!encoded) {
3163 return NULL; // Return NULL if memory allocation fails
3164 }
3165
3166 char* pbuf = encoded;
3167
3168 for (size_t i = 0; i < len; i++) {
3169 unsigned char c = (unsigned char)str[i];
3170 if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
3171 *pbuf++ = (char)c; // Copy safe characters directly
3172 } else {
3173 *pbuf++ = '%'; // Encode unsafe characters as %XX
3174 *pbuf++ = hex[c >> 4];
3175 *pbuf++ = hex[c & 0xF];
3176 }
3177 }
3178
3179 *pbuf = '\0'; // Null-terminate the encoded string
3180 return encoded;
3181}
3182
3188char* netw_extract_http_request_type(const char* request) {
3189 __n_assert(request, return NULL);
3190 // Find the first space in the request string
3191 const char* space = strchr(request, ' ');
3192
3193 if (space == NULL) {
3194 // No space found, invalid request format
3195 return NULL;
3196 }
3197
3198 // Calculate the length of the request type
3199 size_t method_length = (size_t)(space - request);
3200
3201 // Allocate memory for the method string (+1 for the null terminator)
3202 char* method = (char*)malloc(method_length + 1);
3203
3204 if (method == NULL) {
3205 // Memory allocation failed
3206 return NULL;
3207 }
3208
3209 // Copy the request method to the allocated memory
3210 strncpy(method, request, method_length);
3211 method[method_length] = '\0'; // Null-terminate the string
3212
3213 return method;
3214}
3215
3222 NETWORK_HTTP_INFO info;
3223 info.content_length = 0;
3224 info.body = NULL;
3225 memset(info.content_type, 0, sizeof(info.content_type));
3226
3227 __n_assert(request, return info);
3228
3229 // Find Request-Type
3230 info.type = netw_extract_http_request_type(request);
3231
3232 // Find Content-Type header (Optional)
3233 const char* content_type_header = strstr(request, "Content-Type:");
3234 if (content_type_header) {
3235 const char* start = content_type_header + strlen("Content-Type: ");
3236 const char* end = strstr(start, "\r\n");
3237 if (end) {
3238 size_t length = (size_t)(end - start);
3239 strncpy(info.content_type, start, length);
3240 info.content_type[length] = '\0';
3241 }
3242 } else {
3243 // If no Content-Type header found, set default
3244 strncpy(info.content_type, "text/plain", sizeof(info.content_type) - 1);
3245 }
3246
3247 // Find Content-Length header (Optional)
3248 const char* content_length_header = strstr(request, "Content-Length:");
3249 if (content_length_header) {
3250 const char* start = content_length_header + strlen("Content-Length: ");
3251 errno = 0;
3252 unsigned long tmp_cl = strtoul(start, NULL, 10); /* parse once */
3253 int error = errno;
3254 // Handle out-of-range error (e.g., set a safe default or return an error)
3255 // Only when ULONG_MAX is larger than SIZE_MAX, to prevent a constant false comparison warning
3256#if ULONG_MAX > SIZE_MAX
3257 if (error == ERANGE || tmp_cl > SIZE_MAX) {
3258#else
3259 if (error == ERANGE) {
3260#endif
3261 n_log(LOG_ERR, "could not get content_length for request %p, returned %s", request, strerror(error));
3262 info.content_length = SIZE_MAX; /* clamp to the maximum supported value */
3263 } else {
3264 info.content_length = (size_t)tmp_cl;
3265 }
3266 }
3267
3268 // Find the start of the body (after \r\n\r\n)
3269 const char* body_start = strstr(request, "\r\n\r\n");
3270 if (body_start) {
3271 body_start += 4; // Skip the \r\n\r\n
3272
3273 // If there is a Content-Length, and it's greater than 0, copy the body
3274 if (info.content_length > 0) {
3275 info.body = malloc(info.content_length + 1); // Allocate memory for body
3276 if (info.body) {
3277 strncpy(info.body, body_start, info.content_length);
3278 info.body[info.content_length] = '\0'; // Null-terminate the body
3279 }
3280 }
3281 }
3282 return info;
3283}
3284
3291 FreeNoLog(http_request.body);
3292 FreeNoLog(http_request.type);
3293 return TRUE;
3294}
3295
3303int netw_get_url_from_http_request(const char* request, char* url, size_t size) {
3304 __n_assert(request && strlen(request) > 0, return FALSE);
3305 __n_assert(url && size > 1, return FALSE);
3306
3307 /* Default output */
3308 strncpy(url, "/", size - 1);
3309 url[size - 1] = '\0';
3310
3311 /* Example request line: "GET /path/to/resource HTTP/1.1" */
3312 const char* first_space = strchr(request, ' ');
3313 if (!first_space) {
3314 /* Malformed request, return default '/' */
3315 return FALSE;
3316 }
3317
3318 const char* second_space = strchr(first_space + 1, ' ');
3319 if (!second_space) {
3320 /* Malformed request, return default '/' */
3321 return FALSE;
3322 }
3323
3324 size_t len = (size_t)(second_space - first_space - 1);
3325 if (len >= size) {
3326 len = size - 1;
3327 }
3328
3329 strncpy(url, first_space + 1, len);
3330 url[len] = '\0'; /* Null-terminate the URL */
3331
3332 return TRUE;
3333}
3334
3340char* netw_urldecode(const char* str) {
3341 __n_assert(str, return NULL);
3342 char* decoded = malloc(strlen(str) + 1);
3343 __n_assert(decoded, return NULL);
3344
3345 char* p = decoded;
3346 while (*str) {
3347 if (*str == '%') {
3348 if (isxdigit((unsigned char)str[1]) && isxdigit((unsigned char)str[2])) {
3349 int value;
3350 if (sscanf(str + 1, "%2x", &value) >= 1) {
3351 *p++ = (char)value;
3352 str += 3;
3353 } else {
3354 n_log(LOG_ERR, "sscanf could not parse char *str (%p) for a %%2x", str);
3355 Free(decoded);
3356 return NULL;
3357 }
3358 } else {
3359 *p++ = *str++;
3360 }
3361 } else if (*str == '+') {
3362 *p++ = ' ';
3363 str++;
3364 } else {
3365 *p++ = *str++;
3366 }
3367 }
3368 *p = '\0';
3369 return decoded;
3370}
3371
3377HASH_TABLE* netw_parse_post_data(const char* post_data) {
3378 __n_assert(post_data, return NULL);
3379
3380 // Create a copy of the post_data string because strtok modifies the string
3381 char* data = strdup(post_data);
3382 __n_assert(data, return NULL);
3383
3384 char* pair = data;
3385 char* ampersand_pos;
3386
3387 HASH_TABLE* post_data_table = new_ht(32);
3388
3389 while (pair != NULL) {
3390 // Find the next key-value pair separated by '&'
3391 ampersand_pos = strchr(pair, '&');
3392
3393 // If found, replace it with '\0' to isolate the current pair
3394 if (ampersand_pos != NULL) {
3395 *ampersand_pos = '\0';
3396 }
3397
3398 // Now split each pair by '=' to get the key and value
3399 char* equal_pos = strchr(pair, '=');
3400 if (equal_pos != NULL) {
3401 *equal_pos = '\0'; // Terminate the key string
3402 char* key = pair;
3403 char* value = equal_pos + 1;
3404
3405 // Decode the value since POST data is URL-encoded
3406 char* decoded_value = netw_urldecode(value);
3407 ht_put_string(post_data_table, key, decoded_value);
3408 // printf("Key: %s, Value: %s\n", key, decoded_value);
3409 free(decoded_value);
3410 }
3411 // Move to the next key-value pair (if any)
3412 pair = (ampersand_pos != NULL) ? (ampersand_pos + 1) : NULL;
3413 }
3414 // Free the duplicated string
3415 free(data);
3416 return post_data_table;
3417}
3418
3424const char* netw_guess_http_content_type(const char* url) {
3425 __n_assert(url, return NULL);
3426
3427 // Create a copy of the URL to work on (to avoid modifying the original string)
3428 char url_copy[1024];
3429 strncpy(url_copy, url, sizeof(url_copy) - 1);
3430 url_copy[sizeof(url_copy) - 1] = '\0';
3431
3432 // Find if there is a '?' (indicating GET parameters) and terminate the string there
3433 char* query_start = strchr(url_copy, '?');
3434 if (query_start) {
3435 *query_start = '\0'; // Terminate the string before the query parameters
3436 }
3437
3438 // Find the last occurrence of a dot in the URL (file extension)
3439 const char* ext = strrchr(url_copy, '.');
3440
3441 // If no extension is found, return "unknown"
3442 if (!ext) {
3443 return "unknown";
3444 }
3445
3446 // Compare the extension to known content types
3447 if (strcmp(ext, ".html") == 0 || strcmp(ext, ".htm") == 0) {
3448 return "text/html";
3449 } else if (strcmp(ext, ".txt") == 0) {
3450 return "text/plain";
3451 } else if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0) {
3452 return "image/jpeg";
3453 } else if (strcmp(ext, ".png") == 0) {
3454 return "image/png";
3455 } else if (strcmp(ext, ".gif") == 0) {
3456 return "image/gif";
3457 } else if (strcmp(ext, ".css") == 0) {
3458 return "text/css";
3459 } else if (strcmp(ext, ".js") == 0) {
3460 return "application/javascript";
3461 } else if (strcmp(ext, ".json") == 0) {
3462 return "application/json";
3463 } else if (strcmp(ext, ".xml") == 0) {
3464 return "application/xml";
3465 } else if (strcmp(ext, ".pdf") == 0) {
3466 return "application/pdf";
3467 } else if (strcmp(ext, ".zip") == 0) {
3468 return "application/zip";
3469 } else if (strcmp(ext, ".mp4") == 0) {
3470 return "video/mp4";
3471 } else if (strcmp(ext, ".mp3") == 0) {
3472 return "audio/mpeg";
3473 } else if (strcmp(ext, ".wav") == 0) {
3474 return "audio/wav";
3475 } else if (strcmp(ext, ".ogg") == 0) {
3476 return "audio/ogg";
3477 }
3478
3479 // Return unknown for other types
3480 return "unknown";
3481}
3482
3488const char* netw_get_http_status_message(int status_code) {
3489 switch (status_code) {
3490 case 200:
3491 return "OK";
3492 case 204:
3493 return "No Content";
3494 case 304:
3495 return "Not Modified";
3496 case 404:
3497 return "Not Found";
3498 case 500:
3499 return "Internal Server Error";
3500 // Add more status codes as needed
3501 default:
3502 return "Unknown";
3503 }
3504}
3505
3512int netw_get_http_date(char* buffer, size_t buffer_size) {
3513 __n_assert(buffer, return FALSE);
3514 const time_t now = time(NULL);
3515 struct tm gmt;
3516#ifdef _WIN32
3517 if (gmtime_s(&gmt, &now) != 0) {
3518 n_log(LOG_ERR, "gmtime_s failed");
3519 return FALSE;
3520 }
3521#else
3522 if (!gmtime_r(&now, &gmt)) {
3523 n_log(LOG_ERR, "gmtime_r returned NULL");
3524 return FALSE;
3525 }
3526#endif
3527 if (strftime(buffer, buffer_size, "%a, %d %b %Y %H:%M:%S GMT", &gmt) == 0) {
3528 n_log(LOG_ERR, "strftime failed: buffer too small");
3529 return FALSE;
3530 }
3531 return TRUE;
3532}
3533
3544int 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) {
3545 __n_assert(server_name, return FALSE);
3546 __n_assert(content_type, return FALSE);
3547 __n_assert(additional_headers, return FALSE);
3548
3549 const char* status_message = netw_get_http_status_message(status_code);
3550 const char* connection_type = "close";
3551
3552 // Buffer for the date header
3553 char date_buffer[128] = "";
3554 netw_get_http_date(date_buffer, sizeof(date_buffer));
3555
3556 if ((*http_response)) {
3557 (*http_response)->written = 0;
3558 }
3559
3560 if (!body || body->written == 0) {
3561 // Handle the case where there is no body
3562 nstrprintf((*http_response),
3563 "HTTP/1.1 %d %s\r\n"
3564 "Date: %s\r\n"
3565 "Server: %s\r\n"
3566 "Content-Length: 0\r\n"
3567 "%s"
3568 "Connection: %s\r\n\r\n",
3569 status_code, status_message, date_buffer, server_name, additional_headers, connection_type);
3570 n_log(LOG_DEBUG, "empty response");
3571 } else {
3572 // Build the response with body
3573 nstrprintf((*http_response),
3574 "HTTP/1.1 %d %s\r\n"
3575 "Date: %s\r\n"
3576 "Server: %s\r\n"
3577 "Content-Type: %s\r\n"
3578 "Content-Length: %zu\r\n"
3579 "%s"
3580 "Connection: %s\r\n\r\n",
3581 status_code, status_message, date_buffer, server_name, content_type, body->written, additional_headers, connection_type);
3582 nstrcat((*http_response), body);
3583 n_log(LOG_DEBUG, "body response");
3584 }
3585 return TRUE;
3586}
int DONE
Definition ex_fluid.c:41
int mode
Network for managing conenctions.
Definition ex_network.c:22
NETWORK * netw
Network for server mode, accepting incomming.
Definition ex_network.c:20
char * key
int ip_version
char * addr
char * port
#define init_lock(__rwlock_mutex)
Macro for initializing a rwlock.
Definition n_common.h:329
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:249
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:185
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:256
#define _str(__PTR)
define true
Definition n_common.h:174
#define rw_lock_destroy(__rwlock_mutex)
Macro to destroy rwlock mutex.
Definition n_common.h:388
#define CALL_RETRY(__retvar, __expression, __max_tries, __delay)
TEMP_FAILURE gnu macro portable version.
Definition n_common.h:263
#define unlock(__rwlock_mutex)
Macro for releasing read/write lock a rwlock mutex.
Definition n_common.h:375
#define write_lock(__rwlock_mutex)
Macro for acquiring a write lock on a rwlock mutex.
Definition n_common.h:361
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:240
#define read_lock(__rwlock_mutex)
Macro for acquiring a read lock on a rwlock mutex.
Definition n_common.h:347
#define _nstr(__PTR)
N_STR or "NULL" string for logging purposes.
Definition n_common.h:180
#define N_ENUM_DEFINE(MACRO_DEFINITION, enum_name)
Macro to define an N_ENUM.
Definition n_enum.h:144
#define N_ENUM_ENTRY(class, method)
helper to build an N_ENUM
Definition n_enum.h:27
size_t nb_keys
total number of used keys in the table
Definition n_hash.h:121
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
Definition n_hash.c:2015
#define ht_foreach(__ITEM_, __HASH_)
ForEach macro helper (classic / old)
Definition n_hash.h:171
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
Definition n_hash.c:2148
int ht_remove(HASH_TABLE *table, const char *key)
remove and delete node at key in table
Definition n_hash.c:2106
HASH_TABLE * new_ht(size_t size)
Create a hash table with the given size.
Definition n_hash.c:1916
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:2081
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:2068
#define hash_val(node, type)
Cast a HASH_NODE element.
Definition n_hash.h:167
structure of a hash table node
Definition n_hash.h:93
structure of a hash table
Definition n_hash.h:117
size_t nb_items
number of item currently in the list
Definition n_list.h:42
#define list_shift(__LIST_, __TYPE_)
Shift macro helper for void pointer casting.
Definition n_list.h:75
int list_empty(LIST *list)
Empty a LIST list of pointers.
Definition n_list.c:472
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:200
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper.
Definition n_list.h:66
#define remove_list_node(__LIST_, __NODE_, __TYPE_)
Remove macro helper for void pointer casting.
Definition n_list.h:77
int list_destroy(LIST **list)
Empty and Free a list container.
Definition n_list.c:519
LIST_NODE * list_search(LIST *list, void *ptr)
search ptr in list
Definition n_list.c:441
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Definition n_list.c:19
#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:56
Structure of a generic list node.
Definition n_list.h:25
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:70
#define LOG_DEBUG
debug-level messages
Definition n_log.h:65
#define LOG_ERR
error conditions
Definition n_log.h:57
#define LOG_INFO
informational
Definition n_log.h:63
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:225
N_SOCKET link
networking socket
Definition n_network.h:305
char * certificate
openssl certificate file
Definition n_network.h:299
int threaded_engine_status
Threaded network engine state for this network.
Definition n_network.h:245
size_t content_length
Definition n_network.h:346
pthread_t send_thr
sending thread
Definition n_network.h:313
int nb_pending
Nb pending connection,if listening.
Definition n_network.h:241
int so_reuseaddr
so reuseaddr state
Definition n_network.h:251
pthread_t recv_thr
receiving thread
Definition n_network.h:315
pthread_rwlock_t rwlock
thread safety
Definition n_network.h:337
struct sockaddr_storage raddr
connected remote addr
Definition n_network.h:235
pthread_mutex_t eventbolt
mutex for threaded access of state event
Definition n_network.h:322
const SSL_METHOD * method
SSL method container.
Definition n_network.h:293
int deplete_socket_timeout
deplete socket send buffer timeout ( 0 disabled, > 0 wait for timeout and check unset/unack datas)
Definition n_network.h:279
int deplete_queues_timeout
deplete network queues timeout ( 0 disabled, > 0 wait for timeout and check unset/unack datas)
Definition n_network.h:277
int nb_running_threads
nb running threads, if > 0 thread engine is still running
Definition n_network.h:275
pthread_mutex_t recvbolt
mutex for threaded access of recv buf
Definition n_network.h:320
pthread_mutex_t sendbolt
mutex for threaded access of send_buf
Definition n_network.h:318
int send_queue_consecutive_wait
send queue consecutive pool interval, used when there are still items to send, in usec
Definition n_network.h:249
int so_rcvtimeo
send timeout value
Definition n_network.h:265
int tcpnodelay
state of naggle algorythm, 0 untouched, 1 forcibly disabled
Definition n_network.h:257
SOCKET sock
a normal socket
Definition n_network.h:223
char * port
port of socket
Definition n_network.h:221
LIST * recv_buf
reveicing buffer (for incomming usage)
Definition n_network.h:310
int user_id
if part of a user property, id of the user
Definition n_network.h:273
sem_t send_blocker
block sending func
Definition n_network.h:324
SSL_CTX * ctx
SSL context holder.
Definition n_network.h:295
int so_sndbuf
size of the socket send buffer, 0 untouched, else size in bytes
Definition n_network.h:259
int so_sndtimeo
send timeout value
Definition n_network.h:263
char content_type[256]
Definition n_network.h:344
struct addrinfo hints
address of local machine
Definition n_network.h:231
int so_keepalive
so keepalive state
Definition n_network.h:255
netw_func send_data
send func ptr
Definition n_network.h:287
int addr_infos_loaded
Internal flag to know if we have to free addr infos.
Definition n_network.h:247
uint32_t state
state of the connection , NETW_RUN, NETW_QUIT, NETW_STOP , NETW_ERR
Definition n_network.h:284
LIST * pools
pointers to network pools if members of any
Definition n_network.h:327
char * key
openssl key file
Definition n_network.h:301
SSL * ssl
SSL handle.
Definition n_network.h:297
int so_linger
close lingering value (-1 disabled, 0 force close, >0 linger )
Definition n_network.h:267
unsigned long int is_blocking
flag to quickly check socket mode
Definition n_network.h:228
int crypto_algo
if encryption is on, which one (flags NETW_ENCRYPT_*)
Definition n_network.h:271
HASH_TABLE * pool
table of clients
Definition n_network.h:334
LIST * send_buf
sending buffer (for outgoing queuing )
Definition n_network.h:308
int mode
NETWORK mode , 1 listening, 0 connecting.
Definition n_network.h:243
int so_rcvbuf
size of the socket recv buffer, 0 untouched, else size in bytes
Definition n_network.h:261
netw_func recv_data
receive func ptr
Definition n_network.h:289
int wait_close_timeout
network wait close timeout value ( < 1 disabled, >= 1 timeout sec )
Definition n_network.h:281
#define NETW_SOCKET_ERROR
code for a socekt error
Definition n_network.h:45
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:3099
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:2958
N_STR * netw_get_msg(NETWORK *netw)
Get a message from aimed NETWORK.
Definition n_network.c:1997
int netw_add_msg(NETWORK *netw, N_STR *msg)
Add a message to send in aimed NETWORK.
Definition n_network.c:1930
ssize_t send_ssl_data(void *netw, char *buf, uint32_t n)
send data onto the socket
Definition n_network.c:2483
char * netw_extract_http_request_type(const char *request)
function to extract the request method from an http request
Definition n_network.c:3188
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:2810
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:2616
int netw_stop_thr_engine(NETWORK *netw)
Stop a NETWORK connection sending and receing thread.
Definition n_network.c:2342
char * netw_urlencode(const char *str, size_t len)
function to perform URL encoding
Definition n_network.c:3155
void * netw_send_func(void *NET)
Thread send function.
Definition n_network.c:2104
NETWORK * netw_accept_nonblock_from(NETWORK *from, int blocking)
make a normal blocking 'accept' .
Definition n_network.c:1920
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:3303
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:31
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:3512
NETWORK_POOL * netw_new_pool(size_t nb_min_element)
return a new network pool of nb_min_element
Definition n_network.c:2829
int netw_set_user_id(NETWORK *netw, int id)
associate an id and a network
Definition n_network.c:2999
ssize_t recv_data(void *netw, char *buf, uint32_t n)
recv data from the socket
Definition n_network.c:2432
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:2549
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:41
int netw_start_thr_engine(NETWORK *netw)
Start the NETWORK netw Threaded Engine.
Definition n_network.c:2069
int netw_destroy_pool(NETWORK_POOL **netw_pool)
free a NETWORK_POOL *pool
Definition n_network.c:2848
#define NETWORK_IPV4
Flag to force IPV4
Definition n_network.h:29
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:3544
void * netw_recv_func(void *NET)
To Thread Receiving function.
Definition n_network.c:2225
__netw_code_type 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:43
size_t ntohst(size_t value)
network to host size_t
Definition n_network.c:47
#define NETWORK_CONSECUTIVE_SEND_WAIT
Flag to set consecutive send waiting timeout
Definition n_network.h:37
size_t netw_pool_nbclients(NETWORK_POOL *netw_pool)
return the number of networks in netw_pool
Definition n_network.c:2982
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 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)
Use this to connect a NETWORK to any listening one.
Definition n_network.c:1222
int SOCKET
default socket declaration
Definition n_network.h:64
#define NETW_SOCKET_DISCONNECTED
Code for a disconnected recv.
Definition n_network.h:47
#define NETWORK_WAIT_CLOSE_TIMEOUT
Flag to set network closing wait timeout.
Definition n_network.h:39
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:2381
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:2867
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:3132
#define NETW_RETRY_DELAY
Send or recv delay between retries in usec.
Definition n_network.h:51
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:1910
#define NETW_MAX_RETRIES
Send or recv max number of retries.
Definition n_network.h:49
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:3115
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:3488
int netw_set_blocking(NETWORK *netw, unsigned long int is_blocking)
Modify blocking socket mode.
Definition n_network.c:739
N_STR * netw_wait_msg(NETWORK *netw, unsigned int refresh, size_t timeout)
Wait a message from aimed NETWORK.
Definition n_network.c:2018
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:3079
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:3014
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:3221
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:213
#define NETWORK_DEPLETE_SOCKET_TIMEOUT
Flag to set send buffer depletion timeout
Definition n_network.h:33
int netw_send_ident(NETWORK *netw, int type, int id, N_STR *name, N_STR *passwd)
Add a formatted NETWMSG_IDENT message to the specified network.
Definition n_network.c:3033
char * netw_urldecode(const char *str)
Function to decode URL-encoded data.
Definition n_network.c:3340
#define NETWORK_DEPLETE_QUEUES_TIMEOUT
Flag to set network queues depletion timeout
Definition n_network.h:35
int netw_pool_add(NETWORK_POOL *netw_pool, NETWORK *netw)
add a NETWORK *netw to a NETWORK_POOL *pool
Definition n_network.c:2880
int netw_info_destroy(NETWORK_HTTP_INFO http_request)
destroy a NETWORK_HTTP_INFO loaded informations
Definition n_network.c:3290
HASH_TABLE * netw_parse_post_data(const char *post_data)
Function to parse POST data.
Definition n_network.c:3377
const char * netw_guess_http_content_type(const char *url)
function to guess the content type based on URL extension
Definition n_network.c:3424
ssize_t recv_php(SOCKET s, int *_code, char **buf)
recv data from the socket
Definition n_network.c:2699
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:3057
int netw_pool_remove(NETWORK_POOL *netw_pool, NETWORK *netw)
remove a NETWORK *netw to a NETWORK_POOL *pool
Definition n_network.c:2923
int netw_add_msg_ex(NETWORK *netw, char *str, unsigned int length)
Add a message to send in aimed NETWORK.
Definition n_network.c:1961
@ NETW_DESTROY_RECVBUF
Definition n_network.h:213
@ NETW_ENCRYPT_OPENSSL
Definition n_network.h:213
@ NETW_THR_ENGINE_STARTED
Definition n_network.h:213
@ NETW_SERVER
Definition n_network.h:213
@ NETW_EMPTY_SENDBUF
Definition n_network.h:213
@ NETW_DESTROY_SENDBUF
Definition n_network.h:213
@ NETW_THR_ENGINE_STOPPED
Definition n_network.h:213
@ NETW_RUN
Definition n_network.h:213
@ NETW_CLIENT
Definition n_network.h:213
@ NETW_EMPTY_RECVBUF
Definition n_network.h:213
@ NETW_EXITED
Definition n_network.h:213
@ NETW_ERROR
Definition n_network.h:213
@ NETW_EXIT_ASKED
Definition n_network.h:213
@ NETW_ENCRYPT_NONE
Definition n_network.h:213
Structure of a NETWORK.
Definition n_network.h:239
structure for splitting HTTP requests
Definition n_network.h:342
structure of a network pool
Definition n_network.h:332
Hash functions and table.
Generic log system.
__attribute__((unused))
Definition n_network.c:1071
static void netw_init_locks(void)
Definition n_network.c:1088
void netw_ssl_print_errors(SOCKET socket)
Definition n_network.c:1025
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
N_ENUM_netw_code_type
network error code
Definition n_network.c:23
#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
static pthread_mutex_t * netw_ssl_lockarray
Definition n_network.c:1069
char * get_in_addr(struct sockaddr *sa)
get sockaddr, IPv4 or IPv6
Definition n_network.c:680
char * netw_get_openssl_error_string()
Definition n_network.c:1002
static void netw_kill_locks(void)
Definition n_network.c:1102
Network Engine.
Network messages , serialization tools.