sslh/collection.c

132 lines
3.9 KiB
C

/*
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;
}