diff --git a/Makefile b/Makefile index 24ae846..6b5c09b 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ CC ?= gcc CFLAGS ?=-Wall -g $(CFLAGS_COV) LIBS= -OBJS=sslh-conf.o common.o sslh-main.o probe.o tls.o argtable3.o udp-listener.o +OBJS=sslh-conf.o common.o sslh-main.o probe.o tls.o argtable3.o udp-listener.o collection.o CONDITIONAL_TARGETS= diff --git a/collection.c b/collection.c new file mode 100644 index 0000000..8255631 --- /dev/null +++ b/collection.c @@ -0,0 +1,131 @@ +/* + collection.c: management of a collection of connections, for sslh-select + +# Copyright (C) 2021 Yves Rutschle +# +# This program is free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more +# details. +# +# The full text for the General Public License is here: +# http://www.gnu.org/licenses/gpl.html + +*/ + +#include "common.h" +#include "collection.h" +#include "sslh-conf.h" + + +/* Info to keep track of all connections */ +struct cnx_collection { + int num_cnx; /* Number of connections in *cnx */ + struct connection *cnx; /* pointer to array of connections */ +}; + +/* cnx_num_alloc is the number of connection to allocate at once (at start-up, + * and then every time we get too many simultaneous connections: e.g. start + * with 100 slots, then if we get more than 100 connections allocate another + * 100 slots, and so on). We never free up connection structures. We try to + * allocate as many structures at once as will fit in one page (which is 102 + * in sslh 1.9 on Linux on x86) + */ +static long cnx_num_alloc; + + + +/* Allocates and initialises a new collection of connections. */ +cnx_collection* collection_init(void) +{ + int i; + cnx_collection* collection; + + collection = malloc(sizeof(*collection)); + CHECK_ALLOC(collection, "malloc(collection)"); + + memset(collection, 0, sizeof(*collection)); + cnx_num_alloc = getpagesize() / sizeof(struct connection); + + collection->num_cnx = cnx_num_alloc; /* Start with a set pool of slots */ + collection->cnx = malloc(collection->num_cnx * sizeof(struct connection)); + CHECK_ALLOC(collection->cnx, "malloc(collection->cnx)"); + + for (i = 0; i < collection->num_cnx; i++) { + init_cnx(&collection->cnx[i]); + } + return collection; +} + +void collection_destroy(cnx_collection* collection) +{ + free(collection); +} + +/* Increases the number of slots available in a collection of connections + * After calling, collection->cnx might have moved + * */ +static int collection_extend(struct cnx_collection* collection) +{ + struct connection* new; + int i, new_length = collection->num_cnx + cnx_num_alloc; + + if (cfg.verbose) + fprintf(stderr, "allocating %ld more slots (target: %d).\n", cnx_num_alloc, new_length); + new = realloc(collection->cnx, new_length * sizeof(collection->cnx[0])); + if (!new) return -1; + + collection->cnx = new; + + for (i = collection->num_cnx; i < new_length; i++) { + init_cnx(&collection->cnx[i]); + } + collection->num_cnx = new_length; + return 0; +} + + +int collection_add_fd(struct cnx_collection* collection, int fd) +{ + int free, res; + struct connection* cnx = collection->cnx; + + /* Find an empty slot */ + for (free = 0; (free < collection->num_cnx) && (cnx[free].q[0].fd != -1); free++) { + /* nothing */ + } + if (free >= collection->num_cnx) { + res = collection_extend(collection); + if (res) { + log_message(LOG_ERR, "unable to extend collection -- dropping connection\n"); + return -1; + } + } + collection->cnx[free].q[0].fd = fd; + collection->cnx[free].state = ST_PROBING; + collection->cnx[free].probe_timeout = time(NULL) + cfg.timeout; + + if (cfg.verbose) + fprintf(stderr, "accepted fd %d on slot %d\n", fd, free); + return 0; +} + + +/* Returns the indexed connection in the collection */ +struct connection* collection_get_cnx(struct cnx_collection* collection, int index) +{ + return & collection->cnx[index]; +} + +/* Returns the number of connections in the collection */ +int collection_get_length(cnx_collection* collection) +{ + return collection->num_cnx; +} diff --git a/sslh-select.c b/sslh-select.c index c0a2030..b83fac7 100644 --- a/sslh-select.c +++ b/sslh-select.c @@ -24,6 +24,7 @@ #include "common.h" #include "probe.h" +#include "collection.h" const char* server_type = "sslh-select"; @@ -36,58 +37,6 @@ struct select_info { fd_set fds_r, fds_w; /* reference fd sets (used to init working copies) */ }; -/* Info to keep track of all connections */ -struct cnx_collection { - int num_cnx; /* Number of connections in *cnx */ - struct connection *cnx; /* pointer to array of connections */ -}; - -/* cnx_num_alloc is the number of connection to allocate at once (at start-up, - * and then every time we get too many simultaneous connections: e.g. start - * with 100 slots, then if we get more than 100 connections allocate another - * 100 slots, and so on). We never free up connection structures. We try to - * allocate as many structures at once as will fit in one page (which is 102 - * in sslh 1.9 on Linux on x86) - */ -static long cnx_num_alloc; - -static void init_collection(struct cnx_collection* collection) -{ - int i; - - memset(collection, 0, sizeof(*collection)); - cnx_num_alloc = getpagesize() / sizeof(struct connection); - - collection->num_cnx = cnx_num_alloc; /* Start with a set pool of slots */ - collection->cnx = malloc(collection->num_cnx * sizeof(struct connection)); - CHECK_ALLOC(collection->cnx, "malloc"); - - for (i = 0; i < collection->num_cnx; i++) { - init_cnx(&collection->cnx[i]); - } -} - -/* Increases the number of slots available in a collection of connections - * After calling, collection->cnx might have moved - * */ -static int extend_collection(struct cnx_collection* collection) -{ - struct connection* new; - int i, new_length = collection->num_cnx + cnx_num_alloc; - - if (cfg.verbose) - fprintf(stderr, "allocating %ld more slots (target: %d).\n", cnx_num_alloc, new_length); - new = realloc(collection->cnx, new_length * sizeof(collection->cnx[0])); - if (!new) return -1; - - collection->cnx = new; - - for (i = collection->num_cnx; i < new_length; i++) { - init_cnx(&collection->cnx[i]); - } - collection->num_cnx = new_length; - return 0; -} @@ -142,8 +91,7 @@ static int fd_is_in_range(int fd) { * connexion */ static int accept_new_connection(int listen_socket, struct cnx_collection *collection) { - int in_socket, free, res; - struct connection* cnx = collection->cnx; + int in_socket, res; in_socket = accept(listen_socket, 0, 0); CHECK_RES_RETURN(in_socket, "accept", -1); @@ -159,24 +107,11 @@ static int accept_new_connection(int listen_socket, struct cnx_collection *colle return -1; } - /* Find an empty slot */ - for (free = 0; (free < collection->num_cnx) && (cnx[free].q[0].fd != -1); free++) { - /* nothing */ + res = collection_add_fd(collection, in_socket); + if (res == -1) { + close(in_socket); + return -1; } - if (free >= collection->num_cnx) { - res = extend_collection(collection); - if (res) { - log_message(LOG_ERR, "unable to extend collection -- dropping connection\n"); - close(in_socket); - return -1; - } - } - collection->cnx[free].q[0].fd = in_socket; - collection->cnx[free].state = ST_PROBING; - collection->cnx[free].probe_timeout = time(NULL) + cfg.timeout; - - if (cfg.verbose) - fprintf(stderr, "accepted fd %d on slot %d\n", in_socket, free); return in_socket; } @@ -431,7 +366,7 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) struct timeval tv; int i, j, res; int in_socket = 0; - struct cnx_collection collection; + cnx_collection* collection; fd_info.num_probing = 0; FD_ZERO(&fd_info.fds_r); @@ -443,7 +378,7 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) } fd_info.max_fd = listen_sockets[num_addr_listen-1].socketfd + 1; - init_collection(&collection); + collection = collection_init(); while (1) { @@ -464,7 +399,7 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) /* Check main socket for new connections */ for (i = 0; i < num_addr_listen; i++) { if (FD_ISSET(listen_sockets[i].socketfd, &readfds)) { - in_socket = accept_new_connection(listen_sockets[i].socketfd, &collection); + in_socket = accept_new_connection(listen_sockets[i].socketfd, collection); if (in_socket > 0) { fd_info.num_probing++; FD_SET(in_socket, &fd_info.fds_r); @@ -475,8 +410,8 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) } /* Check all sockets for write activity */ - for (i = 0; i < collection.num_cnx; i++) { - struct connection* cnx = &collection.cnx[i]; + for (i = 0; i < collection_get_length(collection); i++) { + struct connection* cnx = collection_get_cnx(collection, i); if (cnx->q[0].fd != -1) { for (j = 0; j < 2; j++) { if (is_fd_active(cnx->q[j].fd, &writefds)) { @@ -500,8 +435,8 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) } /* Check all sockets for read activity */ - for (i = 0; i < collection.num_cnx; i++) { - struct connection* cnx = &collection.cnx[i]; + for (i = 0; i < collection_get_length(collection); i++) { + struct connection* cnx = collection_get_cnx(collection, i); for (j = 0; j < 2; j++) { if (is_fd_active(cnx->q[j].fd, &readfds) || ((cnx->state == ST_PROBING) && (cnx->probe_timeout < time(NULL)))) {