diff --git a/src/3proxy.c b/src/3proxy.c index 90e6e07..4559be2 100644 --- a/src/3proxy.c +++ b/src/3proxy.c @@ -559,6 +559,7 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int _3proxy_mutex_init(&confref_mutex); _3proxy_mutex_init(&listener_mutex); reattachfunc = reattach; + listenertrafficfunc = listenertraffic; _3proxy_mutex_init(&runningservices_mutex); _3proxy_mutex_init(&bandlim_mutex); _3proxy_mutex_init(&connlim_mutex); diff --git a/src/common.c b/src/common.c index 1d1f534..3b6f993 100644 --- a/src/common.c +++ b/src/common.c @@ -234,6 +234,7 @@ struct extparam confboot = { struct extparam *conf = &confboot; struct extparam *runconf = &confboot; int (*reattachfunc)(struct clientparam *param, int auth) = NULL; +void (*listenertrafficfunc)(struct clientparam *param) = NULL; /* Authorizes a request on a connection which may outlive a reload, an HTTP one kept alive: as a client of the service whose rules apply now, the diff --git a/src/datatypes.c b/src/datatypes.c index cf70981..6293511 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -538,6 +538,14 @@ static void * ef_server_listenerprocessed(struct node * node){ return listenerprocessed((struct srvparam *)node->value); } +static void * ef_server_listenertrafin(struct node * node){ + return listenertrafin((struct srvparam *)node->value); +} + +static void * ef_server_listenertrafout(struct node * node){ + return listenertrafout((struct srvparam *)node->value); +} + static void * ef_server_childcount(struct node * node){ return &((struct srvparam *)node->value) -> childcount; } @@ -896,6 +904,8 @@ static struct property prop_server[] = { {"childcount", ef_server_childcount, TYPE_INTEGER, "number of servers connected"}, {"listenerclients", ef_server_listenerclients, TYPE_UNSIGNED64, "clients connected to the listening socket, of its services old and new"}, {"listenerprocessed", ef_server_listenerprocessed, TYPE_UNSIGNED64, "clients of the listening socket done with"}, + {"listenertrafin", ef_server_listenertrafin, TYPE_UNSIGNED64, "bytes from servers to the clients of the listening socket, as logged"}, + {"listenertrafout", ef_server_listenertrafout, TYPE_UNSIGNED64, "bytes from the clients of the listening socket, as logged"}, {"maxchild", ef_server_maxchild, TYPE_INTEGER, "max concurrent connections"}, {"backlog", ef_server_backlog, TYPE_INTEGER, "listen backlog"}, {"needuser", ef_server_needuser, TYPE_INTEGER, "require user authentication"}, diff --git a/src/log.c b/src/log.c index b498556..db7e70f 100644 --- a/src/log.c +++ b/src/log.c @@ -25,6 +25,9 @@ void dolog(struct clientparam * param, const unsigned char *s){ void clearstat(struct clientparam * param) { + /* the traffic logged, or dropped, counted for the listener first */ + if(param->srv && listenertrafficfunc && (param->statssrv64 || param->statscli64)) + (*listenertrafficfunc)(param); #ifdef _WIN32 struct timeb tb; diff --git a/src/proxy.h b/src/proxy.h index 89cd6ee..66ca224 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -406,6 +406,11 @@ extern int (*reattachfunc)(struct clientparam *param, int auth); int clientauth(struct clientparam *param); uint64_t *listenerclients(struct srvparam *srv); uint64_t *listenerprocessed(struct srvparam *srv); +uint64_t *listenertrafin(struct srvparam *srv); +uint64_t *listenertrafout(struct srvparam *srv); +void listenertraffic(struct clientparam *param); +/* listenertraffic() where services have listeners, NULL elsewhere */ +extern void (*listenertrafficfunc)(struct clientparam *param); struct passwords * copypwl (struct passwords *pwl); void freepwl(struct passwords *pw); int copyfilter(struct filter *, struct srvparam *srv); diff --git a/src/proxymain.c b/src/proxymain.c index 2784b77..a8771e2 100644 --- a/src/proxymain.c +++ b/src/proxymain.c @@ -906,6 +906,9 @@ struct listener { /* its clients, whichever of its services, old or new, they came to: those connected now, and those done with */ uint64_t clients, processed; + /* the traffic of its clients as logged: from the server (%I) and + from the client (%O) */ + uint64_t trafin, trafout; _3proxy_mutex_t count_mutex; }; @@ -923,6 +926,18 @@ static void listenercount(struct srvparam *srv, int delta){ _3proxy_mutex_unlock(&l->count_mutex); } +/* The traffic of a client, about to be cleared once logged, counted for + its listener. */ +void listenertraffic(struct clientparam *param){ + struct listener *l = param->srv->listener; + + if(!l) return; + _3proxy_mutex_lock(&l->count_mutex); + l->trafin += param->statssrv64; + l->trafout += param->statscli64; + _3proxy_mutex_unlock(&l->count_mutex); +} + static uint64_t nocount = 0; /* The counters of a running service's listener, for the admin pages; the @@ -934,6 +949,14 @@ uint64_t *listenerclients(struct srvparam *srv){ uint64_t *listenerprocessed(struct srvparam *srv){ return srv->listener? &srv->listener->processed : &nocount; } + +uint64_t *listenertrafin(struct srvparam *srv){ + return srv->listener? &srv->listener->trafin : &nocount; +} + +uint64_t *listenertrafout(struct srvparam *srv){ + return srv->listener? &srv->listener->trafout : &nocount; +} static struct listener *listeners = NULL; _3proxy_mutex_t listener_mutex; diff --git a/tests/cases/takeover.py b/tests/cases/takeover.py index 6907d69..2da8ec1 100644 --- a/tests/cases/takeover.py +++ b/tests/cases/takeover.py @@ -76,15 +76,25 @@ def run(t): page = t.http(f"http://127.0.0.1:{adm}/S").text m = re.search(r"type of the service/clientlistenerclients.*?CDATA\[(\d+)\]" - r".*?listenerprocessed.*?CDATA\[(\d+)\]", page, re.S) - return (int(m.group(1)), int(m.group(2))) if m else (None, None) + r".*?listenerprocessed.*?CDATA\[(\d+)\]" + r".*?listenertrafin.*?CDATA\[(\d+)\]" + r".*?listenertrafout.*?CDATA\[(\d+)\]", page, re.S) + return tuple(int(v) for v in m.groups()) if m else (None,) * 4 - clients, processed = listener_counts("PROXY") + clients, processed, trafin, trafout = listener_counts("PROXY") t.eq(0, clients, "no client is connected to the proxy's listener after the run") total = done["ok"] + done["failed"] t.ok(f"its count of clients done with goes on through the reloads ({processed} of {total})") \ if processed is not None and processed >= total else \ t.fail("its count of clients done with goes on through the reloads", f"at least {total}", processed) + # and the traffic as logged: each answer brings 2000 bytes of body, each + # request a few dozen bytes + t.ok(f"the traffic from servers is counted through the reloads ({trafin} bytes)") \ + if trafin is not None and trafin >= 2000 * done["ok"] else \ + t.fail("the traffic from servers is counted through the reloads", f"at least {2000 * done['ok']}", trafin) + t.ok(f"and the traffic from clients ({trafout} bytes)") \ + if trafout is not None and trafout >= 50 * done["ok"] else \ + t.fail("and the traffic from clients", f"at least {50 * done['ok']}", trafout) # --- UDP: the socket is handed over too, and a session of the old # service goes on through it, its datagrams forwarded by the new one ---