refactor: move udp timeout management to udp module

This commit is contained in:
yrutschle 2021-11-09 18:27:52 +01:00
parent d4d9dbb8e7
commit 207d482189
5 changed files with 57 additions and 62 deletions

View File

@ -27,10 +27,10 @@ CC ?= gcc
CFLAGS ?=-Wall -DLIBPCRE -g $(CFLAGS_COV)
LIBS=-lm -lpcre2-8
OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o argtable3.o udp-listener.o collection.o gap.o
OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o argtable3.o collection.o gap.o
FORK_OBJS=sslh-fork.o $(OBJS)
SELECT_OBJS=sslh-select.o $(OBJS) processes.o
EV_OBJS=sslh-ev.o $(OBJS) processes.o
SELECT_OBJS=sslh-select.o $(OBJS) processes.o udp-listener.o
EV_OBJS=sslh-ev.o $(OBJS) processes.o udp-listener.o
CONDITIONAL_TARGETS=

View File

@ -224,7 +224,7 @@ int cnx_accept_process(struct loop_info* fd_info, struct listen_endpoint* listen
break;
case SOCK_DGRAM:
new_fd = udp_c2s_forward(fd, fd_info->collection, watchers_maxfd(fd_info->watchers));
new_fd = udp_c2s_forward(fd, fd_info);
print_message(msg_fd, "new_fd %d\n", new_fd);
if (new_fd == -1)
return -1;

View File

@ -30,8 +30,6 @@
#define __LINUX__
#include <limits.h>
#include "common.h"
#include "probe.h"
#include "udp-listener.h"
@ -113,41 +111,6 @@ static int fd_is_in_range(int fd) {
/* Check all connections to see if a UDP connections has timed out, then free
* it. At the same time, keep track of the closest, next timeout. Only do the
* search through connections if that timeout actually happened. If the
* connection that would have timed out has had activity, it doesn't matter: we
* go through connections to find the next timeout, which was needed anyway. */
static void udp_timeouts(struct loop_info* fd_info)
{
time_t now = time(NULL);
if (now < fd_info->next_timeout) return;
time_t next_timeout = INT_MAX;
for (int i = 0; i < watchers_maxfd(fd_info->watchers); i++) {
/* if it's either in read or write set, there is a connection
* behind that file descriptor */
struct connection* cnx = collection_get_cnx_from_fd(fd_info->collection, i);
if (cnx) {
time_t timeout = udp_timeout(cnx);
if (!timeout) continue; /* Not a UDP connection */
if (cnx && (timeout <= now)) {
print_message(msg_fd, "timed out UDP %d\n", cnx->target_sock);
close(cnx->target_sock);
watchers_del_read(fd_info->watchers, i);
watchers_del_write(fd_info->watchers, i);
collection_remove_cnx(fd_info->collection, cnx);
} else {
if (timeout < next_timeout) next_timeout = timeout;
}
}
}
if (next_timeout != INT_MAX)
fd_info->next_timeout = next_timeout;
}
/* Main loop: the idea is as follow:
* - fds_r and fds_w contain the file descriptors to monitor in read and write
@ -192,10 +155,6 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen)
if (res < 0)
perror("select");
/* UDP timeouts: clear out connections after some idle time */
udp_timeouts(&fd_info);
/* Check main socket for new connections */
for (i = 0; i < num_addr_listen; i++) {
if (FD_ISSET(listen_sockets[i].socketfd, &readfds)) {

View File

@ -20,12 +20,58 @@
*/
#include <limits.h>
#include "common.h"
#include "probe.h"
#include "sslh-conf.h"
#include "udp-listener.h"
/* returns date at which this socket times out. */
static int udp_timeout(struct connection* cnx)
{
if (cnx->type != SOCK_DGRAM) return 0; /* Not a UDP connection */
return cnx->proto->udp_timeout + cnx->last_active;
}
/* Check all connections to see if a UDP connections has timed out, then free
* it. At the same time, keep track of the closest, next timeout. Only do the
* search through connections if that timeout actually happened. If the
* connection that would have timed out has had activity, it doesn't matter: we
* go through connections to find the next timeout, which was needed anyway. */
void udp_timeouts(struct loop_info* fd_info)
{
time_t now = time(NULL);
if (now < fd_info->next_timeout) return;
time_t next_timeout = INT_MAX;
for (int i = 0; i < watchers_maxfd(fd_info->watchers); i++) {
/* if it's either in read or write set, there is a connection
* behind that file descriptor */
struct connection* cnx = collection_get_cnx_from_fd(fd_info->collection, i);
if (cnx) {
time_t timeout = udp_timeout(cnx);
if (!timeout) continue; /* Not a UDP connection */
if (cnx && (timeout <= now)) {
print_message(msg_fd, "timed out UDP %d\n", cnx->target_sock);
close(cnx->target_sock);
watchers_del_read(fd_info->watchers, i);
watchers_del_write(fd_info->watchers, i);
collection_remove_cnx(fd_info->collection, cnx);
} else {
if (timeout < next_timeout) next_timeout = timeout;
}
}
}
if (next_timeout != INT_MAX)
fd_info->next_timeout = next_timeout;
}
/* Find if the specified source has been seen before. -1 if not found
*
* TODO This is linear search and needs to be changed to something better for
@ -53,12 +99,14 @@ static int known_source(cnx_collection* collection, int max_fd, struct sockaddr*
* Returns: >= 0 sockfd of newly allocated socket, for new connections
* -1 otherwise
* */
int udp_c2s_forward(int sockfd, cnx_collection* collection, int max_fd)
int udp_c2s_forward(int sockfd, struct loop_info* fd_info)
{
char addr_str[NI_MAXHOST+1+NI_MAXSERV+1];
struct sockaddr src_addr;
struct addrinfo addrinfo;
struct sslhcfg_protocols_item* proto;
cnx_collection* collection = fd_info->collection;
int max_fd = watchers_maxfd(fd_info->watchers);
struct connection* cnx;
ssize_t len;
socklen_t addrlen;
@ -67,6 +115,8 @@ int udp_c2s_forward(int sockfd, cnx_collection* collection, int max_fd)
This will do. Dynamic allocation is possible with the MSG_PEEK flag in recvfrom(2), but that'd imply
malloc/free overhead for each packet, when really 64K is not that much */
udp_timeouts(fd_info);
addrlen = sizeof(src_addr);
len = recvfrom(sockfd, data, sizeof(data), 0, &src_addr, &addrlen);
if (len < 0) {
@ -125,12 +175,3 @@ void udp_s2c_forward(struct connection* cnx)
cnx->last_active = time(NULL);
}
/* returns date at which this socket times out. */
int udp_timeout(struct connection* cnx)
{
if (cnx->type != SOCK_DGRAM) return 0; /* Not a UDP connection */
return cnx->proto->udp_timeout + cnx->last_active;
}

View File

@ -2,6 +2,7 @@
#define UDPLISTENER_H
#include "collection.h"
#include "processes.h"
#include "common.h"
/* UDP listener: upon incoming packet, find where it should go
@ -15,15 +16,9 @@ void udp_listener(struct listen_endpoint* endpoint, int num_endpoints, int activ
* Returns: >= 0 sockfd of newly allocated socket, for new connections
* -1 otherwise
* */
int udp_c2s_forward(int sockfd, cnx_collection* collection, int max_fd);
int udp_c2s_forward(int sockfd, struct loop_info* fd_info);
/* Process UDP coming from inside (server towards client) */
void udp_s2c_forward(struct connection* cnx);
/* returns how many seconds before socket times out. Negative if timed out
* already.
*/
int udp_timeout(struct connection* cnx);
#endif /* UDPLISTENER_H */