From 26e707387c6bac44090bbd9e3776b7c603070e3c Mon Sep 17 00:00:00 2001 From: Th Pi Date: Mon, 15 Jun 2020 14:19:43 +0200 Subject: [PATCH] Various changes, see Changelog --- Authors | 1 + ChangeLog | 33 ++++++ Makefile | 2 +- TODO | 4 + misc.c | 87 +++++++++++++++- proxy.c | 5 +- revinetd.c | 21 ++-- revinetd.h | 1 + server.c | 320 ++++++++++++++++++++++++++++++++++++++++++++--------------- server.h | 3 + statistics.c | 16 +++ statistics.h | 15 +++ 12 files changed, 419 insertions(+), 89 deletions(-) create mode 100644 statistics.c create mode 100644 statistics.h diff --git a/Authors b/Authors index 26abd18..8589919 100644 --- a/Authors +++ b/Authors @@ -1,2 +1,3 @@ Steven M. Gill Alexandre Carmel-Veilleux +Thomas P diff --git a/ChangeLog b/ChangeLog index b420156..4248ad9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,36 @@ +2020-06-12 ("revinetd-1.0.2_p5") (thpi) +- applying "-v" two times outputs statistics (for debugging) +- in server.c: more adaptive priority of handling +- in misc.c: read() error now leading to channel close (not prg exit) + +2020-06-11 ("revinetd-1.0.2_p4") (thpi) (development version) +- in server.c: changing handling priority towards "first accepting conns, + then processing their data" +- in server.c: adding sock queue cleanup by re-issuing request for a + worker connection if sock queue non-empty for too long +- in server.c: preparing outputting statistics + +2020-06-10 ("revinetd-1.0.2_p3") (thpi) (development version) +- version string in splash message + +2020-06-09 ("revinetd-1.0.2_p2") (thpi) (development version) +- reorganizing server main loop => clean relay reconnect handling +- adjustment of verbosity handling and format of output +- more info messages +- increasing listen queue capacity to 5 (from previously 1) for + the client-facing incoming connections + +2020-06-06 ("revinetd-1.0.2_p1") (thpi) (development version) +- For the client-facing listening interface, now accepting IPv6 numerical + addresses enclosed in square brackets. (Lookup of IPv6 addresses from + names is not implemented.) (see misc.c and server.c revinetd.c) +- Format specifiers for ports now "%u" instead of "%d", making port numbers + display properly. +- Rearrangement of the proxy listen code in server.c to gracefully refuse + client-side connections if the relay agent is not yet available. + (status: hack) +- Minor corrections in comments and indentation + 8/27/2008 Added bugfix for broken relase of relay agent. diff --git a/Makefile b/Makefile index d6318a2..0b4d68d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = gcc CFLAGS = -Wall -g -O2 -DHAVE_CONFIG_H LDFLAGS = -OBJS = getopt.o revinetd.o misc.o proxy.o server.o relay_agt.o +OBJS = getopt.o revinetd.o misc.o proxy.o server.o relay_agt.o statistics.o BINDIR = /usr/local/bin INSTALL = ./install-sh diff --git a/TODO b/TODO index ddd9a7c..b5b8af6 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,7 @@ +TODO for version past revinetd-1.0.2_p5 +- access control to server (relay endpoint) by IP address pattern + +-------------------------------------------------------------- TODO for revinetd v 1.0.1 There are many things to do right now, here is a quick list: diff --git a/misc.c b/misc.c index ce6ab68..42e5098 100644 --- a/misc.c +++ b/misc.c @@ -59,7 +59,8 @@ copy_between_ports(int src_file, int dst_file) if (nbytes < 0) { /* Read error. */ perror("read"); - exit(EXIT_FAILURE); + //old: exit(EXIT_FAILURE); + return -1; } else if (nbytes == 0) { return -1; } else { @@ -102,7 +103,7 @@ send_comm_message(int dst_file, int message) } int -make_socket(const char *hostname, unsigned short port) +make_socket_IPv4(const char *hostname, unsigned short port) { int sock, sock_opt = 1; struct sockaddr_in name; @@ -149,6 +150,88 @@ make_socket(const char *hostname, unsigned short port) } int +make_socket_IPv6(const char *hostname, unsigned short port) +{ + int sock6, sock_opt = 1; + struct sockaddr_in6 name; + //struct hostent *hostinfo; + struct in6_addr saddr; + // char str[INET6_ADDRSTRLEN]; + + /* Create the socket. */ + sock6 = socket(AF_INET6, SOCK_STREAM, 0); + if (sock6 < 0) { + perror("socket"); + exit(EXIT_FAILURE); + } + + /* Set SO_REUSEADDR */ + setsockopt(sock6, SOL_SOCKET, SO_REUSEADDR, &sock_opt, sizeof(sock_opt)); + + + /* Give the socket a name. */ + //name.sin6_len = sizeof(name); + name.sin6_family = AF_INET6; + name.sin6_flowinfo = 0; + name.sin6_port = htons(port); + + /* check if ip address or resolve hostname */ + // https://man7.org/linux/man-pages/man3/inet_pton.3.html + if (inet_pton(AF_INET6, hostname, &saddr) == 0) + { +//#ifdef HAVE_INET_ATON +// if (!inet_aton(hostname, &saddr)) { +//#else +// saddr.s_addr = inet_addr(hostname); +// if (saddr.s_addr == -1) { +//#endif + fprintf(stderr, "Not a valid IPv6 numeric address, and address lookup not implemented for supposed IPv6 hostname %s.\n", hostname); + exit(EXIT_FAILURE); + //hostinfo = gethostbyname(hostname); + //if (hostinfo == NULL) { + // fprintf(stderr, "Unknown host %s.\n", hostname); + // exit(EXIT_FAILURE); + //} + //name.sin6_addr = *(struct in6_addr *)hostinfo->h_addr; + } else { + name.sin6_addr = saddr; + } +/* name.sin_addr.s_addr = htonl(INADDR_ANY); */ + if (bind(sock6, (struct sockaddr *)&name, sizeof(name)) < 0) { + perror("bind"); + exit(EXIT_FAILURE); + } + + return sock6; +} + +// Returns AF_INET6 if hostname is a string of format "[...]" (i.e. +// something enclosed in square brackets, or AF_INET if not +// enclosed in square brackets. Returns -1 if the format is ambiguous +// due to only one bracket occuring. +// If AF_INET6 is returned, the hostname_stripped will contain the +// string value of hostname without the brackets. (Must have been allocated +// of sufficient size.) +int +detect_address_family(const char *hostname, char *hostname_stripped) +{ + size_t x; + if ((x=strlen(hostname)) > 2) { + if (hostname[0] == '[') { + if (hostname[x-1] == ']') { + strncpy(hostname_stripped, &(hostname[1]), x-2); + hostname_stripped[x-2] = '\0'; + return AF_INET6; + } + else { + return -1; + } + } + } + return AF_INET; +} + +int init_sockaddr(struct sockaddr_in *name, const char *hostname, unsigned short port) { diff --git a/proxy.c b/proxy.c index 696c2c5..a32d7cc 100644 --- a/proxy.c +++ b/proxy.c @@ -26,9 +26,12 @@ #include "includes.h" #include "proxy.h" #include "misc.h" +#include "statistics.h" static const char cvsid[] = "$Id: proxy.c,v 1.8 2008/08/28 03:24:59 necrotaur Exp $"; +extern Statistics statistics; + int proxy(fd_set *active, fd_set *perm) { @@ -73,7 +76,6 @@ proxy(fd_set *active, fd_set *perm) void chan_remove(Channels *temp) { - unregister_sock(temp->source); unregister_sock(temp->target); @@ -99,6 +101,7 @@ chan_remove(Channels *temp) free(temp); } } + statistics.nmb_relay_worker_conns_cur--; } Channels * diff --git a/revinetd.c b/revinetd.c index 9b673d7..dc2faf0 100644 --- a/revinetd.c +++ b/revinetd.c @@ -29,7 +29,7 @@ #include "server.h" #include "misc.h" -static const char cvsid[] = "$Id: revinetd.c,v 1.29 2008/08/28 03:24:59 necrotaur Exp $"; +static const char cvsid[] = "$Id: revinetd.c,v 1.29 2008/08/28 03:24:59 necrotaur Exp, adapted by ThP $"; int main(int argc, char **argv) @@ -55,7 +55,7 @@ main(int argc, char **argv) int c, option_index = 0; pid_t pid; - printf("%s - Copyright (c) 2003-2008 Steven M. Gill\n", *argv); + printf("%s - v1.0.2_p5_20200612 - Copyright (c) 2003-2008 Steven M. Gill, et al (201x, 2020)\n", *argv); printf("%s is distributed under the terms of the GPL\n", *argv); printf("http://revinetd.sourceforge.net\n\n"); exec_name = strdup(*argv); @@ -159,7 +159,8 @@ main(int argc, char **argv) case 'v': if (conf.daemonize == 0) { - conf.verbosity = VB_VERBOSE; + //conf.verbosity = VB_VERBOSE; + conf.verbosity++; } break; @@ -274,26 +275,32 @@ clean_exit(int sig) exit(0); } +// Adapted to search for the colon from the right. (thpi) unsigned short parse_host_str(char *host_str) { unsigned short port; - int j = 0; + int j; /* Skip any leading spaces. */ while (isspace(*host_str)) { host_str++; } /* Loop through the line until we reach a ':'. Exit with errors if we stumble on an illegal character. */ + j = strlen(host_str)-1; + if (j < 0) return 0; while (*(host_str + j) != ':') { - if (*(host_str + j) == '\0' || isspace(*(host_str + j))) { + if (isspace(*(host_str + j))) { + *(host_str + j) = '\0'; // remove the trailing padding + } + --j; + if (j < 0) { fprintf(stderr, "Invalid hostname format.\n"); usage(); } - j++; } - /* Insert a NUL byte at the position of the ':' to delimitate the + /* Insert a NUL byte at the position of the right-most ':' to delimitate the hostname. And then skip ahead one byte. */ *(host_str + j++) = '\0'; diff --git a/revinetd.h b/revinetd.h index 4e8ec45..e9bdf1b 100644 --- a/revinetd.h +++ b/revinetd.h @@ -46,6 +46,7 @@ #define VB_NORMAL 0 #define VB_QUIET -1 #define VB_VERBOSE 1 +#define VB_DEBUG 2 /* Structures defs for configuration. */ typedef struct _OpenSockets { diff --git a/server.c b/server.c index c8bbde0..5e754dd 100644 --- a/server.c +++ b/server.c @@ -23,105 +23,153 @@ * * */ +/* + Changelog: + + p5 - option switched statistics output + - statistics.size_sock_queue now also used for controlling + priority of handling (##004) + + p4 - adding "continue"s in the main loop for proxy_sock acceptance + and ra_sock acceptance (##001 and ##002) + - introducing auto sockq cleanup (by re-requesting a worker connection + if necessary) (##003) + For this, timeout to the select() call had to be added, and + "create_time" member introduced. + Avoided CPU overload by a usleep(10000) call near "rc == 0". + - prepared: outputting connection statistics + + 2020-06-09 - complete restructuring of the main loop, to obtain + (thp) correct behaviour for relay agent connection loss and + reconnection. + Now, the proxy_sock accept branch is prevented, + thus avoiding blocking or idling. + [Could optionally shutdown client-facing listen socket + upon relay agent's disconnect; not implemented] + - slight adjustment of error/info messages + - code line rearrangement near "chan_remove(temp)" + - verbosity handling adjusted + */ + #include "revinetd.h" #include "includes.h" #include "proxy.h" #include "server.h" #include "misc.h" +#include "statistics.h" + +#include "time.h" static const char cvsid[] = "$Id: server.c,v 1.28 2008/08/28 03:24:59 necrotaur Exp $"; +extern Statistics statistics; +time_t next_display_time = 0; +#define STATS_INTVL 3 + +// On the client-facing end: +#define LISTEN_QUEUE_SIZE 10 + +void +cond_print_stats() +{ + time_t now = time(NULL); + if (now >= next_display_time) + { + printf("%8d\t%8d\t%8d\t%8d\t%8d\t%8d\t%8d\n", + statistics.nmb_client_accepts_acc, + statistics.nmb_sock_queue_enqueues_acc, + statistics.size_sock_queue, + statistics.nmb_relay_worker_conns_acc, + statistics.nmb_relay_worker_conns_acc - statistics.nmb_relay_worker_conns_cur, + statistics.nmb_relay_worker_conns_cur, + statistics.nmb_keep_alives_recv); + fflush(stdout); + next_display_time = now + STATS_INTVL; + } +} + +// Allows "host" to be of format "[xxxx:xxxx:...:xxxx]". int server(char *host,int port, char *host2, int port2) { - int ra_sock, proxy_sock, tmp_sock, bh_sock = -1; + int ra_sock, proxy_sock, tmp_sock, tmp_sock_4or6, bh_sock = -1; fd_set active, read; struct sockaddr_in tmp_sin; + struct sockaddr_in6 tmp_sin6; Channels *tmp_chan, *temp; SockQueue *tmp_sq, *sockq = NULL; - size_t size; + socklen_t size; + + struct timeval timeout; // select() timeout spec + timeout.tv_sec = 1; + timeout.tv_usec = 0; /* Make the sockets. */ - ra_sock = make_socket(host2, port2); - proxy_sock = make_socket(host, port); + char host_strp[strlen(host)]; + int proxy_af = detect_address_family(host, host_strp); + if (proxy_af < 0) { + fprintf(stderr, "server(): listen-client hostname value is not in valid format: %s\n", host); + exit(EXIT_FAILURE); + } + + if (conf.verbosity >= VB_NORMAL) printf("I: Binding relay end server socket...\n"); + ra_sock = make_socket_IPv4(host2, port2); + if (conf.verbosity >= VB_NORMAL) printf("I: Binding client end server socket...\n"); + proxy_sock = (proxy_af == AF_INET6 ? make_socket_IPv6(host_strp, port) : make_socket_IPv4(host, port)); register_sock(ra_sock); register_sock(proxy_sock); - if (listen(proxy_sock, 1) < 0) { + if (listen(ra_sock, 1) < 0) { perror("listen"); exit(EXIT_FAILURE); } + if (conf.verbosity >= VB_NORMAL) + printf("I: Waiting for relay agent on %s:%u\n", host2, port2); - if (conf.verbosity != VB_QUIET) - printf("Waiting for client on %s:%i\n", host, port); + FD_ZERO(&active); + FD_SET(ra_sock, &active); - if (listen(ra_sock, 1) < 0) { + // Now start to listen (pro-forma) on the client-facing end: + if (listen(proxy_sock, LISTEN_QUEUE_SIZE) < 0) { perror("listen"); exit(EXIT_FAILURE); } - - if (conf.verbosity != VB_QUIET) - printf("Waiting for relay agent on %s:%i\n", host2, port2); + // ... but do not actually accept while ra not yet connected: + //No: FD_SET(proxy_sock, &active); /* No channels yet. */ chan = NULL; - - FD_ZERO(&active); - FD_SET(proxy_sock, &active); - FD_SET(ra_sock, &active); + + reset_stats(&statistics); while (1) { + if (conf.verbosity >= VB_DEBUG) + cond_print_stats(); + + if (sockq != NULL) { // ##003 + if (sockq->create_time + 4 < time(NULL)) // if the sockq entry is already 4 secs old, regenerate a worker connection request: + { + if (conf.verbosity >= VB_VERBOSE) + printf("I: Extraordinarily requesting new proxy pair from relay agent\n"); + send_comm_message(bh_sock, RA_TARGET_UP); + sockq->create_time = time(NULL); + } + } + read = active; - if (select(FD_SETSIZE, &read, NULL, NULL, NULL) < 0) { + int rc = select(FD_SETSIZE, &read, NULL, NULL, &timeout); + if (rc < 0) { perror("select"); exit(EXIT_FAILURE); } - if (FD_ISSET(proxy_sock, &read)) { - if (bh_sock == -1) continue; /* Ignore untill relay agent is - connected. */ - /* Connect with client. */ - size = sizeof(tmp_sin); - tmp_sock = accept(proxy_sock, (struct sockaddr *)&tmp_sin, - &size); - if (tmp_sock < 0) { - perror("accept"); - exit(EXIT_FAILURE); - } - register_sock(tmp_sock); - - if (conf.verbosity != VB_QUIET) - printf("New client connection detected from %s:%hd\n", - inet_ntoa(tmp_sin.sin_addr), - ntohs(tmp_sin.sin_port)); - - /* New sockq entry for half open connections. */ - if (sockq == NULL) { - sockq = (SockQueue *)malloc(sizeof(SockQueue)); - if (sockq == NULL) { - perror("malloc"); - exit(EXIT_FAILURE); - } - memset(sockq, 0, sizeof(SockQueue)); - tmp_sq = sockq; - } else { - tmp_sq = sockq; - while (tmp_sq->next != NULL) - tmp_sq = tmp_sq->next; - tmp_sq->next = (SockQueue *)malloc(sizeof(SockQueue)); - tmp_sq = tmp_sq->next; - if (tmp_sq == NULL) { - perror("malloc"); - exit(EXIT_FAILURE); - } - memset(tmp_sq, 0, sizeof(SockQueue)); - } - tmp_sq->sock = tmp_sock; - - /* Now we send a request for a new backhaul channel. */ - printf("Requesting new proxy pair from relay agent\n"); - send_comm_message(bh_sock, RA_TARGET_UP); - } else if (FD_ISSET(ra_sock, &read)) { - /* Connect with client. */ + if (rc == 0) { + usleep(10000); /* wait for 10 msecs */ + continue; + } + + // Handle changes on the relay side with priority: + if (FD_ISSET(ra_sock, &read)) { + /* Connect with relay agent. */ size = sizeof(tmp_sin); tmp_sock = accept(ra_sock, (struct sockaddr *)&tmp_sin, &size); if (tmp_sock < 0) { @@ -131,24 +179,35 @@ server(char *host,int port, char *host2, int port2) register_sock(tmp_sock); if (bh_sock == -1) { - if (conf.verbosity != VB_QUIET) - printf("Relay agent comm channel established from %s:%hd\n", + if (conf.verbosity >= VB_NORMAL) + printf("I: Accepting relay agent from %s:%u\n", inet_ntoa(tmp_sin.sin_addr), ntohs(tmp_sin.sin_port)); bh_sock = tmp_sock; FD_SET(bh_sock, &active); + // Switch on accepting client connections later: + FD_SET(proxy_sock, &active); + listen(proxy_sock, LISTEN_QUEUE_SIZE); + if (conf.verbosity >= VB_VERBOSE) + printf("I: (Re-)Activating waiting for clients on %s:%u\n", host, port); } else { if (sockq == NULL) { - printf("Unrequested connection from relay agent.\n"); + if (conf.verbosity >= VB_NORMAL) + printf("W: Unrequested connection from another relay agent.\n"); + // TODO: closing tmp_sock here? } else { - - if (conf.verbosity != VB_QUIET) - printf("New relay agent connection established from %s:%hd\n", + // Any connection attempt that is made at the ra_sock + // end while the backhaul is standing is understood to + // be a data transfer channel established by the relay + // upon our own request. Thus, match it to the half-open + // connection queue pointed to by sockq: + + if (conf.verbosity >= VB_VERBOSE) + printf("I: New relay agent (worker) connection established from %s:%hu\n", inet_ntoa(tmp_sin.sin_addr), ntohs(tmp_sin.sin_port)); tmp_sq = sockq; - sockq = tmp_sq->next; if (chan == NULL) { chan = chan_add(); @@ -164,14 +223,26 @@ server(char *host,int port, char *host2, int port2) tmp_chan->source = tmp_sq->sock; tmp_chan->target = tmp_sock; + statistics.nmb_relay_worker_conns_acc++; + statistics.nmb_relay_worker_conns_cur++; FD_SET(tmp_chan->source, &active); FD_SET(tmp_chan->target, &active); - + + // Finally remove the processed from the queue of half-open + // connections: + sockq = tmp_sq->next; free(tmp_sq); + statistics.size_sock_queue--; } - } - } else if (FD_ISSET(bh_sock, &read)) { + } /* end bh != -1 */ + continue; + // ##001 + } /* end ra_sock readable */ + + /*----------------------------------------------*/ + + if (FD_ISSET(bh_sock, &read)) { /* We don't expect anything back. This should mean that comm is dropped. relay agent is disconnected so reset state and wait for @@ -180,22 +251,115 @@ server(char *host,int port, char *host2, int port2) * heart beat... Hopefully this won't break anything. */ if (get_comm_message(bh_sock) == SV_HEART_BEAT) { send_comm_message(bh_sock, RA_SERVER_ALIVE); + statistics.nmb_keep_alives_recv++; } else { - if (conf.verbosity != VB_QUIET) - printf("Relay agent disconnected. Resetting...\n"); + if (conf.verbosity >= VB_NORMAL) + printf("W: Relay agent disconnected. Resetting...\n"); unregister_sock(bh_sock); FD_CLR(bh_sock, &active); bh_sock = -1; temp = chan; while (temp != NULL) { - chan_remove(temp); FD_CLR(temp->source, &active); FD_CLR(temp->target, &active); - } + chan_remove(temp); // deallocates "temp" !! + } + // TODO: + // Review: Could make sense to clear the sock queue here as well? + // ... + + // Finally ensure that the proxy_sock accept() branch above + // is excluded from running, and avoid clients piling up in + // listen queue: + FD_CLR(proxy_sock, &active); + listen(proxy_sock, 0); + if (conf.verbosity >= VB_NORMAL) + printf("W: Client-facing port stopping accepting connections.\n"); + } + } /* end bh_sock ready */ + + /*----------------------------------------------*/ + + if (FD_ISSET(proxy_sock, &read)) { + if (bh_sock == -1) { + if (conf.verbosity >= VB_NORMAL) + printf("E: Ignoring a client-facing connection until relay agent is connected. (should not occur)\n"); + usleep(1000000); /* wait for a second */ + continue; /* Ignore until relay agent is connected. */ + // In fact, this branch should not occur anymore; the client-side + // socket is only to be marked ready if the relay agent is available. + } + + /* Accept the client, creating a client-side connection: */ + size = (proxy_af == AF_INET6 ? sizeof(tmp_sin6) : sizeof(tmp_sin)); + tmp_sock_4or6 = accept(proxy_sock, (struct sockaddr *)&tmp_sin6, + &size); + if (tmp_sock_4or6 < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + register_sock(tmp_sock_4or6); + statistics.nmb_client_accepts_acc++; + + if (conf.verbosity >= VB_VERBOSE) + { + char buf6[128]; + inet_ntop(proxy_af, &(tmp_sin6.sin6_addr), buf6, 127); + printf("I: New client connection detected from %s:%hu\n", + //inet_ntoa(tmp_sin6.sin6_addr), + buf6, + ntohs(tmp_sin6.sin6_port)); + } + + /* New sockq entry for half open connections. */ + if (sockq == NULL) { + sockq = (SockQueue *)malloc(sizeof(SockQueue)); + if (sockq == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + memset(sockq, 0, sizeof(SockQueue)); + tmp_sq = sockq; + } else { + tmp_sq = sockq; + while (tmp_sq->next != NULL) + tmp_sq = tmp_sq->next; + tmp_sq->next = (SockQueue *)malloc(sizeof(SockQueue)); + tmp_sq = tmp_sq->next; + if (tmp_sq == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + memset(tmp_sq, 0, sizeof(SockQueue)); } - } + tmp_sq->sock = tmp_sock_4or6; + tmp_sq->create_time = time(NULL); + statistics.nmb_sock_queue_enqueues_acc++; + statistics.size_sock_queue++; + + /* Now we send a request for a new backhaul channel. */ + if (conf.verbosity >= VB_VERBOSE) + printf("I: Requesting new proxy pair from relay agent\n"); + send_comm_message(bh_sock, RA_TARGET_UP); + + if (statistics.size_sock_queue < 20) // ##004 + continue; + // ##002: By adding "continue", client-side connection attempts + // are handled with priority, with effect that + // first all connections which are desired are accepted + // and thus established, and only then afterwards the data + // transfer begins. Therefore, do not fall through to proxy() + // directly. + } /* end proxy_sock ready */ + + /*----------------------------------------------*/ + + // Process possible data which is ready on the worker + // connections. proxy(&read, &active); } - + return(0); } + + diff --git a/server.h b/server.h index 5641058..9f27036 100644 --- a/server.h +++ b/server.h @@ -28,9 +28,12 @@ #ifndef __SERVER_H__ #define __SERVER_H__ +#include + typedef struct _SockQueue { int sock; struct _SockQueue *next; + time_t create_time; } SockQueue; int server(char *, int, char *, int); diff --git a/statistics.c b/statistics.c new file mode 100644 index 0000000..d376b81 --- /dev/null +++ b/statistics.c @@ -0,0 +1,16 @@ +#include "string.h" + +#include "statistics.h" + +Statistics statistics; + +void reset_stats(Statistics *st) +{ + st->nmb_client_accepts_acc = (0); + st->nmb_sock_queue_enqueues_acc = (0); + st->size_sock_queue = (0); + st->nmb_relay_worker_conns_acc = (0); + st->nmb_relay_worker_conns_cur = (0); + st->nmb_keep_alives_recv = (0); +} + diff --git a/statistics.h b/statistics.h new file mode 100644 index 0000000..6fc21e6 --- /dev/null +++ b/statistics.h @@ -0,0 +1,15 @@ +#pragma once + + +struct Statistics_str { + unsigned int nmb_client_accepts_acc; + unsigned int nmb_sock_queue_enqueues_acc; + unsigned int size_sock_queue; + unsigned int nmb_relay_worker_conns_acc; + unsigned int nmb_relay_worker_conns_cur; + unsigned int nmb_keep_alives_recv; +}; +typedef struct Statistics_str Statistics; + +void reset_stats(Statistics *st); + -- 2.11.4.GIT