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));
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));
66char* wchar_to_char(
const wchar_t* pwchar) {
68 int currentCharIndex = 0;
69 char currentChar = pwchar[currentCharIndex];
70 char* filePathC = NULL;
72 while (currentChar !=
'\0') {
74 currentChar = pwchar[currentCharIndex];
77 const int charCount = currentCharIndex + 1;
80 Malloc(filePathC,
char, charCount);
83 for (
int i = 0; i < charCount; i++) {
85 char character = pwchar[i];
87 *filePathC = character;
89 filePathC +=
sizeof(char);
93 filePathC -= (
sizeof(char) * charCount);
99#define neterrno WSAGetLastError()
102#define netstrerror(code) ({ \
104 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
106 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), \
107 (LPWSTR) & s, 0, NULL); \
108 char* netstr = wchar_to_char(s); \
113#if __GNUC__ <= 6 && __GNUC_MINOR__ <= 3
147size_t strlcpy(
char* dst,
const char* src,
size_t siz) {
155 if ((*d++ = *s++) ==
'\0')
167 return (s - src - 1);
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);
203char* inet_ntop(
int af,
const void* src,
char* dst, socklen_t size) {
206 return (inet_ntop4((
const unsigned char*)src, dst, size));
208 return (inet_ntop6((
const unsigned char*)src, dst, size));
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"];
231 l = snprintf(tmp,
sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
232 if (l <= 0 || (socklen_t)l >= size) {
235 strlcpy(dst, tmp, size);
245static char* inet_ntop6(
const unsigned char* src,
char* dst, socklen_t size) {
253 char tmp[
sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
258#define NS_IN6ADDRSZ 16
260 u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
268 memset(words,
'\0',
sizeof words);
269 for (i = 0; i < NS_IN6ADDRSZ; i++)
270 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
275 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
278 cur.base = i, cur.len = 1;
282 if (cur.base != -1) {
283 if (best.base == -1 || cur.len > best.len)
289 if (cur.base != -1) {
290 if (best.base == -1 || cur.len > best.len)
293 if (best.base != -1 && best.len < 2)
300 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
302 if (best.base != -1 && i >= best.base &&
303 i < (best.base + best.len)) {
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)))
318 tp += sprintf(tp,
"%x", words[i]);
321 if (best.base != -1 && (best.base + best.len) ==
322 (NS_IN6ADDRSZ / NS_INT16SZ))
329 if ((socklen_t)(tp - tmp) > size) {
358static int inet_pton4(
const char* src, u_char* dst);
359static int inet_pton6(
const char* src, u_char* dst);
372int inet_pton(
int af,
const char* src,
void* dst) {
375 return (inet_pton4(src, (
unsigned char*)dst));
377 return (inet_pton6(src, (
unsigned char*)dst));
394static int inet_pton4(
const char* src, u_char* dst) {
395 static const char digits[] =
"0123456789";
396 int saw_digit, octets, ch;
398 u_char tmp[NS_INADDRSZ], *tp;
403 while ((ch = *src++) !=
'\0') {
406 if ((pch = strchr(digits, ch)) != NULL) {
407 u_int uiNew = *tp * 10 + (pch - digits);
409 if (saw_digit && *tp == 0)
419 }
else if (ch ==
'.' && saw_digit) {
429 memcpy(dst, tmp, NS_INADDRSZ);
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
451 u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
453 int ch, seen_xdigits;
456 memset((tp = tmp),
'\0', NS_IN6ADDRSZ);
457 endp = tp + NS_IN6ADDRSZ;
466 while ((ch = *src++) !=
'\0') {
467 const char* xdigits :
const char* pch;
469 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
470 pch = strchr((xdigits = xdigits_u), ch);
473 val |= (pch - xdigits);
474 if (++seen_xdigits > 4)
485 }
else if (*src ==
'\0') {
488 if (tp + NS_INT16SZ > endp)
490 *tp++ = (u_char)(val >> 8) & 0xff;
491 *tp++ = (u_char)val & 0xff;
496 if (ch ==
'.' && ((tp + NS_INADDRSZ) <= endp) &&
497 inet_pton4(curtok, tp) > 0) {
505 if (tp + NS_INT16SZ > endp)
507 *tp++ = (u_char)(val >> 8) & 0xff;
508 *tp++ = (u_char)val & 0xff;
510 if (colonp != NULL) {
515 const int n = tp - colonp;
520 for (i = 1; i <= n; i++) {
521 endp[-i] = colonp[n - i];
528 memcpy(dst, tmp, NS_IN6ADDRSZ);
536#include <sys/types.h>
540#define neterrno errno
555#define netstrerror(code) ({ \
556 char* __errmsg = NULL; \
558 __errmsg = strdup(strerror(code)); \
559 if (errno == ENOMEM) { \
555#define netstrerror(code) ({ \ …
584 netw->
state = NETW_EXITED;
591 memset(&netw->
link.
hints, 0,
sizeof(
struct addrinfo));
592 memset(&netw->
link.
raddr, 0,
sizeof(
struct sockaddr_storage));
595 if (pthread_mutex_init(&netw->
sendbolt, NULL) != 0) {
601 if (pthread_mutex_init(&netw->
recvbolt, NULL) != 0) {
603 pthread_mutex_destroy(&netw->
sendbolt);
608 if (pthread_mutex_init(&netw->
eventbolt, NULL) != 0) {
610 pthread_mutex_destroy(&netw->
sendbolt);
611 pthread_mutex_destroy(&netw->
recvbolt);
619 pthread_mutex_destroy(&netw->
sendbolt);
620 pthread_mutex_destroy(&netw->
recvbolt);
625 netw->
recv_buf = new_generic_list(recv_list_limit);
627 n_log(
LOG_ERR,
"Error when creating receive list with %d item limit", recv_list_limit);
631 netw->
send_buf = new_generic_list(send_list_limit);
633 n_log(
LOG_ERR,
"Error when creating send list with %d item limit", send_list_limit);
681 return sa->sa_family == AF_INET
682 ? (
char*)&(((
struct sockaddr_in*)sa)->sin_addr)
683 : (
char*)&(((
struct sockaddr_in6*)sa)->sin6_addr);
694 int compiler_warning_suppressor = 0;
695#if !defined(__linux__) && !defined(__sun) && !defined(_AIX)
696 static WSADATA WSAdata;
697 static int WSA_IS_INITIALIZED = 0;
703 return WSA_IS_INITIALIZED;
707 if (WSA_IS_INITIALIZED == 1)
709 if ((WSAStartup(MAKEWORD(v1, v2), &WSAdata)) != 0) {
710 WSA_IS_INITIALIZED = 0;
713 WSA_IS_INITIALIZED = 1;
719 if (WSA_IS_INITIALIZED == 0)
721 if (WSACleanup() == 0) {
722 WSA_IS_INITIALIZED = 0;
728 compiler_warning_suppressor = mode + v1 + v2;
729 compiler_warning_suppressor = TRUE;
730 return compiler_warning_suppressor;
745#if defined(__linux__) || defined(__sun)
747 flags = fcntl(netw->
link.
sock, F_GETFL, 0);
749 if ((flags & O_NONBLOCK) && !is_blocking) {
756 if (!(flags & O_NONBLOCK) && is_blocking) {
763 if (fcntl(netw->
link.
sock, F_SETFL, is_blocking ? flags ^ O_NONBLOCK : flags | O_NONBLOCK) == -1) {
771 unsigned long int blocking = 1 - is_blocking;
772 int res = ioctlsocket(netw->
link.
sock, FIONBIO, &blocking);
774 if (res != NO_ERROR) {
776 n_log(
LOG_ERR,
"ioctlsocket failed with error: %ld , neterrno: %s", res,
_str(errmsg));
804 if (setsockopt(netw->
link.
sock, IPPROTO_TCP, TCP_NODELAY, (
const char*)&value,
sizeof(value)) == -1) {
817 if (setsockopt(netw->
link.
sock, SOL_SOCKET, SO_SNDBUF, (
const char*)&value,
sizeof(value)) == -1) {
829 if (setsockopt(netw->
link.
sock, SOL_SOCKET, SO_RCVBUF, (
const char*)&value,
sizeof(value)) == -1) {
841 if (setsockopt(netw->
link.
sock, SOL_SOCKET, SO_REUSEADDR, (
char*)&value,
sizeof(value)) == -1) {
867 }
else if (value == 0) {
872 ling.l_linger = value;
875 if (setsockopt(netw->
link.
sock, SOL_SOCKET, SO_LINGER, &ling,
sizeof(ling)) == -1) {
883 if (setsockopt(netw->
link.
sock, SOL_SOCKET, SO_LINGER, (
const char*)&ling,
sizeof(ling)) == -1) {
900 if (setsockopt(netw->
link.
sock, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&tv,
sizeof tv) == -1) {
909 if (setsockopt(netw->
link.
sock, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&value,
sizeof value) == -1) {
928 if (setsockopt(netw->
link.
sock, SOL_SOCKET, SO_SNDTIMEO, (
const char*)&tv,
sizeof tv) == -1) {
937 if (setsockopt(netw->
link.
sock, SOL_SOCKET, SO_SNDTIMEO, (
const char*)&value,
sizeof value) == -1) {
961 case TCP_USER_TIMEOUT:
963 if (setsockopt(netw->
link.
sock, IPPROTO_TCP, TCP_USER_TIMEOUT, (
const char*)&value,
sizeof value) == -1) {
966 n_log(
LOG_ERR,
"Error from setsockopt(TCP_USER_TIMEOUT) on socket %d. neterrno: %s", netw->
link.
sock,
_str(errmsg));
973 if (setsockopt(netw->
link.
sock, IPPROTO_TCP, TCP_QUICKACK, &value,
sizeof(value)) < 0) {
976 n_log(
LOG_ERR,
"Error setting setsockopt(TCP_QUICKACK) to %d on sock %d. neterrno: %s", value, netw->
link.
sock,
_str(errmsg));
983 if (setsockopt(netw->
link.
sock, SOL_SOCKET, SO_KEEPALIVE, (
const char*)&value,
sizeof value) == -1) {
994 n_log(
LOG_ERR,
"%d is not a supported setsockopt", optname);
1002char* netw_get_openssl_error_string() {
1003 BIO* bio = BIO_new(BIO_s_mem());
1008 ERR_print_errors(bio);
1011 size_t len = (size_t)BIO_get_mem_data(bio, &buf);
1014 char* error_str = malloc(len + 1);
1016 memcpy(error_str, buf, len);
1017 error_str[len] =
'\0';
1025void netw_ssl_print_errors(
SOCKET socket) {
1026 unsigned long error = 0;
1027 while ((error = ERR_get_error())) {
1028 n_log(
LOG_ERR,
"socket %d: %s", socket, ERR_reason_error_string(error));
1069static pthread_mutex_t* netw_ssl_lockarray;
1071__attribute__((unused))
static void netw_ssl_lock_callback(
int mode,
int type,
char* file,
int line) {
1074 if (mode & CRYPTO_LOCK) {
1075 pthread_mutex_lock(&(netw_ssl_lockarray[type]));
1077 pthread_mutex_unlock(&(netw_ssl_lockarray[type]));
1081__attribute__((unused))
static unsigned long thread_id(
void) {
1084 ret = (
unsigned long)pthread_self();
1088static void netw_init_locks(
void) {
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)));
1094 for (i = 0; i < CRYPTO_num_locks(); i++) {
1095 pthread_mutex_init(&(netw_ssl_lockarray[i]), NULL);
1098 CRYPTO_set_id_callback((
unsigned long (*)())thread_id);
1099 CRYPTO_set_locking_callback((
void (*)())netw_ssl_lock_callback);
1102static void netw_kill_locks(
void) {
1105 CRYPTO_set_locking_callback(NULL);
1106 for (i = 0; i < CRYPTO_num_locks(); i++)
1107 pthread_mutex_destroy(&(netw_ssl_lockarray[i]));
1109 OPENSSL_free(netw_ssl_lockarray);
1117 static int OPENSSL_IS_INITIALIZED = 0;
1119 if (OPENSSL_IS_INITIALIZED == 1)
1123 SSL_load_error_strings();
1125#if OPENSSL_VERSION_NUMBER < 0x10100000L
1126 ERR_load_BIO_strings();
1128 OpenSSL_add_all_algorithms();
1131 OPENSSL_IS_INITIALIZED = 1;
1141 static int OPENSSL_IS_INITIALIZED = 0;
1143 if (OPENSSL_IS_INITIALIZED == 0)
1149 OPENSSL_IS_INITIALIZED = 0;
1163 if (key && strlen(key) > 0) {
1164 netw->
key = strdup(key);
1166 if (certificate && strlen(certificate) > 0) {
1169 if (key && certificate) {
1171#if OPENSSL_VERSION_NUMBER >= 0x10100000L
1172 netw->
method = TLS_method();
1174 netw->
method = TLSv1_2_method();
1179 if (netw->
ctx == NULL) {
1180 netw_ssl_print_errors(netw->
link.
sock);
1185 if (SSL_CTX_load_verify_locations(netw->
ctx, NULL,
"/etc/ssl/certs/") != 1) {
1186 netw_ssl_print_errors(netw->
link.
sock);
1190 if (SSL_CTX_use_certificate_file(netw->
ctx, certificate, SSL_FILETYPE_PEM) <= 0) {
1191 netw_ssl_print_errors(netw->
link.
sock);
1194 if (SSL_CTX_use_PrivateKey_file(netw->
ctx, key, SSL_FILETYPE_PEM) <= 0) {
1195 netw_ssl_print_errors(netw->
link.
sock);
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) {
1225 (void)ssl_cert_file;
1226 int error = 0, net_status = 0;
1227 char* errmsg = NULL;
1231 n_log(
LOG_ERR,
"Unable to allocate (*netw), already existing. You must use empty NETWORK *structs.");
1236 (*netw) =
netw_new(send_list_limit, recv_list_limit);
1248 (*netw)->link.hints.ai_family = AF_INET;
1250 (*netw)->link.hints.ai_family = AF_INET6;
1253 (*netw)->link.hints.ai_family = AF_UNSPEC;
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;
1265 error = getaddrinfo(host, port, &(*netw)->link.hints, &(*netw)->link.rhost);
1267 n_log(
LOG_ERR,
"Error when resolving %s:%s getaddrinfo: %s", host, port, gai_strerror(error));
1271 (*netw)->addr_infos_loaded = 1;
1272 Malloc((*netw)->link.ip,
char, 64);
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);
1287 (*netw)->link.sock = sock;
1289 net_status = connect(sock, rp->ai_addr, rp->ai_addrlen);
1290 if (net_status == -1) {
1296 (*netw)->link.sock = -1;
1300 if (!inet_ntop(rp->ai_family,
get_in_addr(rp->ai_addr), (*netw)->link.ip, 64)) {
1311 n_log(
LOG_ERR,
"Couldn't connect to %s:%s : no address succeeded", host, port);
1316 (*netw)->link.port = strdup(port);
1319 if (ssl_key_file && ssl_cert_file) {
1328 (*netw)->ssl = SSL_new((*netw)->ctx);
1329 SSL_set_fd((*netw)->ssl, (*netw)->link.sock);
1332 if (SSL_connect((*netw)->ssl) <= 0) {
1338 n_log(
LOG_DEBUG,
"SSL-Connected to %s:%s", (*netw)->link.ip, (*netw)->link.port);
1340 n_log(
LOG_ERR,
"%s:%s trying to configure SSL but application was compiled without SSL support !", (*netw)->link.ip, (*netw)->link.port);
1343 n_log(
LOG_DEBUG,
"Connected to %s:%s", (*netw)->link.ip, (*netw)->link.port);
1346 netw_set((*netw), NETW_CLIENT | NETW_RUN | NETW_THR_ENGINE_STOPPED);
1390 pthread_mutex_lock(&netw->
sendbolt);
1392 (*state) = netw->
state;
1393 if (thr_engine_status)
1395 pthread_mutex_unlock(&netw->
sendbolt);
1410 if (flag & NETW_EMPTY_SENDBUF) {
1411 pthread_mutex_lock(&netw->
sendbolt);
1414 pthread_mutex_unlock(&netw->
sendbolt);
1416 if (flag & NETW_EMPTY_RECVBUF) {
1417 pthread_mutex_lock(&netw->
recvbolt);
1420 pthread_mutex_unlock(&netw->
recvbolt);
1422 if (flag & NETW_DESTROY_SENDBUF) {
1423 pthread_mutex_lock(&netw->
sendbolt);
1426 pthread_mutex_unlock(&netw->
sendbolt);
1428 if (flag & NETW_DESTROY_RECVBUF) {
1429 pthread_mutex_lock(&netw->
recvbolt);
1432 pthread_mutex_unlock(&netw->
recvbolt);
1435 if (flag & NETW_CLIENT) {
1436 netw->
mode = NETW_CLIENT;
1438 if (flag & NETW_SERVER) {
1439 netw->
mode = NETW_SERVER;
1441 if (flag & NETW_RUN) {
1442 netw->
state = NETW_RUN;
1444 if (flag & NETW_EXITED) {
1445 netw->
state = NETW_EXITED;
1447 if (flag & NETW_ERROR) {
1448 netw->
state = NETW_ERROR;
1450 if (flag & NETW_EXIT_ASKED) {
1451 netw->
state = NETW_EXIT_ASKED;
1453 if (flag & NETW_THR_ENGINE_STARTED) {
1456 if (flag & NETW_THR_ENGINE_STOPPED) {
1473#if defined(__linux__)
1474 int outstanding = 0;
1478 for (
int it = 0; it < timeout; it += 100) {
1480 if (ioctl(fd, SIOCOUTQ, &outstanding) == -1) {
1482 n_log(
LOG_ERR,
"ioctl SIOCOUTQ returned -1: %s for socket %d", strerror(error), fd);
1506 int thr_engine_status = 0;
1510 if ((*netw)->deplete_queues_timeout > 0) {
1511 countdown = (*netw)->deplete_queues_timeout * 1000000;
1513 if (thr_engine_status == NETW_THR_ENGINE_STARTED) {
1515 pthread_mutex_lock(&(*netw)->eventbolt);
1516 nb_running = (*netw)->nb_running_threads;
1517 pthread_mutex_unlock(&(*netw)->eventbolt);
1519 if (countdown < 100000)
1522 countdown -= 100000;
1523 }
while (nb_running > 0 && countdown > 0);
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);
1531 if ((*netw)->link.sock != INVALID_SOCKET) {
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);
1545 if (thr_engine_status == NETW_THR_ENGINE_STARTED) {
1549 if ((*netw)->link.sock != INVALID_SOCKET) {
1551 if ((*netw)->crypto_algo == NETW_ENCRYPT_OPENSSL) {
1553 int shutdown_res = SSL_shutdown((*netw)->ssl);
1554 if (shutdown_res == 0) {
1556 shutdown_res = SSL_shutdown((*netw)->ssl);
1558 if (shutdown_res < 0) {
1559 int err = SSL_get_error((*netw)->ssl, shutdown_res);
1562 SSL_shutdown((*netw)->ssl);
1563 SSL_free((*netw)->ssl);
1565 n_log(
LOG_ERR,
"SSL handle of socket %d was already NULL", (*netw)->link.sock);
1571 shutdown((*netw)->link.sock, SHUT_WR);
1573 if ((*netw)->wait_close_timeout > 0) {
1575 char buffer[4096] =
"";
1577 for (
int it = 0; it < ((*netw)->wait_close_timeout * 1000000); it += 100000) {
1578 ssize_t res = recv((*netw)->link.sock, buffer, 4096, NETFLAGS);
1583 if (error != ENOTCONN && error != 10057 && error != EINTR && error != ECONNRESET)
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));
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);
1598 closesocket((*netw)->link.sock);
1602 if ((*netw)->crypto_algo == NETW_ENCRYPT_OPENSSL) {
1604 SSL_CTX_free((*netw)->ctx);
1606 n_log(
LOG_ERR,
"SSL context of socket %d was already NULL", (*netw)->link.sock);
1618 if ((*netw)->link.rhost) {
1619 freeaddrinfo((*netw)->link.rhost);
1623 netw_set((*netw), NETW_DESTROY_SENDBUF | NETW_DESTROY_RECVBUF);
1625 pthread_mutex_destroy(&(*netw)->recvbolt);
1626 pthread_mutex_destroy(&(*netw)->sendbolt);
1627 pthread_mutex_destroy(&(*netw)->eventbolt);
1628 sem_destroy(&(*netw)->send_blocker);
1648 char* errmsg = NULL;
1651 n_log(
LOG_ERR,
"Cannot use an allocated network. Please pass a NULL network to modify");
1662 (*netw)->link.port = strdup(port);
1665 (*netw)->link.hints.ai_family = AF_INET;
1667 (*netw)->link.hints.ai_family = AF_INET6;
1670 (*netw)->link.hints.ai_family = AF_UNSPEC;
1673 (*netw)->link.hints.ai_flags = AI_PASSIVE;
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;
1680 error = getaddrinfo(addr, port, &(*netw)->link.hints, &(*netw)->link.rhost);
1682 n_log(
LOG_ERR,
"Error when resolving %s:%s getaddrinfo: %s",
_str(addr), port, gai_strerror(error));
1686 (*netw)->addr_infos_loaded = 1;
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) {
1704 if (bind((*netw)->link.sock, rp->ai_addr, rp->ai_addrlen) == 0) {
1712 if (!inet_ntop(rp->ai_family,
get_in_addr(rp->ai_addr), ip, 64)) {
1719 (*netw)->link.ip = ip;
1724 n_log(
LOG_ERR,
"Error from bind() on port %s neterrno: %s", port, errmsg);
1726 closesocket((*netw)->link.sock);
1730 n_log(
LOG_ERR,
"Couldn't get a socket for listening on port %s", port);
1736 (*netw)->nb_pending = nbpending;
1737 listen((*netw)->link.sock, (*netw)->nb_pending);
1739 netw_set((*netw), NETW_SERVER | NETW_RUN | NETW_THR_ENGINE_STOPPED);
1754 int tmp = 0, error = 0;
1755 char* errmsg = NULL;
1757#if defined(__linux__) || defined(__sun) || defined(_AIX)
1758 socklen_t sin_size = 0;
1773 netw =
netw_new(send_list_limit, recv_list_limit);
1778 int secs = blocking / 1000;
1779 int usecs = (blocking % 1000) * 1000;
1780 struct timeval select_timeout = {secs, usecs};
1783 FD_SET(from->
link.
sock, &accept_set);
1784 FD_ZERO(&accept_set);
1786 int ret = select(from->
link.
sock + 1, &accept_set, NULL, NULL, &select_timeout);
1792 n_log(
LOG_DEBUG,
"error on select with timeout %ds (%d.%ds), neterrno: %s", blocking, secs, usecs,
_str(errmsg));
1796 }
else if (ret == 0) {
1802 if (FD_ISSET(from->
link.
sock, &accept_set)) {
1821 }
else if (blocking == -1) {
1830 n_log(
LOG_ERR,
"accept returned an invalid socket (-1)");
1873 netw_set(netw, NETW_SERVER | NETW_RUN | NETW_THR_ENGINE_STOPPED);
1880 netw->
ssl = SSL_new(from->
ctx);
1886 if (SSL_accept(netw->
ssl) <= 0) {
1891 netw_ssl_print_errors(netw->
link.
sock);
1934 n_log(
LOG_ERR,
"Empty messages are not supported. msg(%p)->lenght=%d", msg, msg->
length);
1938 pthread_mutex_lock(&netw->
sendbolt);
1941 pthread_mutex_unlock(&netw->
sendbolt);
1945 pthread_mutex_unlock(&netw->
sendbolt);
1971 n_log(
LOG_ERR,
"Empty messages are not supported. msg(%p)->lenght=%d", str, length);
1978 pthread_mutex_lock(&netw->
sendbolt);
1980 pthread_mutex_unlock(&netw->
sendbolt);
1983 pthread_mutex_unlock(&netw->
sendbolt);
2000 pthread_mutex_lock(&netw->
recvbolt);
2004 pthread_mutex_unlock(&netw->
recvbolt);
2016N_STR* netw_wait_msg(
NETWORK* netw,
unsigned int refresh,
size_t timeout) {
2017 N_STR* nstrptr = NULL;
2019 unsigned int secs = 0;
2020 unsigned int usecs = 0;
2025 if (refresh > 999999) {
2026 secs = refresh / 1000000;
2027 usecs = refresh % 1000000;
2033 n_log(
LOG_DEBUG,
"wait from socket %d, refresh: %zu usec (%zu secs, %zu usecs), timeout %zu usec", netw->
link.
sock, refresh, secs, usecs, timeout);
2034 uint32_t state = NETW_RUN;
2042 if (timed >= refresh)
2044 if (timed == 0 || timed < refresh) {
2055 }
while (state != NETW_EXITED && state != NETW_ERROR);
2105 ssize_t net_status = 0;
2120 int message_sent = 0;
2121 while (message_sent == 0 && !DONE) {
2123 if (state & NETW_ERROR) {
2125 }
else if (state & NETW_EXITED) {
2127 }
else if (state & NETW_EXIT_ASKED) {
2130 nboctet = htonl(NETW_EXIT_ASKED);
2131 memcpy(nboct, &nboctet,
sizeof(uint32_t));
2133 net_status = netw->
send_data(netw, nboct,
sizeof(int32_t));
2138 pthread_mutex_lock(&netw->
sendbolt);
2140 pthread_mutex_unlock(&netw->
sendbolt);
2142 if (ptr->
written <= UINT_MAX) {
2146 nboctet = htonl(state);
2147 memcpy(nboct, &nboctet,
sizeof(uint32_t));
2150 net_status = netw->
send_data(netw, nboct,
sizeof(int32_t));
2156 nboctet = htonl((uint32_t)ptr->
written);
2157 memcpy(nboct, &nboctet,
sizeof(uint32_t));
2159 net_status = netw->
send_data(netw, nboct,
sizeof(uint32_t));
2178 n_log(
LOG_ERR,
"discarded packet of size %zu which is greater than %" PRIu32, ptr->
written, UINT_MAX);
2213#if !defined(__linux__)
2225 ssize_t net_status = 0;
2227 uint32_t nboctet = 0,
2233 N_STR* recvdmsg = NULL;
2241 if (state & NETW_EXIT_ASKED || state & NETW_EXITED) {
2244 if (state & NETW_ERROR) {
2250 net_status = netw->
recv_data(netw, nboct,
sizeof(uint32_t));
2251 if (net_status < 0) {
2254 memcpy(&nboctet, nboct,
sizeof(uint32_t));
2255 tmpstate = ntohl(nboctet);
2257 if (tmpstate == NETW_EXIT_ASKED) {
2263 net_status = netw->
recv_data(netw, nboct,
sizeof(uint32_t));
2264 if (net_status < 0) {
2267 memcpy(&nboctet, nboct,
sizeof(uint32_t));
2268 tmpstate = ntohl(nboctet);
2277 if (!recvdmsg->
data) {
2280 recvdmsg->
length = nboctet + 1;
2284 net_status = netw->
recv_data(netw, recvdmsg->
data, nboctet);
2285 if (net_status < 0) {
2288 pthread_mutex_lock(&netw->
recvbolt);
2291 pthread_mutex_unlock(&netw->
recvbolt);
2330#if !defined(__linux__)
2343 int thr_engine_status = 0;
2349 if (thr_engine_status != NETW_THR_ENGINE_STARTED) {
2350 n_log(
LOG_ERR,
"Thread engine status already stopped for network %p", netw);
2357 for (
int it = 0; it < 10; it++) {
2361 pthread_join(netw->
send_thr, NULL);
2363 pthread_join(netw->
recv_thr, NULL);
2365 netw_set(netw, NETW_EXITED | NETW_THR_ENGINE_STOPPED);
2386 char* errmsg = NULL;
2393 char* tmp_buf = buf;
2408 }
else if (error == ECONNRESET || error == ENOTCONN) {
2419 send(s, NULL, 0, 0);
2437 char* errmsg = NULL;
2444 char* tmp_buf = buf;
2459 }
else if (br == 0) {
2465 n_log(
LOG_ERR,
"socket %d recv returned %d, error: %s", s, br,
_str(errmsg));
2485 SSL* ssl = ((
NETWORK*)netw)->ssl;
2492 char* errmsg = NULL;
2502#if OPENSSL_VERSION_NUMBER < 0x1010107fL
2503 int status = SSL_write(ssl, buf, (
int)(n - bcount));
2504 bs = (status > 0) ? (
size_t)status : 0;
2506 int status = SSL_write_ex(ssl, buf, (
size_t)(n - bcount), &bs);
2510 bcount += (ssize_t)bs;
2513 int ssl_error = SSL_get_error(ssl, status);
2514 if (ssl_error == SSL_ERROR_WANT_READ || ssl_error == SSL_ERROR_WANT_WRITE) {
2519 switch (ssl_error) {
2520 case SSL_ERROR_SYSCALL:
2522 n_log(
LOG_ERR,
"socket %d SSL_read syscall error: connection closed by peer", s);
2526 n_log(
LOG_ERR,
"socket %d SSL_read returned %d, error: %s", s, bs, ERR_reason_error_string(ERR_get_error()));
2530 n_log(
LOG_ERR,
"socket %d SSL_read returned %d, errno: %s", s, bs,
_str(errmsg));
2551 SSL* ssl = ((
NETWORK*)netw)->ssl;
2557 char* errmsg = NULL;
2564 while (bcount < n) {
2567#if OPENSSL_VERSION_NUMBER < 0x10101000L
2568 int status = SSL_read(ssl, buf, (
int)(n - bcount));
2569 br = (status > 0) ? (
size_t)status : 0;
2571 int status = SSL_read_ex(ssl, buf, (
size_t)(n - bcount), &br);
2575 bcount += (ssize_t)br;
2578 int ssl_error = SSL_get_error(ssl, status);
2579 if (ssl_error == SSL_ERROR_WANT_READ || ssl_error == SSL_ERROR_WANT_WRITE) {
2584 switch (ssl_error) {
2585 case SSL_ERROR_SYSCALL:
2587 n_log(
LOG_ERR,
"socket %d SSL_read syscall error: connection closed by peer", s);
2591 n_log(
LOG_ERR,
"socket %d SSL_read returned %d, error: %s", s, br, ERR_reason_error_string(ERR_get_error()));
2595 n_log(
LOG_ERR,
"socket %d SSL_read returned %d, errno: %s", s, br,
_str(errmsg));
2619 char* errmsg = NULL;
2635 bs = send(s, ptr, (
size_t)(
HEAD_SIZE - bcount), NETFLAGS);
2643 n_log(
LOG_ERR,
"Socket %d sending Error %d when sending head size, neterrno: %s", s, bs,
_str(errmsg));
2654 bs = send(s, ptr, (
size_t)(
HEAD_CODE - bcount), NETFLAGS);
2661 n_log(
LOG_ERR,
"Socket %d sending Error %d when sending head code, neterrno: %s", s, bs,
_str(errmsg));
2672 bs = send(s, buf, (
size_t)(n - bcount), NETFLAGS);
2680 n_log(
LOG_ERR,
"Socket %d sending Error %d when sending message of size %d, neterrno: %s", s, bs, n,
_str(errmsg));
2700 long int tmpnb = 0, size = 0;
2704 char* errmsg = NULL;
2714 br = recv(s, ptr, (
size_t)(
HEAD_SIZE - bcount), NETFLAGS);
2720 if (br == 0 && bcount == (
HEAD_SIZE - bcount))
2730 tmpnb = strtol(head, NULL, 10);
2731 if (tmpnb == LONG_MIN || tmpnb == LONG_MAX) {
2732 n_log(
LOG_ERR,
"Size received ( %ld ) can not be determined on socket %d", tmpnb, s);
2743 br = recv(s, ptr, (
size_t)(
HEAD_CODE - bcount), NETFLAGS);
2749 if (br == 0 && bcount == (
HEAD_CODE - bcount))
2753 n_log(
LOG_ERR,
"Socket %d receive %d Error , neterrno: %s", s, br,
_str(errmsg));
2759 tmpnb = strtol(code, NULL, 10);
2760 if (tmpnb <= INT_MIN || tmpnb >= INT_MAX) {
2761 n_log(
LOG_ERR,
"Code received ( %ld ) too big or too little to be valid code on socket %d\n", tmpnb, s);
2765 (*_code) = (int)tmpnb;
2771 Malloc((*buf),
char, (
size_t)(size + 1));
2780 while (bcount < size) {
2782 br = recv(s, ptr, (
size_t)(size - bcount), NETFLAGS);
2788 if (br == 0 && bcount == (size - bcount))
2792 n_log(
LOG_ERR,
"Socket %d receive %d Error neterrno: %s", s, br,
_str(errmsg));
2811 pthread_mutex_lock(&netw->
sendbolt);
2813 pthread_mutex_unlock(&netw->
sendbolt);
2815 pthread_mutex_lock(&netw->
recvbolt);
2817 pthread_mutex_unlock(&netw->
recvbolt);
2847 __n_assert(netw_pool && (*netw_pool),
return FALSE);
2850 if ((*netw_pool)->pool)
2852 unlock((*netw_pool)->rwlock);
2899 if ((retval =
list_push(netw->
pools, netw_pool, NULL)) == TRUE) {
3013 N_STR* tmpstr = NULL;
3032 N_STR* tmpstr = NULL;
3056 N_STR* tmpstr = NULL;
3078 N_STR* tmpstr = NULL;
3098 N_STR* tmpstr = NULL;
3116 N_STR* tmpstr = NULL;
3133 size_t encoded_size = 0;
3135 for (
size_t i = 0; i < len; i++) {
3136 unsigned char c = (
unsigned char)str[i];
3137 if (isalnum(c) || c ==
'-' || c ==
'_' || c ==
'.' || c ==
'~') {
3144 return encoded_size;
3156 static const char* hex =
"0123456789ABCDEF";
3158 char* encoded = (
char*)malloc(encoded_size + 1);
3164 char* pbuf = encoded;
3166 for (
size_t i = 0; i < len; i++) {
3167 unsigned char c = (
unsigned char)str[i];
3168 if (isalnum(c) || c ==
'-' || c ==
'_' || c ==
'.' || c ==
'~') {
3172 *pbuf++ = hex[c >> 4];
3173 *pbuf++ = hex[c & 0xF];
3189 const char* space = strchr(request,
' ');
3191 if (space == NULL) {
3197 size_t method_length = (size_t)(space - request);
3200 char* method = (
char*)malloc(method_length + 1);
3202 if (method == NULL) {
3208 strncpy(method, request, method_length);
3209 method[method_length] =
'\0';
3221 info.content_length = 0;
3223 memset(info.content_type, 0,
sizeof(info.content_type));
3231 const char* content_type_header = strstr(request,
"Content-Type:");
3232 if (content_type_header) {
3233 const char* start = content_type_header + strlen(
"Content-Type: ");
3234 const char* end = strstr(start,
"\r\n");
3236 size_t length = (size_t)(end - start);
3237 strncpy(info.content_type, start, length);
3238 info.content_type[length] =
'\0';
3242 strncpy(info.content_type,
"text/plain",
sizeof(info.content_type) - 1);
3246 const char* content_length_header = strstr(request,
"Content-Length:");
3247 if (content_length_header) {
3248 const char* start = content_length_header + strlen(
"Content-Length: ");
3250 unsigned long tmp_cl = strtoul(start, NULL, 10);
3254#if ULONG_MAX > SIZE_MAX
3255 if (error == ERANGE || tmp_cl > SIZE_MAX) {
3257 if (error == ERANGE) {
3259 n_log(
LOG_ERR,
"could not get content_length for request %p, returned %s", request, strerror(error));
3260 info.content_length = SIZE_MAX;
3262 info.content_length = (size_t)tmp_cl;
3267 const char* body_start = strstr(request,
"\r\n\r\n");
3272 if (info.content_length > 0) {
3273 info.body = malloc(info.content_length + 1);
3275 strncpy(info.body, body_start, info.content_length);
3276 info.body[info.content_length] =
'\0';
3302 __n_assert(request && strlen(request) > 0,
return FALSE);
3306 strncpy(url,
"/", size - 1);
3307 url[size - 1] =
'\0';
3310 const char* first_space = strchr(request,
' ');
3316 const char* second_space = strchr(first_space + 1,
' ');
3317 if (!second_space) {
3322 size_t len = (size_t)(second_space - first_space - 1);
3327 strncpy(url, first_space + 1, len);
3340 char* decoded = malloc(strlen(str) + 1);
3346 if (isxdigit((
unsigned char)str[1]) && isxdigit((
unsigned char)str[2])) {
3348 if (sscanf(str + 1,
"%2x", &value) >= 1) {
3352 n_log(
LOG_ERR,
"sscanf could not parse char *str (%p) for a %%2x", str);
3359 }
else if (*str ==
'+') {
3379 char* data = strdup(post_data);
3383 char* ampersand_pos;
3387 while (pair != NULL) {
3389 ampersand_pos = strchr(pair,
'&');
3392 if (ampersand_pos != NULL) {
3393 *ampersand_pos =
'\0';
3397 char* equal_pos = strchr(pair,
'=');
3398 if (equal_pos != NULL) {
3401 char* value = equal_pos + 1;
3407 free(decoded_value);
3410 pair = (ampersand_pos != NULL) ? (ampersand_pos + 1) : NULL;
3414 return post_data_table;
3426 char url_copy[1024];
3427 strncpy(url_copy, url,
sizeof(url_copy) - 1);
3428 url_copy[
sizeof(url_copy) - 1] =
'\0';
3431 char* query_start = strchr(url_copy,
'?');
3433 *query_start =
'\0';
3437 const char* ext = strrchr(url_copy,
'.');
3445 if (strcmp(ext,
".html") == 0 || strcmp(ext,
".htm") == 0) {
3447 }
else if (strcmp(ext,
".txt") == 0) {
3448 return "text/plain";
3449 }
else if (strcmp(ext,
".jpg") == 0 || strcmp(ext,
".jpeg") == 0) {
3450 return "image/jpeg";
3451 }
else if (strcmp(ext,
".png") == 0) {
3453 }
else if (strcmp(ext,
".gif") == 0) {
3455 }
else if (strcmp(ext,
".css") == 0) {
3457 }
else if (strcmp(ext,
".js") == 0) {
3458 return "application/javascript";
3459 }
else if (strcmp(ext,
".json") == 0) {
3460 return "application/json";
3461 }
else if (strcmp(ext,
".xml") == 0) {
3462 return "application/xml";
3463 }
else if (strcmp(ext,
".pdf") == 0) {
3464 return "application/pdf";
3465 }
else if (strcmp(ext,
".zip") == 0) {
3466 return "application/zip";
3467 }
else if (strcmp(ext,
".mp4") == 0) {
3469 }
else if (strcmp(ext,
".mp3") == 0) {
3470 return "audio/mpeg";
3471 }
else if (strcmp(ext,
".wav") == 0) {
3473 }
else if (strcmp(ext,
".ogg") == 0) {
3487 switch (status_code) {
3491 return "No Content";
3493 return "Not Modified";
3497 return "Internal Server Error";
3512 const time_t now = time(NULL);
3515 if (gmtime_s(&gmt, &now) != 0) {
3520 if (!gmtime_r(&now, &gmt)) {
3525 if (strftime(buffer, buffer_size,
"%a, %d %b %Y %H:%M:%S GMT", &gmt) == 0) {
3545 __n_assert(additional_headers,
return FALSE);
3548 const char* connection_type =
"close";
3551 char date_buffer[128] =
"";
3554 if ((*http_response)) {
3555 (*http_response)->written = 0;
3558 if (!body || body->
written == 0) {
3561 "HTTP/1.1 %d %s\r\n"
3564 "Content-Length: 0\r\n"
3566 "Connection: %s\r\n\r\n",
3567 status_code, status_message, date_buffer, server_name, additional_headers, connection_type);
3572 "HTTP/1.1 %d %s\r\n"
3575 "Content-Type: %s\r\n"
3576 "Content-Length: %zu\r\n"
3578 "Connection: %s\r\n\r\n",
3579 status_code, status_message, date_buffer, server_name, content_type, body->
written, additional_headers, connection_type);
3580 nstrcat((*http_response), body);
#define init_lock(__rwlock_mutex)
Macro for initializing a rwlock.
#define FreeNoLog(__ptr)
Free Handler without log.
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
#define __n_assert(__ptr, __ret)
macro to assert things
#define _str(__PTR)
define true
#define rw_lock_destroy(__rwlock_mutex)
Macro to destroy rwlock mutex.
#define CALL_RETRY(__retvar, __expression, __max_tries, __delay)
TEMP_FAILURE gnu macro portable version.
#define unlock(__rwlock_mutex)
Macro for releasing read/write lock a rwlock mutex.
#define write_lock(__rwlock_mutex)
Macro for acquiring a write lock on a rwlock mutex.
#define Free(__ptr)
Free Handler to get errors.
#define read_lock(__rwlock_mutex)
Macro for acquiring a read lock on a rwlock mutex.
#define _nstr(__PTR)
N_STR or "NULL" string for logging purposes.
#define N_ENUM_DEFINE(MACRO_DEFINITION, enum_name)
Macro to define an N_ENUM.
#define N_ENUM_ENTRY(class, method)
helper to build an N_ENUM
size_t nb_keys
total number of used keys in the table
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
#define ht_foreach(__ITEM_, __HASH_)
ForEach macro helper (classic / old)
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
int ht_remove(HASH_TABLE *table, const char *key)
remove and delete node at key in table
HASH_TABLE * new_ht(size_t size)
Create a hash table with the given size.
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
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
#define hash_val(node, type)
Cast a HASH_NODE element.
structure of a hash table node
structure of a hash table
size_t nb_items
number of item currently in the list
#define list_shift(__LIST_, __TYPE_)
Shift macro helper for void pointer casting.
int list_empty(LIST *list)
Empty a LIST list of pointers.
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper.
#define remove_list_node(__LIST_, __NODE_, __TYPE_)
Remove macro helper for void pointer casting.
int list_destroy(LIST **list)
Empty and Free a list container.
LIST_NODE * list_search(LIST *list, void *ptr)
search ptr in list
#define MAX_LIST_ITEMS
flag to pass to new_generic_list for the maximum possible number of item in a list
Structure of a generic list node.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
#define LOG_INFO
informational
size_t written
size of the written data inside the string
size_t length
length of string (in case we wanna keep information after the 0 end of string value)
void free_nstr_ptr(void *ptr)
Free a N_STR pointer structure.
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
#define nstrcat(__nstr_dst, __nstr_src)
Macro to quickly concatenate two N_STR.
N_STR * nstrdup(N_STR *str)
Duplicate a N_STR.
#define nstrprintf(__nstr_var, __format,...)
Macro to quickly allocate and sprintf to N_STR.
A box including a string and his lenght.
void u_sleep(unsigned int usec)
wrapper around usleep for API consistency
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
N_SOCKET link
networking socket
char * certificate
openssl certificate file
int threaded_engine_status
Threaded network engine state for this network.
pthread_t send_thr
sending thread
int nb_pending
Nb pending connection,if listening.
int so_reuseaddr
so reuseaddr state
pthread_t recv_thr
receiving thread
pthread_rwlock_t rwlock
thread safety
struct sockaddr_storage raddr
connected remote addr
pthread_mutex_t eventbolt
mutex for threaded access of state event
const SSL_METHOD * method
SSL method container.
int deplete_socket_timeout
deplete socket send buffer timeout ( 0 disabled, > 0 wait for timeout and check unset/unack datas)
int deplete_queues_timeout
deplete network queues timeout ( 0 disabled, > 0 wait for timeout and check unset/unack datas)
int nb_running_threads
nb running threads, if > 0 thread engine is still running
pthread_mutex_t recvbolt
mutex for threaded access of recv buf
pthread_mutex_t sendbolt
mutex for threaded access of send_buf
int send_queue_consecutive_wait
send queue consecutive pool interval, used when there are still items to send, in usec
int so_rcvtimeo
send timeout value
int tcpnodelay
state of naggle algorythm, 0 untouched, 1 forcibly disabled
SOCKET sock
a normal socket
char * port
port of socket
LIST * recv_buf
reveicing buffer (for incomming usage)
int user_id
if part of a user property, id of the user
sem_t send_blocker
block sending func
SSL_CTX * ctx
SSL context holder.
int so_sndbuf
size of the socket send buffer, 0 untouched, else size in bytes
int so_sndtimeo
send timeout value
struct addrinfo hints
address of local machine
int so_keepalive
so keepalive state
netw_func send_data
send func ptr
int addr_infos_loaded
Internal flag to know if we have to free addr infos.
uint32_t state
state of the connection , NETW_RUN, NETW_QUIT, NETW_STOP , NETW_ERR
LIST * pools
pointers to network pools if members of any
char * key
openssl key file
int so_linger
close lingering value (-1 disabled, 0 force close, >0 linger )
unsigned long int is_blocking
flag to quickly check socket mode
int crypto_algo
if encryption is on, which one (flags NETW_ENCRYPT_*)
HASH_TABLE * pool
table of clients
LIST * send_buf
sending buffer (for outgoing queuing )
int mode
NETWORK mode , 1 listening, 0 connecting.
int so_rcvbuf
size of the socket recv buffer, 0 untouched, else size in bytes
netw_func recv_data
receive func ptr
int wait_close_timeout
network wait close timeout value ( < 1 disabled, >= 1 timeout sec )
#define NETW_SOCKET_ERROR
code for a socekt error
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.
int netw_pool_broadcast(NETWORK_POOL *netw_pool, NETWORK *from, N_STR *net_msg)
add net_msg to all network in netork pool
N_STR * netw_get_msg(NETWORK *netw)
Get a message from aimed NETWORK.
int netw_add_msg(NETWORK *netw, N_STR *msg)
Add a message to send in aimed NETWORK.
ssize_t send_ssl_data(void *netw, char *buf, uint32_t n)
send data onto the socket
char * netw_extract_http_request_type(const char *request)
function to extract the request method from an http request
int netw_get_queue_status(NETWORK *netw, size_t *nb_to_send, size_t *nb_to_read)
retrieve network send queue status
int netw_init_wsa(int mode, int v1, int v2)
Do not directly use, internal api.
ssize_t send_php(SOCKET s, int _code, char *buf, int n)
send data onto the socket
int netw_stop_thr_engine(NETWORK *netw)
Stop a NETWORK connection sending and receing thread.
char * netw_urlencode(const char *str, size_t len)
function to perform URL encoding
void * netw_send_func(void *NET)
Thread send function.
NETWORK * netw_accept_nonblock_from(NETWORK *from, int blocking)
make a normal blocking 'accept' .
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.
#define N_ENUM_netw_code_type(_)
Network codes definition.
int netw_set_crypto(NETWORK *netw, char *key, char *certificate)
activate SSL encryption on selected network, using key and certificate
#define NETWORK_IPV6
Flag to force IPV6
int netw_get_http_date(char *buffer, size_t buffer_size)
helper function to generate the current date in HTTP format
NETWORK_POOL * netw_new_pool(size_t nb_min_element)
return a new network pool of nb_min_element
int netw_set_user_id(NETWORK *netw, int id)
associate an id and a network
ssize_t recv_data(void *netw, char *buf, uint32_t n)
recv data from the socket
int netw_init_openssl(void)
Do not directly use, internal api.
ssize_t recv_ssl_data(void *netw, char *buf, uint32_t n)
recv data from the socket
int netw_make_listening(NETWORK **netw, char *addr, char *port, int nbpending, int ip_version)
Make a NETWORK be a Listening network.
#define HEAD_SIZE
Size of a HEAD message.
int netw_start_thr_engine(NETWORK *netw)
Start the NETWORK netw Threaded Engine.
int netw_destroy_pool(NETWORK_POOL **netw_pool)
free a NETWORK_POOL *pool
#define NETWORK_IPV4
Flag to force IPV4
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
void * netw_recv_func(void *NET)
To Thread Receiving function.
size_t htonst(size_t value)
host to network size_t
int netw_unload_openssl(void)
Do not directly use, internal api.
#define HEAD_CODE
Code of a HEAD message.
#define NETWORK_CONSECUTIVE_SEND_WAIT
Flag to set consecutive send waiting timeout
size_t netw_pool_nbclients(NETWORK_POOL *netw_pool)
return the number of networks in netw_pool
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' .
int SOCKET
default socket declaration
#define NETW_SOCKET_DISCONNECTED
Code for a disconnected recv.
#define NETWORK_WAIT_CLOSE_TIMEOUT
Flag to set network closing wait timeout.
int netw_setsockopt(NETWORK *netw, int optname, int value)
Modify common socket options on the given netw.
int netw_set(NETWORK *netw, int flag)
Restart or reset the specified network ability.
ssize_t send_data(void *netw, char *buf, uint32_t n)
send data onto the socket
int netw_get_state(NETWORK *netw, uint32_t *state, int *thr_engine_status)
Get the state of a network.
void netw_pool_netw_close(void *netw_ptr)
close a network from a network pool
size_t netw_calculate_urlencoded_size(const char *str, size_t len)
function to calculate the required size for the URL-encoded string
int deplete_send_buffer(int fd, int timeout)
wait until the socket is empty or timeout, checking each 100 msec.
NETWORK * netw_accept_from(NETWORK *from)
make a normal blocking 'accept' .
#define NETW_MAX_RETRIES
Send or recv max number of retries.
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
int netw_send_quit(NETWORK *netw)
Add a formatted NETMSG_QUIT message to the specified network.
const char * netw_get_http_status_message(int status_code)
helper function to convert status code to a human-readable message
int netw_set_blocking(NETWORK *netw, unsigned long int is_blocking)
Modify blocking socket mode.
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.
int netw_send_ping(NETWORK *netw, int type, int id_from, int id_to, int time)
Add a ping reply to the network.
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.
NETWORK_HTTP_INFO netw_extract_http_info(char *request)
extract a lot of informations, mostly as pointers, and populate a NETWORK_HTTP_INFO structure
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.
__netw_code_type
Network codes declaration.
#define NETWORK_DEPLETE_SOCKET_TIMEOUT
Flag to set send buffer depletion timeout
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.
char * netw_urldecode(const char *str)
Function to decode URL-encoded data.
#define NETWORK_DEPLETE_QUEUES_TIMEOUT
Flag to set network queues depletion timeout
int netw_pool_add(NETWORK_POOL *netw_pool, NETWORK *netw)
add a NETWORK *netw to a NETWORK_POOL *pool
int netw_info_destroy(NETWORK_HTTP_INFO http_request)
destroy a NETWORK_HTTP_INFO loaded informations
HASH_TABLE * netw_parse_post_data(const char *post_data)
Function to parse POST data.
const char * netw_guess_http_content_type(const char *url)
function to guess the content type based on URL extension
ssize_t recv_php(SOCKET s, int *_code, char **buf)
recv data from the socket
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.
int netw_pool_remove(NETWORK_POOL *netw_pool, NETWORK *netw)
remove a NETWORK *netw to a NETWORK_POOL *pool
int netw_add_msg_ex(NETWORK *netw, char *str, unsigned int length)
Add a message to send in aimed NETWORK.
structure for splitting HTTP requests
structure of a network pool
Hash functions and table.
NETWORK * netw_new(size_t send_list_limit, size_t recv_list_limit)
Return an empty allocated network ready to be netw_closed.
#define netstrerror(code)
BSD style errno string NO WORKING ON REDHAT.
#define neterrno
get last socket error code, linux version
char * get_in_addr(struct sockaddr *sa)
get sockaddr, IPv4 or IPv6
Network messages , serialization tools.