From 1361f0e88138653d2437f45ddf940206ed0e93b7 Mon Sep 17 00:00:00 2001 From: Jakub Sławiński Date: Thu, 6 Apr 2006 23:34:51 +0200 Subject: v0.8.1 - Fixed: enableproxy option in server's config file - Added: clients idle time - Added: 'maxidle' option - Modified: task scheduling subsystem has been completely rewritten - Fixed: segmentation fault in http tunnels after multiple simultaneous POST connections from the same source - Fixed: unexpected connection close when http proxy was too slow - Fixed: SIGSEGV in http proxy mode under cygwin - Added: enabled the SO_KEEPALIVE option for all the sockets used by the apf - Added: 60 seconds timeout for SSL_connect --- ChangeLog | 12 ++ NEWS | 3 + README | 5 +- configure.ac | 4 +- doc/afclient.1 | 2 +- doc/afclient.conf.5 | 2 +- doc/afserver.1 | 8 +- doc/afserver.conf.5 | 7 +- doc/afserver_example.conf | 1 + doc/en/README | 5 +- src/Makefile.am | 19 +- src/activefor.h | 2 +- src/afclient.c | 2 + src/afserver.c | 233 ++++++++++++--------- src/afserver.h | 1 + src/client_initialization.c | 5 + src/client_signals.c | 20 +- src/client_signals.h | 1 + src/connect_client_struct.c | 71 +++++++ src/connect_client_struct.h | 7 + src/file_server.c | 7 + src/http_proxy_client.c | 40 ++-- src/http_proxy_functions.c | 19 +- src/http_proxy_functions.h | 1 + src/http_proxy_server.c | 44 +++- src/network.c | 478 +++++++++++++++++++++++--------------------- src/remove_client_task.c | 134 +++++++++++++ src/remove_client_task.h | 47 +++++ src/server_realm_struct.c | 68 +++++++ src/server_realm_struct.h | 6 + src/server_remoteadmin.c | 8 + src/server_remove.c | 26 ++- src/server_remove.h | 5 +- src/task_list_node_struct.c | 124 ++++++++++++ src/task_list_node_struct.h | 42 ++++ src/task_scheduler_struct.c | 321 +++++++++++++++++++++++++++++ src/task_scheduler_struct.h | 47 +++++ src/task_struct.c | 122 +++++++++++ src/task_struct.h | 39 ++++ src/timeval_functions.c | 94 +++++++++ src/timeval_functions.h | 3 + src/usage.c | 4 +- 42 files changed, 1692 insertions(+), 397 deletions(-) create mode 100644 src/remove_client_task.c create mode 100644 src/remove_client_task.h create mode 100644 src/task_list_node_struct.c create mode 100644 src/task_list_node_struct.h create mode 100644 src/task_scheduler_struct.c create mode 100644 src/task_scheduler_struct.h create mode 100644 src/task_struct.c create mode 100644 src/task_struct.h diff --git a/ChangeLog b/ChangeLog index b9aeb51..a7895db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +06.04.2006 (v0.8.1): + - Fixed: enableproxy option in server's config file + - Added: clients idle time + - Added: 'maxidle' option + - Modified: task scheduling subsystem has been completely rewritten + - Fixed: segmentation fault in http tunnels after multiple simultaneous POST + connections from the same source + - Fixed: unexpected connection close when http proxy was too slow + - Fixed: SIGSEGV in http proxy mode under cygwin + - Added: enabled the SO_KEEPALIVE option for all the sockets used by the apf + - Added: 60 seconds timeout for SSL_connect + 04.02.2006 (v0.8): - Fixed: infinite loop after buffering message - Fixed: corrupt packets after closing connections in the stopped state diff --git a/NEWS b/NEWS index 15a5a0c..f566ebb 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +16.03.2006: + * configure and other scripts have been updated + 05.02.2006: * debug feature (default is NO) has been added to the configure script diff --git a/README b/README index cea4c66..11c3fe6 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -AF - Active Port Forwarder 0.8 - README +AF - Active Port Forwarder 0.8.1 - README Copyright (C) 2003-2006 jeremian - ================================================================= @@ -136,9 +136,10 @@ Multiple clients allow to create more sophisticated tunneling scheme. active forwarder (server) -D, --dateformat - format of the date printed in logs (see 'man strftime' for details) (default: %d.%m.%Y %H:%M:%S) - -t, --timeout - the timeout value for the client's connection (default: 5) + --maxidle - the maximum idle time for the client's connection + (default: disabled) -u, --users - the amount of users allowed to use this server (default: 5) -C, --clients - the number of allowed clients to use this server diff --git a/configure.ac b/configure.ac index 761e9fe..b09785c 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) -AC_INIT([Active port forwarder], [0.8], [jeremian@poczta.fm], [apf]) -AM_INIT_AUTOMAKE([apf], [0.8]) +AC_INIT([Active port forwarder], [0.8.1], [jeremian@poczta.fm], [apf]) +AM_INIT_AUTOMAKE([apf], [0.8.1]) AC_COPYRIGHT([ Copyright (C) 2003-2006 jeremian - =================== diff --git a/doc/afclient.1 b/doc/afclient.1 index a7833b1..eac49b4 100644 --- a/doc/afclient.1 +++ b/doc/afclient.1 @@ -1,4 +1,4 @@ -.TH afclient 1 "apf 0.8" Jeremian +.TH afclient 1 "apf 0.8.1" Jeremian .SH NAME afclient \- active port forwarder client .SH SYNOPSIS diff --git a/doc/afclient.conf.5 b/doc/afclient.conf.5 index abd9dd2..35be286 100644 --- a/doc/afclient.conf.5 +++ b/doc/afclient.conf.5 @@ -1,4 +1,4 @@ -.TH afclient.conf 5 "apf 0.8" Jeremian +.TH afclient.conf 5 "apf 0.8.1" Jeremian .SH NAME afclient.conf \- Configuration File for afclient .SH INTRODUCTION diff --git a/doc/afserver.1 b/doc/afserver.1 index 0691ebd..856bbe8 100644 --- a/doc/afserver.1 +++ b/doc/afserver.1 @@ -1,4 +1,4 @@ -.TH afserver 1 "apf 0.8" Jeremian +.TH afserver 1 "apf 0.8.1" Jeremian .SH NAME afserver \- active port forwarder server .SH SYNOPSIS @@ -37,6 +37,9 @@ which redirects it to the specified destination host:port. .I afclient connects to it (default: 50126) +.B -V, --version + display version number + .B -h, --help prints help screen @@ -63,6 +66,9 @@ connects to it (default: 50126) .B -t, --timeout N the timeout value for the client's connection (default: 5) +.B --maxidle N + the maximum idle time for the client's connection (default: disabled) + .B -u, --users N the amount of users allowed to use this server (default: 5) diff --git a/doc/afserver.conf.5 b/doc/afserver.conf.5 index a86ff78..7a17eda 100644 --- a/doc/afserver.conf.5 +++ b/doc/afserver.conf.5 @@ -1,4 +1,4 @@ -.TH afserver.conf 5 "apf 0.8" Jeremian +.TH afserver.conf 5 "apf 0.8.1" Jeremian .SH NAME afserver.conf \- Configuration File for afserver .SH INTRODUCTION @@ -68,7 +68,10 @@ commands. .B timeout N the timeout value for the client's connection (default: 5) - + +.B --maxidle N + the maximum idle time for the client's connection (default: disabled) + .B clients N the number of allowed clients to use this server (default: 1) diff --git a/doc/afserver_example.conf b/doc/afserver_example.conf index e96ec02..a11f5c1 100644 --- a/doc/afserver_example.conf +++ b/doc/afserver_example.conf @@ -32,6 +32,7 @@ listenport 50127 #portnumber on which server is listening for users manageport 50126 #portnumber on which server is listening for afclient #users 5 #amount of users we are allowing to connect (>0) (default: 5) #timeout 5 #timeout value for the client's connection (>0) (default: 5) +#maxidle 300 #the maximum idle time for the client's connection (>0) (default: disabled) #clients 1 #number of allowed clients for this realm (>0) (default: 1) #usrpcli $users #allowed users per client for this realm (>0) (default: $users) #climode 1 #strategy used for connecting users with clients (1) (default: 1) diff --git a/doc/en/README b/doc/en/README index cea4c66..11c3fe6 100644 --- a/doc/en/README +++ b/doc/en/README @@ -1,4 +1,4 @@ -AF - Active Port Forwarder 0.8 - README +AF - Active Port Forwarder 0.8.1 - README Copyright (C) 2003-2006 jeremian - ================================================================= @@ -136,9 +136,10 @@ Multiple clients allow to create more sophisticated tunneling scheme. active forwarder (server) -D, --dateformat - format of the date printed in logs (see 'man strftime' for details) (default: %d.%m.%Y %H:%M:%S) - -t, --timeout - the timeout value for the client's connection (default: 5) + --maxidle - the maximum idle time for the client's connection + (default: disabled) -u, --users - the amount of users allowed to use this server (default: 5) -C, --clients - the number of allowed clients to use this server diff --git a/src/Makefile.am b/src/Makefile.am index 68e6679..f16461a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,16 +6,15 @@ afserver_SOURCES = afserver.c network.c file.c stats.c buf_list_node_struct.c bu thread_management.c server_signals.c usage.c logging.c daemon.c ssl_fd_struct.c \ user_stats_struct.c usr_cli_struct.c connect_user_struct.c string_functions.c \ audit_list_node_struct.c audit_list_struct.c connect_client_struct.c timeval_functions.c \ - header_buffer_struct.c server_realm_struct.c server_configuration_struct.c file_server.c + header_buffer_struct.c server_realm_struct.c server_configuration_struct.c file_server.c \ + task_struct.c task_list_node_struct.c task_scheduler_struct.c remove_client_task.c afclient_LDFLAGS = ${USE_RDYNAMIC} ${LINKED_LDLIB} afclient_SOURCES = afclient.c network.c file.c stats.c buf_list_node_struct.c buf_list_struct.c \ module_struct.c client_remoteadmin.c make_ssl_handshake.c first_run.c inet_ntop.c \ - realmnames.c usernames.c http_proxy_functions.c http_proxy_client.c \ - http_proxy_options_struct.c thread_management.c client_reverse_udp.c server_check.c \ - client_initialization.c client_shutdown.c client_signals.c usage.c logging.c \ - daemon.c base64.c ssl_routines.c connect_user_struct.c user_stats_struct.c \ - string_functions.c ar_options_struct.c audit_list_node_struct.c audit_list_struct.c \ - ssl_fd_struct.c timeval_functions.c server_realm_struct.c server_configuration_struct.c \ - usr_cli_struct.c connect_client_struct.c header_buffer_struct.c \ - client_configuration_struct.c file_client.c client_realm_struct.c \ - port_list_node_struct.c port_list_struct.c + http_proxy_functions.c http_proxy_client.c http_proxy_options_struct.c \ + thread_management.c client_reverse_udp.c server_check.c client_initialization.c \ + client_shutdown.c client_signals.c usage.c logging.c daemon.c base64.c ssl_routines.c \ + connect_user_struct.c user_stats_struct.c string_functions.c ar_options_struct.c \ + audit_list_node_struct.c audit_list_struct.c ssl_fd_struct.c timeval_functions.c \ + usr_cli_struct.c header_buffer_struct.c client_configuration_struct.c file_client.c \ + client_realm_struct.c port_list_node_struct.c port_list_struct.c diff --git a/src/activefor.h b/src/activefor.h index 9ce940b..8f127aa 100644 --- a/src/activefor.h +++ b/src/activefor.h @@ -53,7 +53,7 @@ #define S_STATE_OPENING_CLOSED 17 #define S_STATE_KICKING 19 -#define AF_VER(info) info" v0.8" +#define AF_VER(info) info" v0.8.1" #define TYPE_TCP 1 #define TYPE_UDP 3 diff --git a/src/afclient.c b/src/afclient.c index ec02e36..7d0ab20 100644 --- a/src/afclient.c +++ b/src/afclient.c @@ -155,6 +155,8 @@ main(int argc, char **argv) act.sa_handler = client_sig_int; sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); + act.sa_handler = client_sig_alrm; + sigaction(SIGALRM, &act, NULL); #ifdef HAVE_LIBPTHREAD remember_mainthread(); diff --git a/src/afserver.c b/src/afserver.c index 2ec71d1..bbc115d 100644 --- a/src/afserver.c +++ b/src/afserver.c @@ -28,6 +28,7 @@ static struct option long_options[] = { {"listenport", 1, 0, 'l'}, {"manageport", 1, 0, 'm'}, {"timeout", 1, 0, 't'}, + {"maxidle", 1, 0, 321}, {"verbose", 0, 0, 'v'}, {"users", 1, 0, 'u'}, {"clients", 1, 0, 'C'}, @@ -71,7 +72,7 @@ main(int argc, char **argv) unsigned char buff[9000]; int maxfdp1; fd_set rset, allset, wset, tmpset; - int manconnecting, numofcon, length; + int numofcon, length; char* name = NULL; char** listen = NULL; int listencount = 0; @@ -85,6 +86,7 @@ main(int argc, char **argv) char* filenam = NULL; char* type = NULL; char* timeout = NULL; + char* maxidle = NULL; char* realmname = NULL; unsigned char pass[4] = {1, 2, 3, 4}; char verbose = 0; @@ -97,6 +99,8 @@ main(int argc, char **argv) char audit = 0; char dnslookups = 0; ServerRealm* pointer = NULL; + TaskScheduler* scheduler; + Task* task; struct sigaction act; time_t now; ServerRealm** scRealmsTable; @@ -173,6 +177,10 @@ main(int argc, char **argv) timeout = optarg; break; } + case 321: { + maxidle = optarg; + break; + } case 'v': { ++verbose; break; @@ -436,6 +444,7 @@ main(int argc, char **argv) ServerRealm_set_sClientsLimit(pointer, clients); ServerRealm_set_sRaClientsLimit(pointer, raclients); ServerRealm_set_sTimeout(pointer, timeout); + ServerRealm_set_sMaxIdle(pointer, maxidle); ServerRealm_set_sUsersPerClient(pointer, usrpcli); ServerRealm_set_sClientMode(pointer, clim); ServerRealm_set_basePortOn(pointer, baseport); @@ -483,7 +492,7 @@ main(int argc, char **argv) ServerRealm_set_realmType(pointer, temp); } - maxfdp1 = manconnecting = 0; + maxfdp1 = 0; SSL_library_init(); method = SSLv3_server_method(); @@ -536,6 +545,13 @@ main(int argc, char **argv) if (!verbose) daemon(0, 0); + scheduler = TaskScheduler_new(); + if (scheduler == NULL) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "Problems with creating task scheduler... exiting"); + exit(1); + } + scRealmsTable = ServerConfiguration_get_realmsTable(config); for (i = 0; i < ServerConfiguration_get_realmsNumber(config); ++i) { if (ServerRealm_get_userClientPairs(scRealmsTable[i]) == 0) { @@ -663,6 +679,17 @@ main(int argc, char **argv) ServerRealm_set_sTimeout(scRealmsTable[i], stemp); ServerRealm_set_timeout(scRealmsTable[i], check_value(ServerRealm_get_sTimeout(scRealmsTable[i]), "Invalid timeout value")); + /* checking maxidle value */ + stemp = ServerRealm_get_sMaxIdle(scRealmsTable[i]); + set_value(&stemp, maxidle, "0"); + ServerRealm_set_sMaxIdle(scRealmsTable[i], stemp); + temp = check_value_liberal(ServerRealm_get_sMaxIdle(scRealmsTable[i]), "Invalid maxidle value"); + if (temp < 0) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "Invalid maxidle value: %d\n", temp); + exit(1); + } + ServerRealm_set_maxIdle(scRealmsTable[i], temp); /* checking climode value */ stemp = ServerRealm_get_sClientMode(scRealmsTable[i]); set_value(&stemp, clim, "1"); @@ -899,70 +926,19 @@ main(int argc, char **argv) ServerConfiguration_set_startTime(config, now); for ( ; ; ) { - rset = allset; - tmpset = wset; - aflog(LOG_T_MAIN, LOG_I_DDEBUG, - "select, maxfdp1: %d", maxfdp1); - if (manconnecting) { - /* find out, in what realm client is trying to connect */ - l = -1; - for (k = 0; k < ServerConfiguration_get_realmsNumber(config); ++k) { - srClientsTable = ServerRealm_get_clientsTable(scRealmsTable[k]); - for (j=0; j < ServerRealm_get_clientsLimit(scRealmsTable[k]); ++j) { - if ((ConnectClient_get_state(srClientsTable[j]) == CONNECTCLIENT_STATE_CONNECTING) || - (ConnectClient_get_state(srClientsTable[j]) == CONNECTCLIENT_STATE_AUTHORIZING)) { - i = k; - k = ServerConfiguration_get_realmsNumber(config); - l = 0; - break; /* so i points to first good realm and j to good client */ - } - } - if (l == -1) { - srRaClientsTable = ServerRealm_get_raClientsTable(scRealmsTable[k]); - for (j=0; j < ServerRealm_get_raClientsLimit(scRealmsTable[k]); ++j) { - if ((ConnectClient_get_state(srRaClientsTable[j])==CONNECTCLIENT_STATE_CONNECTING) || - (ConnectClient_get_state(srRaClientsTable[j])==CONNECTCLIENT_STATE_AUTHORIZING)) { - i = k; - k = ServerConfiguration_get_realmsNumber(config); - l = 1; - break; /* so i points to first good realm and j to good client */ - } - } - } - } - if (!l) { - srClientsTable = ServerRealm_get_clientsTable(scRealmsTable[i]); - if (select(maxfdp1,&rset,&tmpset,NULL,ConnectClient_get_timerp(srClientsTable[j])) == 0) { - close(SslFd_get_fd(ConnectClient_get_sslFd(srClientsTable[j]))); - FD_CLR(SslFd_get_fd(ConnectClient_get_sslFd(srClientsTable[j])), &allset); - SSL_clear(SslFd_get_ssl(ConnectClient_get_sslFd(srClientsTable[j]))); - ConnectClient_set_state(srClientsTable[j], CONNECTCLIENT_STATE_FREE); - manconnecting--; - ServerRealm_decrease_connectedClients(scRealmsTable[i]); - aflog(LOG_T_CLIENT, LOG_I_WARNING, - "realm[%s]: Client[%s]: SSL_accept failed (timeout)", - get_realmname(config, i), get_clientname(scRealmsTable[i], j)); - } - } - else { - srRaClientsTable = ServerRealm_get_raClientsTable(scRealmsTable[i]); - if (select(maxfdp1,&rset,&tmpset,NULL,ConnectClient_get_timerp(srRaClientsTable[j]))==0) { - close(SslFd_get_fd(ConnectClient_get_sslFd(srRaClientsTable[j]))); - FD_CLR(SslFd_get_fd(ConnectClient_get_sslFd(srRaClientsTable[j])), &allset); - SSL_clear(SslFd_get_ssl(ConnectClient_get_sslFd(srRaClientsTable[j]))); - ConnectClient_set_state(srRaClientsTable[j], CONNECTCLIENT_STATE_FREE); - manconnecting--; - ServerRealm_decrease_connectedClients(scRealmsTable[i]); - aflog(LOG_T_CLIENT, LOG_I_WARNING, - "realm[%s]: Client[%s] (ra): SSL_accept failed (timeout)", - get_realmname(config, i), get_raclientname(scRealmsTable[i], j)); - } - } - } - else { - select(maxfdp1, &rset, &tmpset, NULL, NULL); - } - aflog(LOG_T_MAIN, LOG_I_DDEBUG, + rset = allset; + tmpset = wset; + aflog(LOG_T_MAIN, LOG_I_DDEBUG, + "select, maxfdp1: %d", maxfdp1); + if (TaskScheduler_hasMoreTasks(scheduler)) { + TaskScheduler_startWatching(scheduler); + select(maxfdp1, &rset, &tmpset, NULL, TaskScheduler_get_actualTimer(scheduler)); + TaskScheduler_stopWatching(scheduler); + } + else { + select(maxfdp1, &rset, &tmpset, NULL, NULL); + } + aflog(LOG_T_MAIN, LOG_I_DDEBUG, "after select..."); for (j = 0; j < ServerConfiguration_get_realmsNumber(config); ++j) { @@ -1263,6 +1239,7 @@ main(int argc, char **argv) aflog(LOG_T_USER, LOG_I_DDEBUG, "realm[%s]: listenfd: FD_ISSET", get_realmname(config, j)); k = find_client(pointer, ServerRealm_get_clientMode(pointer), l); + if (ConnectClient_get_state(srClientsTable[k]) == CONNECTCLIENT_STATE_ACCEPTED) { if (ServerRealm_get_connectedUsers(pointer) == ServerRealm_get_usersLimit(pointer)) { close(sent); @@ -1331,6 +1308,7 @@ main(int argc, char **argv) for (k = 0; k < ServerRealm_get_clientsLimit(pointer); ++k) { if (ConnectClient_get_state(srClientsTable[k]) == CONNECTCLIENT_STATE_ACCEPTED) { if (FD_ISSET(ConnectClient_get_listenFd(srClientsTable[k]), &rset)) { + len = ServerRealm_get_addressLength(pointer); sent = accept(ConnectClient_get_listenFd(srClientsTable[k]), ServerRealm_get_clientAddress(pointer), &len); if (sent == -1) { @@ -1417,7 +1395,10 @@ main(int argc, char **argv) FD_CLR(SslFd_get_fd(ConnectClient_get_sslFd(srClientsTable[k])), &allset); SSL_clear(SslFd_get_ssl(ConnectClient_get_sslFd(srClientsTable[k]))); ConnectClient_set_state(srClientsTable[k], CONNECTCLIENT_STATE_FREE); - manconnecting--; + if ((task = ConnectClient_get_task(srClientsTable[k]))) { + TaskScheduler_removeTask(scheduler, task); + ConnectClient_set_task(srClientsTable[k], NULL); + } ServerRealm_decrease_connectedClients(pointer); aflog(LOG_T_CLIENT, LOG_I_ERR, "realm[%s]: new Client[%s]: DENIED by SSL_accept", @@ -1511,7 +1492,7 @@ main(int argc, char **argv) AuditList_delete_first(ConnectClient_get_auditList(srClientsTable[k])); } } - remove_client(pointer, k, &allset, &wset, &manconnecting); + remove_client(pointer, k, &allset, &wset, scheduler); continue; } @@ -1536,6 +1517,13 @@ main(int argc, char **argv) (buff[0] != AF_S_LOGIN) && (buff[0] != AF_S_ADMIN_LOGIN)) { buff[0] = AF_S_WRONG; } + + time(&now); + ConnectClient_set_lastActivity(srClientsTable[k], now); + if (ServerRealm_get_maxIdle(pointer)) { + ConnectClient_set_timer(srClientsTable[k], timeval_create(ServerRealm_get_maxIdle(pointer), 0)); + TaskScheduler_update(scheduler); + } switch (buff[0]) { case AF_S_CONCLOSED : { @@ -1590,7 +1578,7 @@ main(int argc, char **argv) } } else { - remove_client(pointer, k, &allset, &wset, &manconnecting); + remove_client(pointer, k, &allset, &wset, scheduler); } break; } @@ -1626,7 +1614,7 @@ main(int argc, char **argv) } } else { - remove_client(pointer, k, &allset, &wset, &manconnecting); + remove_client(pointer, k, &allset, &wset, scheduler); } break; } @@ -1654,14 +1642,14 @@ main(int argc, char **argv) } } else { - remove_client(pointer, k, &allset, &wset, &manconnecting); + remove_client(pointer, k, &allset, &wset, scheduler); } break; } case AF_S_MESSAGE : { if (ConnectClient_get_state(srClientsTable[k]) != CONNECTCLIENT_STATE_ACCEPTED) { - remove_client(pointer, k, &allset, &wset, &manconnecting); + remove_client(pointer, k, &allset, &wset, scheduler); break; } if (TYPE_IS_UDP(ServerRealm_get_realmType(pointer))) { /* udp */ @@ -1833,7 +1821,20 @@ main(int argc, char **argv) ConnectClient_get_sslFd( srClientsTable[k]), buff, 5); - manconnecting--; + if ((task = ConnectClient_get_task(srClientsTable[k]))) { + TaskScheduler_removeTask(scheduler, task); + ConnectClient_set_task(srClientsTable[k], NULL); + } + if (ServerRealm_get_maxIdle(pointer)) { + ConnectClient_set_timer(srClientsTable[k], + timeval_create(ServerRealm_get_maxIdle(pointer), 0)); + task = Task_new(ConnectClient_get_timerp(srClientsTable[k]), + RCTfunction, + RCTdata_new(config, j, k, 0, RCT_REASON_MAXIDLE, &allset, &wset), + RCTdata_free); + ConnectClient_set_task(srClientsTable[k], task); + TaskScheduler_addTask(scheduler, task); + } if (ServerRealm_get_basePortOn(pointer) == 1) { long tmp_val; char tmp_tab[6]; @@ -1845,7 +1846,7 @@ main(int argc, char **argv) aflog(LOG_T_CLIENT, LOG_I_ERR, "realm[%s]: INVALID listenport - removing Client[%s]", get_realmname(config, j), get_clientname(pointer, k)); - remove_client(pointer, k, &allset, &wset, &manconnecting); + remove_client(pointer, k, &allset, &wset, scheduler); break; } tmp_val = tmp_val%65536; @@ -1888,7 +1889,7 @@ main(int argc, char **argv) ConnectClient_get_sslFd( srClientsTable[k]), buff, 5); - remove_client(pointer, k, &allset, &wset, &manconnecting); + remove_client(pointer, k, &allset, &wset, scheduler); } } else if ((ConnectClient_get_state(srClientsTable[k]) == @@ -1912,7 +1913,7 @@ main(int argc, char **argv) ConnectClient_get_sslFd( srClientsTable[k]), buff, 5); - remove_client(pointer, k, &allset, &wset, &manconnecting); + remove_client(pointer, k, &allset, &wset, scheduler); } break; } @@ -1950,7 +1951,7 @@ main(int argc, char **argv) aflog(LOG_T_CLIENT, LOG_I_ERR, "realm[%s]: Client[%s]: Wrong message - CLOSING", get_realmname(config, j), get_clientname(pointer, k)); - remove_client(pointer, k, &allset, &wset, &manconnecting); + remove_client(pointer, k, &allset, &wset, scheduler); break; } case AF_S_ADMIN_LOGIN: { @@ -1971,6 +1972,9 @@ main(int argc, char **argv) ConnectClient_set_connectTime( srRaClientsTable[l], ConnectClient_get_connectTime(srClientsTable[k])); + ConnectClient_set_lastActivity( + srRaClientsTable[l], + ConnectClient_get_lastActivity(srClientsTable[k])); #ifdef HAVE_LIBPTHREAD ConnectClient_set_tunnelType( srRaClientsTable[l], @@ -2005,7 +2009,10 @@ main(int argc, char **argv) srRaClientsTable[l], CONNECTCLIENT_STATE_ACCEPTED); ServerRealm_increase_connectedRaClients(pointer); - manconnecting--; + if ((task = ConnectClient_get_task(srClientsTable[k]))) { + TaskScheduler_removeTask(scheduler, task); + ConnectClient_set_task(srClientsTable[k], NULL); + } sprintf((char*) &buff[5], AF_VER("AFSERVER")); n = strlen((char*) &buff[5]); buff[0] = AF_S_ADMIN_LOGIN; /* sending message */ @@ -2027,7 +2034,7 @@ main(int argc, char **argv) ConnectClient_get_sslFd( srClientsTable[k]), buff, 5); - remove_client(pointer, k, &allset, &wset, &manconnecting); + remove_client(pointer, k, &allset, &wset, scheduler); } } break; @@ -2049,7 +2056,7 @@ main(int argc, char **argv) aflog(LOG_T_CLIENT, LOG_I_ERR, "realm[%s]: Client[%s]: Unrecognized message - CLOSING", get_realmname(config, j), get_clientname(pointer, k)); - remove_client(pointer, k, &allset, &wset, &manconnecting); + remove_client(pointer, k, &allset, &wset, scheduler); } } } @@ -2068,7 +2075,10 @@ main(int argc, char **argv) FD_CLR(SslFd_get_fd(ConnectClient_get_sslFd(srRaClientsTable[k])), &allset); SSL_clear(SslFd_get_ssl(ConnectClient_get_sslFd(srRaClientsTable[k]))); ConnectClient_set_state(srRaClientsTable[k], CONNECTCLIENT_STATE_FREE); - manconnecting--; + if ((task = ConnectClient_get_task(srRaClientsTable[k]))) { + TaskScheduler_removeTask(scheduler, task); + ConnectClient_set_task(srRaClientsTable[k], NULL); + } ServerRealm_decrease_connectedClients(pointer); aflog(LOG_T_MANAGE, LOG_I_ERR, "realm[%s]: new Client[%s] (ra): DENIED by SSL_accept", @@ -2123,7 +2133,7 @@ main(int argc, char **argv) } } if (n==0) { - remove_raclient(pointer, k, &allset, &wset, &manconnecting); + remove_raclient(pointer, k, &allset, &wset, scheduler); aflog(LOG_T_MANAGE, LOG_I_INFO, "realm[%s]: Client[%s] (ra): commfd: CLOSED", get_realmname(config, j), get_raclientname(pointer, k)); @@ -2147,6 +2157,9 @@ main(int argc, char **argv) (buff[0] != AF_S_LOGIN) && (buff[0] != AF_S_ADMIN_LOGIN)) { buff[0] = AF_S_WRONG; } + + time(&now); + ConnectClient_set_lastActivity(srRaClientsTable[k], now); switch (buff[0]) { case AF_S_LOGIN : { @@ -2169,6 +2182,9 @@ main(int argc, char **argv) ConnectClient_set_connectTime( srClientsTable[l], ConnectClient_get_connectTime(srRaClientsTable[k])); + ConnectClient_set_lastActivity( + srClientsTable[l], + ConnectClient_get_lastActivity(srRaClientsTable[k])); #ifdef HAVE_LIBPTHREAD ConnectClient_set_tunnelType( srClientsTable[l], @@ -2214,7 +2230,20 @@ main(int argc, char **argv) ConnectClient_get_sslFd( srClientsTable[l]), buff, 5); - manconnecting--; + if ((task = ConnectClient_get_task(srRaClientsTable[k]))) { + TaskScheduler_removeTask(scheduler, task); + ConnectClient_set_task(srRaClientsTable[k], NULL); + } + if (ServerRealm_get_maxIdle(pointer)) { + ConnectClient_set_timer(srClientsTable[l], + timeval_create(ServerRealm_get_maxIdle(pointer), 0)); + task = Task_new(ConnectClient_get_timerp(srClientsTable[l]), + RCTfunction, + RCTdata_new(config, j, l, 0, RCT_REASON_MAXIDLE, &allset, &wset), + RCTdata_free); + ConnectClient_set_task(srClientsTable[l], task); + TaskScheduler_addTask(scheduler, task); + } if (ServerRealm_get_basePortOn(pointer) == 1) { long tmp_val; char tmp_tab[6]; @@ -2226,7 +2255,7 @@ main(int argc, char **argv) aflog(LOG_T_CLIENT, LOG_I_ERR, "realm[%s]: INVALID listenport - removing Client[%s]", get_realmname(config, j), get_clientname(pointer, l)); - remove_client(pointer, l, &allset, &wset, &manconnecting); + remove_client(pointer, l, &allset, &wset, scheduler); break; } tmp_val = tmp_val%65536; @@ -2269,7 +2298,7 @@ main(int argc, char **argv) ConnectClient_get_sslFd( srRaClientsTable[k]), buff, 5); - remove_raclient(pointer, k, &allset, &wset, &manconnecting); + remove_raclient(pointer, k, &allset, &wset, scheduler); } } else if ((ConnectClient_get_state(srRaClientsTable[k]) == @@ -2288,7 +2317,7 @@ main(int argc, char **argv) aflog(LOG_T_MANAGE, LOG_I_ERR, "realm[%s]: Client[%s] (ra): Wrong password - CLOSING", get_realmname(config, j), get_raclientname(pointer, k)); - remove_raclient(pointer, k, &allset, &wset, &manconnecting); + remove_raclient(pointer, k, &allset, &wset, scheduler); } break; } @@ -2296,7 +2325,7 @@ main(int argc, char **argv) aflog(LOG_T_MANAGE, LOG_I_ERR, "realm[%s]: Client[%s] (ra): Wrong message - CLOSING", get_realmname(config, j), get_raclientname(pointer, k)); - remove_raclient(pointer, k, &allset, &wset, &manconnecting); + remove_raclient(pointer, k, &allset, &wset, scheduler); break; } case AF_S_ADMIN_LOGIN: { @@ -2311,7 +2340,10 @@ main(int argc, char **argv) srRaClientsTable[k], CONNECTCLIENT_STATE_ACCEPTED); ServerRealm_increase_connectedRaClients(pointer); - manconnecting--; + if ((task = ConnectClient_get_task(srRaClientsTable[k]))) { + TaskScheduler_removeTask(scheduler, task); + ConnectClient_set_task(srRaClientsTable[k], NULL); + } sprintf((char*) &buff[5], AF_VER("AFSERVER")); n = strlen((char*) &buff[5]); buff[0] = AF_S_ADMIN_LOGIN; /* sending message */ @@ -2334,7 +2366,7 @@ main(int argc, char **argv) aflog(LOG_T_MANAGE, LOG_I_NOTICE, "realm[%s]: Client[%s] (ra): remote admin -- closing", get_realmname(config, j), get_raclientname(pointer, k)); - remove_raclient(pointer, k, &allset, &wset, &manconnecting); + remove_raclient(pointer, k, &allset, &wset, scheduler); } else { for (i = 0; i < ServerConfiguration_get_realmsNumber(config); ++i) { @@ -2394,7 +2426,7 @@ main(int argc, char **argv) } } remove_client(scRealmsTable[i], l, - &allset, &wset, &manconnecting); + &allset, &wset, scheduler); break; } } @@ -2405,7 +2437,7 @@ main(int argc, char **argv) aflog(LOG_T_MANAGE, LOG_I_ERR, "realm[%s]: Client[%s] (ra): remote admin -- security VIOLATION", get_realmname(config, j), get_raclientname(pointer, k)); - remove_raclient(pointer, k, &allset, &wset, &manconnecting); + remove_raclient(pointer, k, &allset, &wset, scheduler); } break; } @@ -2419,13 +2451,14 @@ main(int argc, char **argv) aflog(LOG_T_MANAGE, LOG_I_ERR, "realm[%s]: Client[%s] (ra): Unrecognized message - CLOSING", get_realmname(config, j), get_raclientname(pointer, k)); - remove_raclient(pointer, k, &allset, &wset, &manconnecting); + remove_raclient(pointer, k, &allset, &wset, scheduler); } } } /* ------------------------------------ */ for (l = 0; l < ServerRealm_get_userClientPairs(pointer); ++l) { if (FD_ISSET(UsrCli_get_manageFd(srUsersClientsTable[l]), &rset)) { + aflog(LOG_T_CLIENT, LOG_I_DDEBUG, "realm[%s]: managefd: FD_ISSET", get_realmname(config, j)); len = ServerRealm_get_addressLength(pointer); @@ -2459,6 +2492,7 @@ main(int argc, char **argv) ConnectClient_set_usrCliPair(srClientsTable[k], l); time(&now); ConnectClient_set_connectTime(srClientsTable[k], now); + ConnectClient_set_lastActivity(srClientsTable[k], now); #ifdef HAVE_LIBPTHREAD ConnectClient_set_tunnelType(srClientsTable[k], tunneltype); #endif @@ -2471,7 +2505,12 @@ main(int argc, char **argv) maxfdp1 : (SslFd_get_fd(ConnectClient_get_sslFd(srClientsTable[k])) + 1); ServerRealm_increase_connectedClients(pointer); ConnectClient_set_timer(srClientsTable[k], timeval_create(ServerRealm_get_timeout(pointer), 0)); - manconnecting++; + task = Task_new(ConnectClient_get_timerp(srClientsTable[k]), + RCTfunction, + RCTdata_new(config, j, k, 0, RCT_REASON_TIMEOUT, &allset, &wset), + RCTdata_free); + ConnectClient_set_task(srClientsTable[k], task); + TaskScheduler_addTask(scheduler, task); ConnectClient_set_state(srClientsTable[k], CONNECTCLIENT_STATE_CONNECTING); break; } @@ -2489,6 +2528,7 @@ main(int argc, char **argv) ConnectClient_set_usrCliPair(srRaClientsTable[k], l); time(&now); ConnectClient_set_connectTime(srRaClientsTable[k], now); + ConnectClient_set_lastActivity(srRaClientsTable[k], now); #ifdef HAVE_LIBPTHREAD ConnectClient_set_tunnelType(srRaClientsTable[k], tunneltype); #endif @@ -2505,7 +2545,12 @@ main(int argc, char **argv) ServerRealm_increase_connectedClients(pointer); ConnectClient_set_timer(srRaClientsTable[k], timeval_create(ServerRealm_get_timeout(pointer), 0)); - manconnecting++; + task = Task_new(ConnectClient_get_timerp(srRaClientsTable[k]), + RCTfunction, + RCTdata_new(config, j, k, 1, RCT_REASON_TIMEOUT, &allset, &wset), + RCTdata_free); + ConnectClient_set_task(srRaClientsTable[k], task); + TaskScheduler_addTask(scheduler, task); ConnectClient_set_state(srRaClientsTable[k], CONNECTCLIENT_STATE_CONNECTING); break; } diff --git a/src/afserver.h b/src/afserver.h index 23e2a2f..229d555 100644 --- a/src/afserver.h +++ b/src/afserver.h @@ -41,6 +41,7 @@ #include "logging.h" #include "daemon.h" #include "timeval_functions.h" +#include "remove_client_task.h" #include #include diff --git a/src/client_initialization.c b/src/client_initialization.c index 77c0e48..5dc3717 100644 --- a/src/client_initialization.c +++ b/src/client_initialization.c @@ -27,6 +27,7 @@ #include "base64.h" #include "ssl_routines.h" #include "client_configuration_struct.h" +#include "client_signals.h" int initialize_client_stage1(ClientRealm* cr, SSL_CTX* ctx, unsigned char* buff, char wanttoexit, @@ -126,6 +127,8 @@ initialize_client_stage1(ClientRealm* cr, SSL_CTX* ctx, unsigned char* buff, cha } } + alarm(60); + aflog(LOG_T_INIT, LOG_I_INFO, "Trying SSL_connect"); if ((n = SSL_connect(SslFd_get_ssl(ClientRealm_get_masterSslFd(cr)))) == 1) { @@ -201,6 +204,7 @@ initialize_client_stage1(ClientRealm* cr, SSL_CTX* ctx, unsigned char* buff, cha "SSL_connect successful"); } else { + alarm(0); aflog(LOG_T_INIT, LOG_I_CRIT, "SSL_connect has failed (%d | %d)... exiting", n, SSL_get_error(SslFd_get_ssl(ClientRealm_get_masterSslFd(cr)), n)); @@ -212,6 +216,7 @@ initialize_client_stage1(ClientRealm* cr, SSL_CTX* ctx, unsigned char* buff, cha return 3; } } + alarm(0); buff[0] = AF_S_LOGIN; buff[1] = ClientRealm_get_password(cr)[0]; diff --git a/src/client_signals.c b/src/client_signals.c index 3184275..1202a48 100644 --- a/src/client_signals.c +++ b/src/client_signals.c @@ -27,7 +27,13 @@ #include - void +/* + * Function name: client_sig_int + * Description: Function responsible for handling SIG_INT. + * Arguments: signo - the signal number + */ + +void client_sig_int(int signo) { #ifdef HAVE_LIBPTHREAD @@ -40,3 +46,15 @@ client_sig_int(int signo) exit(0); } +/* + * Function name: client_sig_alrm + * Description: Function responsible for handling SIG_ALRM. + * Arguments: signo - the signal number + */ + +void +client_sig_alrm(int signo) +{ + aflog(LOG_T_MAIN, LOG_I_DEBUG, + "Received SIGALRM"); +} diff --git a/src/client_signals.h b/src/client_signals.h index 198e7a5..9082009 100644 --- a/src/client_signals.h +++ b/src/client_signals.h @@ -22,6 +22,7 @@ #define _JS_CLIENT_SIGNALS_H void client_sig_int(int); /* INT signal handler for the afclient */ +void client_sig_alrm(int); /* ALRM signal handler for the afclient */ #endif diff --git a/src/connect_client_struct.c b/src/connect_client_struct.c index 3481833..f5e713e 100644 --- a/src/connect_client_struct.c +++ b/src/connect_client_struct.c @@ -275,6 +275,23 @@ ConnectClient_set_connectTime(ConnectClient* cc, time_t connectTime) } /* + * Function name: ConnectClient_set_lastActivity + * Description: Sets time of the last client activity (when last packet from afclient has arrived) + * Arguments: cc - pointer to ConnectClient structure + * lastActivity - time of the last client activity + */ + +void +ConnectClient_set_lastActivity(ConnectClient* cc, time_t lastActivity) +{ + assert(cc != NULL); + if (cc == NULL) { + return; + } + cc->lastActivity = lastActivity; +} + +/* * Function name: ConnectClient_set_sClientId * Description: Sets client identification string. * Arguments: cc - pointer to ConnectClient structure @@ -403,6 +420,26 @@ ConnectClient_set_header(ConnectClient* cc, HeaderBuffer* hb) } /* + * Function name: ConnectClient_set_task + * Description: Sets the client task. + * Arguments: cc - pointer to ConnectClient structure + * task - the task to set + */ + +void +ConnectClient_set_task(ConnectClient* cc, Task* task) +{ + assert(cc != NULL); + if (cc == NULL) { + return; + } + if (cc->task) { + Task_free(&(cc->task)); + } + cc->task = task; +} + +/* * Function name: ConnectClient_get_state * Description: Gets state of the connected client. * Arguments: cc - pointer to ConnectClient structure @@ -573,6 +610,23 @@ ConnectClient_get_connectTime(ConnectClient* cc) } /* + * Function name: ConnectClient_get_lastActivity + * Description: Gets time of the last client activity (when last packet from afclient has arrived) + * Arguments: cc - pointer to ConnectClient structure + * Returns: Time of the last client activity. + */ + +time_t +ConnectClient_get_lastActivity(ConnectClient* cc) +{ + assert(cc != NULL); + if (cc == NULL) { + return 0; + } + return cc->lastActivity; +} + +/* * Function name: ConnectClient_get_sClientId * Description: Gets client identification string. * Arguments: cc - pointer to ConnectClient structure @@ -693,6 +747,23 @@ ConnectClient_get_header(ConnectClient* cc) } /* + * Function name: ConnectClient_get_task + * Description: Gets the client task. + * Arguments: cc - pointer to ConnectClient structure + * Returns: The client task. + */ + +Task* +ConnectClient_get_task(ConnectClient* cc) +{ + assert(cc != NULL); + if (cc == NULL) { + return NULL; + } + return cc->task; +} + +/* * Function name: ConnectClient_create_users * Description: Creates user descriptor table. Memory for the table is allocated according * to the previously set 'limit' value. All the descriptors are set to -1. diff --git a/src/connect_client_struct.h b/src/connect_client_struct.h index 58ce276..322a910 100644 --- a/src/connect_client_struct.h +++ b/src/connect_client_struct.h @@ -27,6 +27,7 @@ #include "ssl_fd_struct.h" #include "audit_list_struct.h" #include "header_buffer_struct.h" +#include "task_struct.h" #define CONNECTCLIENT_STATE_UNKNOWN -1 #define CONNECTCLIENT_STATE_FREE 0 @@ -53,6 +54,7 @@ typedef struct { int usrCliPair; int clientId; time_t connectTime; + time_t lastActivity; char* sClientId; char nameBuf[128]; char portBuf[7]; @@ -60,6 +62,7 @@ typedef struct { char multi; AuditList* auditList; HeaderBuffer* header; + Task* task; } ConnectClient; /* 'constructor' */ @@ -77,6 +80,7 @@ void ConnectClient_set_listenFd(ConnectClient* cc, int listenFd); void ConnectClient_set_usrCliPair(ConnectClient* cc, int usrCliPair); void ConnectClient_set_clientId(ConnectClient* cc, int clientId); void ConnectClient_set_connectTime(ConnectClient* cc, time_t connectTime); +void ConnectClient_set_lastActivity(ConnectClient* cc, time_t lastActivity); void ConnectClient_set_sClientId(ConnectClient* cc, char* sClientId); void ConnectClient_set_nameBuf(ConnectClient* cc, char* nameBuf); void ConnectClient_set_portBuf(ConnectClient* cc, char* portBuf); @@ -84,6 +88,7 @@ void ConnectClient_set_tunnelType(ConnectClient* cc, char tunnelType); void ConnectClient_set_multi(ConnectClient* cc, char multi); void ConnectClient_set_auditList(ConnectClient* cc, AuditList* al); void ConnectClient_set_header(ConnectClient* cc, HeaderBuffer* hb); +void ConnectClient_set_task(ConnectClient* cc, Task* task); /* getters */ char ConnectClient_get_state(ConnectClient* cc); SslFd* ConnectClient_get_sslFd(ConnectClient* cc); @@ -95,6 +100,7 @@ int ConnectClient_get_listenFd(ConnectClient* cc); int ConnectClient_get_usrCliPair(ConnectClient* cc); int ConnectClient_get_clientId(ConnectClient* cc); time_t ConnectClient_get_connectTime(ConnectClient* cc); +time_t ConnectClient_get_lastActivity(ConnectClient* cc); char* ConnectClient_get_sClientId(ConnectClient* cc); char* ConnectClient_get_nameBuf(ConnectClient* cc); char* ConnectClient_get_portBuf(ConnectClient* cc); @@ -102,6 +108,7 @@ char ConnectClient_get_tunnelType(ConnectClient* cc); char ConnectClient_get_multi(ConnectClient* cc); AuditList* ConnectClient_get_auditList(ConnectClient* cc); HeaderBuffer* ConnectClient_get_header(ConnectClient* cc); +Task* ConnectClient_get_task(ConnectClient* cc); /* other */ int ConnectClient_create_users(ConnectClient* cc); struct timeval* ConnectClient_get_timerp(ConnectClient* cc); diff --git a/src/file_server.c b/src/file_server.c index 427fb1b..e495f65 100644 --- a/src/file_server.c +++ b/src/file_server.c @@ -169,6 +169,7 @@ parsefile(char* name, int* status) ServerConfiguration_get_realmsNumber(cfg) - 1]); TYPE_SET_SSL(temp); TYPE_SET_ZLIB(temp); + TYPE_SET_SUPPORTED_MULTI(temp); ServerRealm_set_realmType(ServerConfiguration_get_realmsTable(cfg)[ ServerConfiguration_get_realmsNumber(cfg) - 1], temp); listencount = managecount = 0; @@ -257,6 +258,7 @@ parsefile(char* name, int* status) ServerConfiguration_get_realmsNumber(cfg) - 1]); TYPE_SET_SSL(temp); TYPE_SET_ZLIB(temp); + TYPE_SET_SUPPORTED_MULTI(temp); ServerRealm_set_realmType(ServerConfiguration_get_realmsTable(cfg)[ ServerConfiguration_get_realmsNumber(cfg) - 1], temp); listencount = managecount = 0; @@ -320,6 +322,11 @@ parsefile(char* name, int* status) ServerConfiguration_get_realmsTable(cfg)[ServerConfiguration_get_realmsNumber(cfg) - 1], helpbuf2); } + else if (strcmp(helpbuf1, "maxidle")==0) { + ServerRealm_set_sMaxIdle( + ServerConfiguration_get_realmsTable(cfg)[ServerConfiguration_get_realmsNumber(cfg) - 1], + helpbuf2); + } else if (strcmp(helpbuf1, "clients")==0) { ServerRealm_set_sClientsLimit( ServerConfiguration_get_realmsTable(cfg)[ServerConfiguration_get_realmsNumber(cfg) - 1], diff --git a/src/http_proxy_client.c b/src/http_proxy_client.c index e801a73..b488f3d 100644 --- a/src/http_proxy_client.c +++ b/src/http_proxy_client.c @@ -258,16 +258,19 @@ http_proxy_client(void *vptr) } while (1) { + if ((conn.state == C_OPEN) && (!(FD_ISSET(conn.sockfd, &allset)))) { + FD_SET(conn.sockfd, &allset); + } rset = allset; if (select(maxfdp1, &rset, NULL, NULL, &tv) == 0) { aflog(LOG_T_MAIN, LOG_I_DDEBUG, "http%s proxy: timeout", name); tv.tv_sec = timeout; - if (conn.state == C_CLOSED) { - continue; - } if (conn.sent_ptr+1 >= 90000) { + if (conn.state == C_CLOSED) { + continue; + } aflog(LOG_T_MAIN, LOG_I_DDEBUG, "http%s proxy: send T", name); http_write(https, conn.postFd, (unsigned char*) "T", 1); @@ -319,6 +322,7 @@ http_proxy_client(void *vptr) conn.sent_ptr = 0; conn.ptr = 0; conn.length = 0; + conn.state = C_CLOSED; set_fd(SslFd_get_fd(conn.postFd), &maxfdp1, &allset); } @@ -335,28 +339,6 @@ http_proxy_client(void *vptr) if (FD_ISSET(conn.sockfd, &rset)) { aflog(LOG_T_MAIN, LOG_I_DDEBUG, "http%s proxy: FD_ISSET(conn.sockfd)", name); - if (conn.state == C_CLOSED) { - /* postfd */ - aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http%s proxy: connecting (postfd)...", name); - if (ip_connect(&tmp, proxyname, proxyport, type, NULL, NULL)) { - clean_return(conn.sockfd); - } - SslFd_set_fd(conn.postFd, tmp); - if (https) { - if (SSL_set_fd(SslFd_get_ssl(conn.postFd), SslFd_get_fd(conn.postFd)) != 1) { - aflog(LOG_T_INIT, LOG_I_CRIT, - "https proxy: Problem with initializing ssl"); - clean_return(conn.sockfd); - } - if (SSL_connect(SslFd_get_ssl(conn.postFd)) != 1) { - aflog(LOG_T_INIT, LOG_I_CRIT, - "https proxy: SSL_connect has failed"); - clean_return(conn.sockfd); - } - } - conn.state = C_OPEN; - } n = read(conn.sockfd, conn.buf+5, 8995); if (n <= 0) { aflog(LOG_T_MAIN, LOG_I_DEBUG, @@ -364,6 +346,9 @@ http_proxy_client(void *vptr) http_write(https, conn.postFd, (unsigned char *) "Q", 1); clean_return(conn.sockfd); } + if ((conn.state == C_CLOSED) && (conn.sent_ptr > 70000)) { + FD_CLR(conn.sockfd, &allset); + } conn.buf[0] = 'M'; tmp = htonl(n); memcpy(&conn.buf[1], &tmp, 4); @@ -429,6 +414,7 @@ http_proxy_client(void *vptr) conn.sent_ptr = conn.length; conn.ptr = 0; conn.length = 0; + conn.state = C_CLOSED; set_fd(SslFd_get_fd(conn.postFd), &maxfdp1, &allset); } @@ -523,9 +509,9 @@ http_proxy_client(void *vptr) /* postfd */ if (FD_ISSET(SslFd_get_fd(conn.postFd), &rset)) { aflog(LOG_T_MAIN, LOG_I_DDEBUG, - "http%s proxy: FD_ISSET(conn.postfd)", name); + "http%s proxy: FD_ISSET(conn.postfd) --> clean_return", name); clear_sslFd(conn.postFd, &allset); - conn.state = C_CLOSED; + clean_return(conn.sockfd); } } clean_return(conn.sockfd); diff --git a/src/http_proxy_functions.c b/src/http_proxy_functions.c index 495d7d8..509b0a1 100644 --- a/src/http_proxy_functions.c +++ b/src/http_proxy_functions.c @@ -284,9 +284,11 @@ read_message(int fd, int length, connection* client, char* tab, int ptr) int tmp = 0; while (j < length) { if (client->curreceived + length-j > client->toreceive) { - writen(fd, (unsigned char*) (tab+ptr+j), client->toreceive - client->curreceived); - j += client->toreceive - client->curreceived; - client->curreceived += client->toreceive - client->curreceived; + if (client->toreceive - client->curreceived > 0) { + writen(fd, (unsigned char*) (tab+ptr+j), client->toreceive - client->curreceived); + j += client->toreceive - client->curreceived; + client->curreceived += client->toreceive - client->curreceived; + } if (client->read_state == 0) { switch (tab[ptr + j]) { case 'M': { @@ -311,6 +313,13 @@ read_message(int fd, int length, connection* client, char* tab, int ptr) ++j; break; } + case 'A': { + ++j; + if (client->state == C_CLOSED) { + client->state = C_OPEN; + } + break; + } default: { return 1; } @@ -332,7 +341,7 @@ read_message(int fd, int length, connection* client, char* tab, int ptr) } } } - else { + else if (length-j > 0) { client->curreceived += length-j; writen(fd, (unsigned char*) (tab+ptr+j), length-j); j += length-j; @@ -342,7 +351,7 @@ read_message(int fd, int length, connection* client, char* tab, int ptr) } /* - * Function name: clear sslFd + * Function name: clear_sslFd * Description: Close the socket encapsulated in SslFd structure, remove this file descriptor * from fd_set and clear ssl structure. * Arguments: sf - pointer to SslFd structure diff --git a/src/http_proxy_functions.h b/src/http_proxy_functions.h index dac6065..386359c 100644 --- a/src/http_proxy_functions.h +++ b/src/http_proxy_functions.h @@ -34,6 +34,7 @@ #define C_POST_WAIT 1 #define C_GET_WAIT 2 #define C_OPEN 4 +#define C_DELAYED_A 8 #define H_TYPE_GET 0 #define H_TYPE_POST 1 diff --git a/src/http_proxy_server.c b/src/http_proxy_server.c index 6da2c30..2bb2082 100644 --- a/src/http_proxy_server.c +++ b/src/http_proxy_server.c @@ -94,6 +94,7 @@ http_proxy_server(void *vptr) int maxclients, tmp; int timeout = 5; socklen_t *addrlenp; + socklen_t addrlen; char type, nothttp, https; char *host, *serv, *name = ""; SSL_CTX* ctx; @@ -111,9 +112,6 @@ http_proxy_server(void *vptr) https = proxy_argptr->https; ctx = proxy_argptr->ctx; - broadcast_condition(); - end_critical_section(); - if (https) { name = "s"; } @@ -167,6 +165,11 @@ http_proxy_server(void *vptr) exit(1); } cliaddr = malloc(*addrlenp); + addrlen = (*addrlenp); + addrlenp = &addrlen; + + broadcast_condition(); + end_critical_section(); FD_ZERO(&allset); FD_SET(listenfd, &allset); @@ -260,6 +263,26 @@ http_proxy_server(void *vptr) table[i].received = 0; clear_sslFd(table[i].postFd, &allset); table[i].state |= C_POST_WAIT; + + if (!(table[i].state & C_GET_WAIT)) { + aflog(LOG_T_MAIN, LOG_I_DDEBUG, + "http%s proxy: send A to table[%d].getfd", name, i); + if (table[i].sent_ptr+1 >= 90000) { + http_write(https, table[i].getFd, (unsigned char*) "A", 1); + table[i].sent_ptr = 0; + clear_sslFd(table[i].getFd, &allset); + FD_CLR(table[i].sockfd, &allset); + table[i].state |= C_GET_WAIT; + } + else { + http_write(https, table[i].getFd, (unsigned char*) "A", 1); + table[i].sent_ptr += 1; + } + } + else { + table[i].state |= C_DELAYED_A; + } + if (table[i].tmpstate == 1) { aflog(LOG_T_MAIN, LOG_I_DEBUG, "http%s proxy: get old POST request...", name); @@ -414,6 +437,13 @@ http_proxy_server(void *vptr) table[i].sent_ptr = table[i].length; table[i].ptr = 0; table[i].length = 0; + if (table[i].state & C_DELAYED_A) { + aflog(LOG_T_MAIN, LOG_I_DDEBUG, + "http%s proxy: send A to table[%d].getfd", name, i); + http_write(https, table[i].getFd, (unsigned char*) "A", 1); + table[i].sent_ptr += 1; + table[i].state &= ~C_DELAYED_A; + } } else if (hdr.type == H_TYPE_POST) { aflog(LOG_T_MAIN, LOG_I_DEBUG, @@ -470,9 +500,11 @@ http_proxy_server(void *vptr) } else { aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http%s proxy: closing this connection...", name); + "http%s proxy: closing this connection... (not POST type)", name); close_fd((&(connFd->fd))); - SSL_clear(SslFd_get_ssl(connFd)); + if (https) { + SSL_clear(SslFd_get_ssl(connFd)); + } continue; } } @@ -492,7 +524,7 @@ http_proxy_server(void *vptr) } else { aflog(LOG_T_MAIN, LOG_I_DEBUG, - "http%s proxy: closing this connection...", name); + "http%s proxy: closing this connection... (no free slots)", name); close_fd((&(connFd->fd))); continue; } diff --git a/src/network.c b/src/network.c index 23b8ee5..6a62a59 100644 --- a/src/network.c +++ b/src/network.c @@ -45,67 +45,69 @@ int ip_listen(int* sockfd, const char *host, const char *serv, socklen_t *addrlenp, const char type) { + const int on = 1; #if defined(HAVE_GETADDRINFO) && defined(AF_INET6) - int n; - const int on = 1; - struct addrinfo hints, *res, *ressave; + int n; + struct addrinfo hints, *res, *ressave; aflog(LOG_T_INIT, LOG_I_DDEBUG, "ip_listen: host=[%s] serv=[%s], type=[%d]", host, serv, type); - bzero(&hints, sizeof(struct addrinfo)); - hints.ai_flags = AI_PASSIVE; - if (type & 0x02) { - hints.ai_family = AF_INET; - } - else if (type & 0x04) { - hints.ai_family = AF_INET6; - } - else { - hints.ai_family = AF_UNSPEC; - } - - if (type & 0x01) { - hints.ai_socktype = SOCK_STREAM; - } - else { - hints.ai_socktype = SOCK_DGRAM; - } - - if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0) { - return n; - } - ressave = res; - - do { - (*sockfd) = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if ((*sockfd) < 0) { - continue; /* error, try next one */ - } - - if (type & 0x01) { /* tcp_listen */ - setsockopt((*sockfd), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - } - if (bind((*sockfd), res->ai_addr, res->ai_addrlen) == 0) { - break; /* success */ - } - - close((*sockfd)); /* bind error, close and try next one */ - } while ( (res = res->ai_next) != NULL); - - if (res == NULL) { /* errno from final socket() or bind() */ - return 1; - } - - if (type & 0x01) { /* tcp_listen */ - listen((*sockfd), 1); - } - - if (addrlenp) { - *addrlenp = res->ai_addrlen; /* return size of protocol address */ - } - - freeaddrinfo(ressave); + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_flags = AI_PASSIVE; + if (type & 0x02) { + hints.ai_family = AF_INET; + } + else if (type & 0x04) { + hints.ai_family = AF_INET6; + } + else { + hints.ai_family = AF_UNSPEC; + } + + if (type & 0x01) { + hints.ai_socktype = SOCK_STREAM; + } + else { + hints.ai_socktype = SOCK_DGRAM; + } + + if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0) { + return n; + } + ressave = res; + + do { + (*sockfd) = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if ((*sockfd) < 0) { + continue; /* error, try next one */ + } + + if (type & 0x01) { /* tcp_listen */ + setsockopt((*sockfd), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + setsockopt((*sockfd), SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); + } + + if (bind((*sockfd), res->ai_addr, res->ai_addrlen) == 0) { + break; /* success */ + } + + close((*sockfd)); /* bind error, close and try next one */ + } while ( (res = res->ai_next) != NULL); + + if (res == NULL) { /* errno from final socket() or bind() */ + return 1; + } + + if (type & 0x01) { /* tcp_listen */ + listen((*sockfd), 1); + } + + if (addrlenp) { + *addrlenp = res->ai_addrlen; /* return size of protocol address */ + } + + freeaddrinfo(ressave); #else struct sockaddr_in servaddr; struct hostent* hostaddr = NULL; @@ -142,6 +144,11 @@ ip_listen(int* sockfd, const char *host, const char *serv, socklen_t *addrlenp, servaddr.sin_addr.s_addr = htonl(INADDR_ANY); } servaddr.sin_port = htons(port); + + if (type & 0x01) { /* tcp_listen */ + setsockopt((*sockfd), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + setsockopt((*sockfd), SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); + } if (bind((*sockfd), (struct sockaddr*) &servaddr, sizeof(servaddr))){ printf("bind failed\n"); @@ -151,6 +158,10 @@ ip_listen(int* sockfd, const char *host, const char *serv, socklen_t *addrlenp, if (listen((*sockfd), 5)){ return 5; } + + if (addrlenp) { + *addrlenp = sizeof(servaddr); /* return size of protocol address */ + } #endif return(0); @@ -173,31 +184,32 @@ int ip_connect(int* sockfd, const char *host, const char *serv, const char type, const char *lhost, const char *lserv) { + const int on = 1; #if defined(HAVE_GETADDRINFO) && defined(AF_INET6) - int n; + int n; int bindFailed; - struct addrinfo hints, *res, *ressave; - struct addrinfo lhints, *lres, *lressave = NULL; + struct addrinfo hints, *res, *ressave; + struct addrinfo lhints, *lres, *lressave = NULL; aflog(LOG_T_INIT, LOG_I_DDEBUG, "ip_connect: host=[%s] serv=[%s], type=[%d], lhost=[%s], lserv=[%s]", host, serv, type, lhost, lserv); - bzero(&hints, sizeof(struct addrinfo)); - if (type & 0x02) { - hints.ai_family = AF_INET; - } - else if (type & 0x04) { - hints.ai_family = AF_INET6; - } - else { - hints.ai_family = AF_UNSPEC; - } - if (type & 0x01) { - hints.ai_socktype = SOCK_STREAM; - } - else { - hints.ai_socktype = SOCK_DGRAM; - } + bzero(&hints, sizeof(struct addrinfo)); + if (type & 0x02) { + hints.ai_family = AF_INET; + } + else if (type & 0x04) { + hints.ai_family = AF_INET6; + } + else { + hints.ai_family = AF_UNSPEC; + } + if (type & 0x01) { + hints.ai_socktype = SOCK_STREAM; + } + else { + hints.ai_socktype = SOCK_DGRAM; + } lhints = hints; @@ -208,16 +220,20 @@ ip_connect(int* sockfd, const char *host, const char *serv, const char type, lressave = lres; } - if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0) { - return n; - } - ressave = res; + if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0) { + return n; + } + ressave = res; - do { - (*sockfd) = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if ((*sockfd) < 0) { - continue; /* ignore this one */ - } + do { + (*sockfd) = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if ((*sockfd) < 0) { + continue; /* ignore this one */ + } + + if (type & 0x01) { /* tcp_connect */ + setsockopt((*sockfd), SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); + } bindFailed = 0; if (lhost || lserv) { @@ -226,31 +242,31 @@ ip_connect(int* sockfd, const char *host, const char *serv, const char type, do { if (bind((*sockfd), lres->ai_addr, lres->ai_addrlen) == 0) { bindFailed = 0; - break; /* success */ + break; /* success */ } } while ( (lres = lres->ai_next) != NULL); } if (bindFailed == 1) { - close((*sockfd)); /* ignore this one */ + close((*sockfd)); /* ignore this one */ continue; } if (connect((*sockfd), res->ai_addr, res->ai_addrlen) == 0) { - break; /* success */ - } + break; /* success */ + } - close((*sockfd)); /* ignore this one */ - } while ( (res = res->ai_next) != NULL); + close((*sockfd)); /* ignore this one */ + } while ( (res = res->ai_next) != NULL); - if (res == NULL) { /* errno set from final connect() */ - return 1; - } + if (res == NULL) { /* errno set from final connect() */ + return 1; + } if (lhost || lserv) { - freeaddrinfo(lressave); + freeaddrinfo(lressave); } - freeaddrinfo(ressave); + freeaddrinfo(ressave); #else struct sockaddr_in servaddr, lservaddr; struct hostent* hostaddr; @@ -282,6 +298,10 @@ ip_connect(int* sockfd, const char *host, const char *serv, const char type, servaddr.sin_port = htons(port); memcpy(&servaddr.sin_addr.s_addr, hostaddr->h_addr_list[0], hostaddr->h_length); + if (type & 0x01) { /* tcp_connect */ + setsockopt((*sockfd), SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); + } + if (lhost || lserv) { memset(&lservaddr, 0, sizeof(lservaddr)); lservaddr.sin_family = AF_INET; @@ -309,7 +329,7 @@ ip_connect(int* sockfd, const char *host, const char *serv, const char type, } #endif - return(0); + return(0); } /* @@ -327,96 +347,96 @@ ip_connect(int* sockfd, const char *host, const char *serv, const char type, char * sock_ntop(const struct sockaddr *sa, socklen_t salen, char* namebuf, char* portbuf, char type) { - char portstr[7]; - static char str[136]; /* Unix domain is largest */ + char portstr[7]; + static char str[136]; /* Unix domain is largest */ - switch (sa->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *) sa; + switch (sa->sa_family) { + case AF_INET: { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; - if (type) { + if (type) { #ifdef HAVE_GETNAMEINFO - if (getnameinfo(sa, salen, str, 128, NULL, 0, 0)) { - return NULL; - } + if (getnameinfo(sa, salen, str, 128, NULL, 0, 0)) { + return NULL; + } #else - struct hostent* hostname; - if ((hostname = gethostbyaddr((void*) &sin->sin_addr, sizeof(struct in_addr), AF_INET))) { - strncpy(str, hostname->h_name, 127); - str[127] = 0; - } - else { - if (inet_ntop(AF_INET, (void*) &sin->sin_addr, str, sizeof(str)) == NULL) { - return NULL; - } - } + struct hostent* hostname; + if ((hostname = gethostbyaddr((void*) &sin->sin_addr, sizeof(struct in_addr), AF_INET))) { + strncpy(str, hostname->h_name, 127); + str[127] = 0; + } + else { + if (inet_ntop(AF_INET, (void*) &sin->sin_addr, str, sizeof(str)) == NULL) { + return NULL; + } + } #endif - } - else { - if (inet_ntop(AF_INET, (void*) &sin->sin_addr, str, sizeof(str)) == NULL) { - return NULL; - } - } - if (namebuf) { - memcpy(namebuf, str, 128); - } - if (ntohs(sin->sin_port) != 0) { - snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin->sin_port)); - if (portbuf) { - snprintf(portbuf, 7, "%d", ntohs(sin->sin_port)); - } - strcat(str, portstr); - } - return(str); - } + } + else { + if (inet_ntop(AF_INET, (void*) &sin->sin_addr, str, sizeof(str)) == NULL) { + return NULL; + } + } + if (namebuf) { + memcpy(namebuf, str, 128); + } + if (ntohs(sin->sin_port) != 0) { + snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin->sin_port)); + if (portbuf) { + snprintf(portbuf, 7, "%d", ntohs(sin->sin_port)); + } + strcat(str, portstr); + } + return(str); + } #ifdef AF_INET6 - case AF_INET6: { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; + case AF_INET6: { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; - if (type) { + if (type) { #ifdef HAVE_GETNAMEINFO - if (getnameinfo(sa, salen, str, 128, NULL, 0, 0)) { - return NULL; - } + if (getnameinfo(sa, salen, str, 128, NULL, 0, 0)) { + return NULL; + } #else - struct hostent* hostname; - if ((hostname = gethostbyaddr(&sin6->sin6_addr, sizeof(struct in6_addr), AF_INET6))) { - strncpy(str, hostname->h_name, 127); - str[127] = 0; - } - else { - if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == NULL) { - return NULL; - } - } + struct hostent* hostname; + if ((hostname = gethostbyaddr(&sin6->sin6_addr, sizeof(struct in6_addr), AF_INET6))) { + strncpy(str, hostname->h_name, 127); + str[127] = 0; + } + else { + if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == NULL) { + return NULL; + } + } #endif - } - else { - if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == NULL) { - return NULL; - } - } - if (namebuf) { - memcpy(namebuf, str, 128); - } - if (ntohs(sin6->sin6_port) != 0) { - snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin6->sin6_port)); - if (portbuf) { - snprintf(portbuf, 7, "%d", ntohs(sin6->sin6_port)); - } - strcat(str, portstr); - } - return(str); - } + } + else { + if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == NULL) { + return NULL; + } + } + if (namebuf) { + memcpy(namebuf, str, 128); + } + if (ntohs(sin6->sin6_port) != 0) { + snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin6->sin6_port)); + if (portbuf) { + snprintf(portbuf, 7, "%d", ntohs(sin6->sin6_port)); + } + strcat(str, portstr); + } + return(str); + } #endif - default: { - snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d", sa->sa_family, salen); - return(str); - } - } - return NULL; + default: { + snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d", sa->sa_family, salen); + return(str); + } + } + return NULL; } /* @@ -431,21 +451,21 @@ sock_ntop(const struct sockaddr *sa, socklen_t salen, char* namebuf, char* portb int SSL_writen(SSL* fd, unsigned char* buf, int amount) { - int sent, n; - sent = 0; + int sent, n; + sent = 0; assert(amount > 0); - while (sent < amount) { - n = SSL_write(fd, buf+sent, amount - sent); + while (sent < amount) { + n = SSL_write(fd, buf+sent, amount - sent); assert(n != 0); - if (n != -1) { - sent += n; - } - if (n == -1) { - if (errno != EAGAIN) - return 0; - } - } - return amount; + if (n != -1) { + sent += n; + } + if (n == -1) { + if (errno != EAGAIN) + return 0; + } + } + return amount; } /* @@ -460,22 +480,22 @@ SSL_writen(SSL* fd, unsigned char* buf, int amount) int SSL_readn(SSL* fd, unsigned char* buf, int amount) { - int sent, n; - sent = 0; + int sent, n; + sent = 0; assert(amount > 0); - while (sent < amount) { - n = SSL_read(fd, buf+sent, amount - sent); - if (n != -1) { - sent += n; - } - if (n == 0) - return 0; - if (n == -1) { - if (errno != EAGAIN) - return 0; - } - } - return amount; + while (sent < amount) { + n = SSL_read(fd, buf+sent, amount - sent); + if (n != -1) { + sent += n; + } + if (n == 0) + return 0; + if (n == -1) { + if (errno != EAGAIN) + return 0; + } + } + return amount; } /* @@ -490,21 +510,21 @@ SSL_readn(SSL* fd, unsigned char* buf, int amount) int writen(int fd, unsigned char* buf, int amount) { - int sent, n; - sent = 0; + int sent, n; + sent = 0; assert(amount > 0); - while (sent < amount) { - n = write(fd, buf+sent, amount - sent); + while (sent < amount) { + n = write(fd, buf+sent, amount - sent); assert(n != 0); - if (n != -1) { - sent += n; - } - if (n == -1) { - if (errno != EAGAIN) - return 0; - } - } - return amount; + if (n != -1) { + sent += n; + } + if (n == -1) { + if (errno != EAGAIN) + return 0; + } + } + return amount; } /* @@ -519,21 +539,21 @@ writen(int fd, unsigned char* buf, int amount) int readn(int fd, unsigned char* buf, int amount) { - int sent, n; - sent = 0; + int sent, n; + sent = 0; assert(amount > 0); - while (sent < amount) { - n = read(fd, buf+sent, amount - sent); - if (n != -1) { - sent += n; - } - if (n == 0) - return 0; - if (n == -1) { - if (errno != EAGAIN) - return 0; - } - } - return amount; + while (sent < amount) { + n = read(fd, buf+sent, amount - sent); + if (n != -1) { + sent += n; + } + if (n == 0) + return 0; + if (n == -1) { + if (errno != EAGAIN) + return 0; + } + } + return amount; } diff --git a/src/remove_client_task.c b/src/remove_client_task.c new file mode 100644 index 0000000..b91e071 --- /dev/null +++ b/src/remove_client_task.c @@ -0,0 +1,134 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003-2006 jeremian + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include +#include + +#include "logging.h" +#include "realmnames.h" +#include "clientnames.h" +#include "server_remove.h" +#include "remove_client_task.h" + +/* + * Function name: RCTdata_new + * Description: Creates and initializes new data for remove client task. + * Arguments: config - server configuration + * realm - the realm id + * client - the client id + * ra - if the client is in remote administration mode + * fdset - the descriptor set watched for read + * Returns: Pointer to newly created RCTdata structure. + */ + +RCTdata* +RCTdata_new(ServerConfiguration* config, int realm, int client, char ra, char reason, fd_set* set, fd_set* wset) +{ + RCTdata* tmp; + assert(config != NULL); + if (config == NULL) { + return NULL; + } + tmp = calloc(1, sizeof(RCTdata)); + assert(tmp != NULL); + if (tmp == NULL) { + return NULL; + } + tmp->config = config; + tmp->realm = realm; + tmp->client = client; + tmp->ra = ra; + tmp->reason = reason; + tmp->set = set; + tmp->wset = wset; + + return tmp; +} + +/* + * Function name: RCTdata_free + * Description: Frees the memory allocated for RCTdata structure. + * Arguments: ptr - pointer to pointer to RCTdata structure + */ + +void +RCTdata_free(void** ptr) +{ + RCTdata** data = (RCTdata**) ptr; + assert(data != NULL); + if (data == NULL) { + return; + } + assert((*data) != NULL); + if ((*data) == NULL) { + return; + } + free((*data)); + (*data) = NULL; +} + +/* + * Function name: RCTfunction + * Description: Function executed in the task by the task scheduler. + * Arguments: Pointer to the memory containing RCTdata structure. + */ + +void +RCTfunction(void* data) +{ + ConnectClient** clientsTable; + ServerRealm** realmsTable; + RCTdata* ptr; + assert(data != NULL); + if (data == NULL) { + return; + } + ptr = (RCTdata*) data; + realmsTable = ServerConfiguration_get_realmsTable(ptr->config); + if (ptr->ra) { + clientsTable = ServerRealm_get_raClientsTable(realmsTable[ptr->realm]); + } + else { + clientsTable = ServerRealm_get_clientsTable(realmsTable[ptr->realm]); + } + switch (ptr->reason) { + case RCT_REASON_TIMEOUT: + close(SslFd_get_fd(ConnectClient_get_sslFd(clientsTable[ptr->client]))); + FD_CLR(SslFd_get_fd(ConnectClient_get_sslFd(clientsTable[ptr->client])), ptr->set); + SSL_clear(SslFd_get_ssl(ConnectClient_get_sslFd(clientsTable[ptr->client]))); + ConnectClient_set_state(clientsTable[ptr->client], CONNECTCLIENT_STATE_FREE); + ServerRealm_decrease_connectedClients(realmsTable[ptr->realm]); + aflog(LOG_T_CLIENT, LOG_I_WARNING, + "realm[%s]: Client[%s]%s: SSL_accept failed (timeout)", + get_realmname(ptr->config, ptr->realm), + ptr->ra ? get_raclientname(realmsTable[ptr->realm], ptr->client) : + get_clientname(realmsTable[ptr->realm], ptr->client), + ptr->ra ? " (ra)" : ""); + break; + case RCT_REASON_MAXIDLE: + aflog(LOG_T_CLIENT, LOG_I_WARNING, + "realm[%s]: Client[%s]: too long idle --> DROPPING", get_realmname(ptr->config, ptr->realm), + get_clientname(realmsTable[ptr->realm], ptr->client)); + remove_client(realmsTable[ptr->realm], ptr->client, ptr->set, ptr->wset, NULL); + } + ConnectClient_set_task(clientsTable[ptr->client], NULL); +} diff --git a/src/remove_client_task.h b/src/remove_client_task.h new file mode 100644 index 0000000..44f98aa --- /dev/null +++ b/src/remove_client_task.h @@ -0,0 +1,47 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003-2006 jeremian + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _JS_REMOVE_CLIENT_TASK_H +#define _JS_REMOVE_CLIENT_TASK_H + +#define RCT_REASON_TIMEOUT 0 +#define RCT_REASON_MAXIDLE 1 + +#include "server_configuration_struct.h" + +typedef struct { + ServerConfiguration* config; + int realm; + int client; + char ra; + char reason; + fd_set* set; + fd_set* wset; +} RCTdata; + +/* 'constructor' */ +RCTdata* RCTdata_new(ServerConfiguration* config, int realm, int client, char ra, char reason, + fd_set* set, fd_set* wset); +/* 'destructor' */ +void RCTdata_free(void** data); +/* other */ +void RCTfunction(void*); + +#endif diff --git a/src/server_realm_struct.c b/src/server_realm_struct.c index f3f06c0..4220600 100644 --- a/src/server_realm_struct.c +++ b/src/server_realm_struct.c @@ -262,6 +262,23 @@ ServerRealm_set_sTimeout(ServerRealm* sr, char* sTimeout) } /* + * Function name: ServerRealm_set_sMaxIdle + * Description: Sets max idle value description. + * Arguments: sr - pointer to ServerRealm structure + * sMaxIdle - max idle value description + */ + +void +ServerRealm_set_sMaxIdle(ServerRealm* sr, char* sMaxIdle) +{ + assert(sr != NULL); + if (sr == NULL) { + return; + } + string_cp(&(sr->sMaxIdle), sMaxIdle); +} + +/* * Function name: ServerRealm_set_realmName * Description: Set realm's name. * Arguments: sr - pointer to ServerRealm structure @@ -432,6 +449,23 @@ ServerRealm_set_timeout(ServerRealm* sr, int timeout) } /* + * Function name: ServerRealm_set_maxIdle + * Description: Sets mas idle value. + * Arguments: sr - pointer to ServerRealm structure + * maxIdle - max idle value + */ + +void +ServerRealm_set_maxIdle(ServerRealm* sr, int maxIdle) +{ + assert(sr != NULL); + if (sr == NULL) { + return; + } + sr->maxIdle = maxIdle; +} + +/* * Function name: ServerRealm_set_clientMode * Description: Set client mode. * Arguments: sr - pointer to ServerRealm structure @@ -850,6 +884,23 @@ ServerRealm_get_sTimeout(ServerRealm* sr) } /* + * Function name: ServerRealm_get_sMaxIdle + * Description: Gets max idle value description. + * Arguments: sr - pointer to ServerRealm structure + * Returns: Max idle value description. + */ + +char* +ServerRealm_get_sMaxIdle(ServerRealm* sr) +{ + assert(sr != NULL); + if (sr == NULL) { + return NULL; + } + return sr->sMaxIdle; +} + +/* * Function name: ServerRealm_get_realmName * Description: Get realm's name. * Arguments: sr - pointer to ServerRealm structure @@ -1020,6 +1071,23 @@ ServerRealm_get_timeout(ServerRealm* sr) } /* + * Function name: ServerRealm_get_maxIdle + * Description: Gets max idle value. + * Arguments: sr - pointer to ServerRealm structure + * Returns: Max idle value. + */ + +int +ServerRealm_get_maxIdle(ServerRealm* sr) +{ + assert(sr != NULL); + if (sr == NULL) { + return 0; + } + return sr->maxIdle; +} + +/* * Function name: ServerRealm_get_clientMode * Description: Get client mode. * Arguments: sr - pointer to ServerRealm structure diff --git a/src/server_realm_struct.h b/src/server_realm_struct.h index 0d61517..4ca21c1 100644 --- a/src/server_realm_struct.h +++ b/src/server_realm_struct.h @@ -31,6 +31,7 @@ typedef struct { char* sUsersPerClient; char* sClientMode; char* sTimeout; + char* sMaxIdle; char* realmName; unsigned char password[4]; int connectedUsers; @@ -41,6 +42,7 @@ typedef struct { int raClientsLimit; int usersPerClient; int timeout; + int maxIdle; int clientMode; int userClientPairs; int clientsCounter; @@ -70,6 +72,7 @@ void ServerRealm_set_sRaClientsLimit(ServerRealm* sr, char* sRaClientsLimit); void ServerRealm_set_sUsersPerClient(ServerRealm* sr, char* sUsersPerClient); void ServerRealm_set_sClientMode(ServerRealm* sr, char* sClientMode); void ServerRealm_set_sTimeout(ServerRealm* sr, char* sTimeout); +void ServerRealm_set_sMaxIdle(ServerRealm* sr, char* sMaxIdle); void ServerRealm_set_realmName(ServerRealm* sr, char* realmName); void ServerRealm_set_password(ServerRealm* sr, unsigned char* password); void ServerRealm_set_connectedUsers(ServerRealm* sr, int connectedUsers); @@ -80,6 +83,7 @@ void ServerRealm_set_connectedRaClients(ServerRealm* sr, int connectedRaClients) void ServerRealm_set_raClientsLimit(ServerRealm* sr, int raClientsLimit); void ServerRealm_set_usersPerClient(ServerRealm* sr, int usersPerClient); void ServerRealm_set_timeout(ServerRealm* sr, int timeout); +void ServerRealm_set_maxIdle(ServerRealm* sr, int maxIdle); void ServerRealm_set_clientMode(ServerRealm* sr, int clientMode); void ServerRealm_set_userClientPairs(ServerRealm* sr, int userClientPairs); void ServerRealm_set_clientsCounter(ServerRealm* sr, int clientsCounter); @@ -103,6 +107,7 @@ char* ServerRealm_get_sRaClientsLimit(ServerRealm* sr); char* ServerRealm_get_sUsersPerClient(ServerRealm* sr); char* ServerRealm_get_sClientMode(ServerRealm* sr); char* ServerRealm_get_sTimeout(ServerRealm* sr); +char* ServerRealm_get_sMaxIdle(ServerRealm* sr); char* ServerRealm_get_realmName(ServerRealm* sr); unsigned char* ServerRealm_get_password(ServerRealm* sr); int ServerRealm_get_connectedUsers(ServerRealm* sr); @@ -113,6 +118,7 @@ int ServerRealm_get_connectedRaClients(ServerRealm* sr); int ServerRealm_get_raClientsLimit(ServerRealm* sr); int ServerRealm_get_usersPerClient(ServerRealm* sr); int ServerRealm_get_timeout(ServerRealm* sr); +int ServerRealm_get_maxIdle(ServerRealm* sr); int ServerRealm_get_clientMode(ServerRealm* sr); int ServerRealm_get_userClientPairs(ServerRealm* sr); int ServerRealm_get_clientsCounter(ServerRealm* sr); diff --git a/src/server_remoteadmin.c b/src/server_remoteadmin.c index 6c2a4a3..c52bf98 100644 --- a/src/server_remoteadmin.c +++ b/src/server_remoteadmin.c @@ -367,6 +367,12 @@ serve_admin(ServerConfiguration* config, int realm, int client, unsigned char* b } add_to_message(buff, "climode: %s", ServerRealm_get_sClientMode(pointer)); add_to_message(buff, "timeout: %d", ServerRealm_get_timeout(pointer)); + if (ServerRealm_get_maxIdle(pointer)) { + add_to_message(buff, "max idle: %d", ServerRealm_get_maxIdle(pointer)); + } + else { + add_to_message(buff, "max idle: disabled"); + } add_to_message(buff, "baseport: %s", ServerRealm_get_basePortOn(pointer) ? "yes" : "no"); add_to_message(buff, "audit: %s", ServerRealm_get_auditOn(pointer) ? @@ -431,6 +437,8 @@ serve_admin(ServerConfiguration* config, int realm, int client, unsigned char* b ConnectClient_get_usrCliPair(cpointer)); tmp = now - ConnectClient_get_connectTime(cpointer); add_uptime_to_message(buff, "Connection time", tmp); + tmp = now - ConnectClient_get_lastActivity(cpointer); + add_uptime_to_message(buff, "Idle time", tmp); add_to_message(buff, "Id: %s", (ConnectClient_get_sClientId(cpointer) == NULL) ? "" : ConnectClient_get_sClientId(cpointer)); diff --git a/src/server_remove.c b/src/server_remove.c index 8a66813..93dcf15 100644 --- a/src/server_remove.c +++ b/src/server_remove.c @@ -29,19 +29,19 @@ * client - the client number * set - the set of file descriptors for reading * wset - the set of file descriptors for writing - * con - the connection counter + * scheduler - the task scheduler */ void -remove_client(ServerRealm* ptr, int client, fd_set* set, fd_set* wset, int* con) +remove_client(ServerRealm* ptr, int client, fd_set* set, fd_set* wset, TaskScheduler* scheduler) { int i; + Task* task; assert(ptr != NULL); assert(client >= 0); assert(set != NULL); assert(wset != NULL); - assert(con != NULL); if (ConnectClient_get_state(ServerRealm_get_clientsTable(ptr)[client]) == CONNECTCLIENT_STATE_ACCEPTED) { for (i = 0; i < ServerRealm_get_usersLimit(ptr); ++i) { @@ -67,8 +67,11 @@ remove_client(ServerRealm* ptr, int client, fd_set* set, fd_set* wset, int* con) ConnectClient_set_connected(ServerRealm_get_clientsTable(ptr)[client], 0); close(SslFd_get_fd(ConnectClient_get_sslFd(ServerRealm_get_clientsTable(ptr)[client]))); FD_CLR(SslFd_get_fd(ConnectClient_get_sslFd(ServerRealm_get_clientsTable(ptr)[client])), set); - if (ConnectClient_get_state(ServerRealm_get_clientsTable(ptr)[client]) == CONNECTCLIENT_STATE_AUTHORIZING) { - (*con)--; + if (scheduler) { + if ((task = ConnectClient_get_task(ServerRealm_get_clientsTable(ptr)[client]))) { + TaskScheduler_removeTask(scheduler, task); + ConnectClient_set_task(ServerRealm_get_clientsTable(ptr)[client], NULL); + } } SSL_clear(SslFd_get_ssl(ConnectClient_get_sslFd(ServerRealm_get_clientsTable(ptr)[client]))); ConnectClient_set_state(ServerRealm_get_clientsTable(ptr)[client], CONNECTCLIENT_STATE_FREE); @@ -82,19 +85,19 @@ remove_client(ServerRealm* ptr, int client, fd_set* set, fd_set* wset, int* con) * client - the client number * set - the set of file descriptors for reading * wset - the set of file descriptors for writing - * con - the connection counter + * scheduler - the task scheduler */ void -remove_raclient(ServerRealm* ptr, int client, fd_set* set, fd_set* wset, int* con) +remove_raclient(ServerRealm* ptr, int client, fd_set* set, fd_set* wset, TaskScheduler* scheduler) { int i; + Task* task; assert(ptr != NULL); assert(client >= 0); assert(set != NULL); assert(wset != NULL); - assert(con != NULL); for (i = 0; i < ConnectClient_get_limit(ServerRealm_get_raClientsTable(ptr)[client]); ++i) { ConnectClient_get_users(ServerRealm_get_raClientsTable(ptr)[client])[i] = -1; @@ -103,8 +106,11 @@ remove_raclient(ServerRealm* ptr, int client, fd_set* set, fd_set* wset, int* co ConnectClient_set_connected(ServerRealm_get_raClientsTable(ptr)[client], 0); close(SslFd_get_fd(ConnectClient_get_sslFd(ServerRealm_get_raClientsTable(ptr)[client]))); FD_CLR(SslFd_get_fd(ConnectClient_get_sslFd(ServerRealm_get_raClientsTable(ptr)[client])), set); - if (ConnectClient_get_state(ServerRealm_get_raClientsTable(ptr)[client]) == CONNECTCLIENT_STATE_AUTHORIZING) { - (*con)--; + if (scheduler) { + if ((task = ConnectClient_get_task(ServerRealm_get_clientsTable(ptr)[client]))) { + TaskScheduler_removeTask(scheduler, task); + ConnectClient_set_task(ServerRealm_get_clientsTable(ptr)[client], NULL); + } } SSL_clear(SslFd_get_ssl(ConnectClient_get_sslFd(ServerRealm_get_raClientsTable(ptr)[client]))); ServerRealm_decrease_connectedClients(ptr); diff --git a/src/server_remove.h b/src/server_remove.h index 31dbe5c..7c745ac 100644 --- a/src/server_remove.h +++ b/src/server_remove.h @@ -19,12 +19,13 @@ */ #include "file.h" +#include "task_scheduler_struct.h" #ifndef _JS_SERVER_REMOVE_H #define _JS_SERVER_REMOVE_H -void remove_client(ServerRealm*, int, fd_set*, fd_set*, int*); -void remove_raclient(ServerRealm*, int, fd_set*, fd_set*, int*); +void remove_client(ServerRealm*, int, fd_set*, fd_set*, TaskScheduler* scheduler); +void remove_raclient(ServerRealm*, int, fd_set*, fd_set*, TaskScheduler* scheduler); #endif diff --git a/src/task_list_node_struct.c b/src/task_list_node_struct.c new file mode 100644 index 0000000..70f43ef --- /dev/null +++ b/src/task_list_node_struct.c @@ -0,0 +1,124 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003-2006 jeremian + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include +#include + +#include "task_list_node_struct.h" + +/* + * Function name: TaskListNode_new + * Description: Creates and initializes new task list node. The task must point + * at previously allocated Task structure. + * Arguments: task - pointer to Task structure, which must be previously initialized + * Returns: Pointer to newly created TaskListNode structure. + */ + +TaskListNode* +TaskListNode_new(Task* task) +{ + TaskListNode* tmp = calloc(1, sizeof(TaskListNode)); + assert(task != NULL); + if (task == NULL) { + return NULL; + } + assert(tmp != NULL); + if (tmp == NULL) { + return NULL; + } + tmp->task = task; + + return tmp; +} + +/* + * Function name: TaskListNode_free + * Description: Frees the memory allocated for TaskListNode structure. + * Arguments: node - pointer to pointer to TaskListNode structure + */ + +void +TaskListNode_free(TaskListNode** node) +{ + assert(node != NULL); + if (node == NULL) { + return; + } + assert((*node) != NULL); + if ((*node) == NULL) { + return; + } + + free((*node)); + (*node) = NULL; +} + +/* + * Function name: TaskListNode_set_next + * Description: Sets the next pointer of the task list node. + * Arguments: node - pointer to TaskListNode structure + * next - the new next pointer + */ + +void +TaskListNode_set_next(TaskListNode* node, TaskListNode* next) +{ + assert(node != NULL); + if (node == NULL) { + return; + } + node->next = next; +} + +/* + * Function name: TaskListNode_set_previous + * Description: Sets the previous pointer of the task list node. + * Arguments: node - pointer to TaskListNode structure + * next - the new previous pointer + */ + +void +TaskListNode_set_previous(TaskListNode* node, TaskListNode* previous) +{ + assert(node != NULL); + if (node == NULL) { + return; + } + node->previous = previous; +} + +/* + * Function name: TaskListNode_get_task + * Description: Returns the task contained in this node. + * Arguments: node - pointer to TaskListNode structure + * Returns: The task contained in this node. + */ + +Task* +TaskListNode_get_task(TaskListNode* node) +{ + assert(node != NULL); + if (node == NULL) { + return NULL; + } + return node->task; +} diff --git a/src/task_list_node_struct.h b/src/task_list_node_struct.h new file mode 100644 index 0000000..2e0cb7a --- /dev/null +++ b/src/task_list_node_struct.h @@ -0,0 +1,42 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003-2006 jeremian + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _JS_TASK_LIST_NODE_STRUCT_H +#define _JS_TASK_LIST_NODE_STRUCT_H + +#include "task_struct.h" + +typedef struct tlnode{ + Task* task; + struct tlnode* previous; + struct tlnode* next; +} TaskListNode; + +/* 'constructor' */ +TaskListNode* TaskListNode_new(Task* task); +/* 'destructor' */ +void TaskListNode_free(TaskListNode** node); +/* setters */ +void TaskListNode_set_next(TaskListNode* node, TaskListNode* next); +void TaskListNode_set_previous(TaskListNode* node, TaskListNode* previous); +/* getters */ +Task* TaskListNode_get_task(TaskListNode* node); + +#endif diff --git a/src/task_scheduler_struct.c b/src/task_scheduler_struct.c new file mode 100644 index 0000000..b96a919 --- /dev/null +++ b/src/task_scheduler_struct.c @@ -0,0 +1,321 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003-2006 jeremian + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include +#include + +#include "timeval_functions.h" +#include "task_scheduler_struct.h" + +/* + * Function name: TaskScheduler_new + * Description: Creates and initializes task scheduler. + * Returns: Pointer to newly created TaskScheduler structure. + */ + +TaskScheduler* +TaskScheduler_new() +{ + TaskScheduler* tmp = calloc(1, sizeof(TaskScheduler)); + assert(tmp != NULL); + if (tmp == NULL) { + return NULL; + } + + return tmp; +} + +/* + * Function name: TaskScheduler_free + * Description: Frees the memory allocated for TaskScheduler structure. + * Arguments: scheduler - pointer to pointer to TaskScheduler structure + */ + +void +TaskScheduler_free(TaskScheduler** scheduler) +{ + assert(scheduler != NULL); + if (scheduler == NULL) { + return; + } + assert((*scheduler) != NULL); + if ((*scheduler) == NULL) { + return; + } + + while ((*scheduler)->head) { + TaskScheduler_removeTask((*scheduler), TaskListNode_get_task((*scheduler)->head)); + } + + free((*scheduler)); + (*scheduler) = NULL; +} + +/* + * Function name: TaskScheduler_get_actualTimer + * Description: Returns the smallest timeval structure in the scheduler. + * Arguments: scheduler - pointer to TaskScheduler structure + * Returns: The smallest timeval structure in the scheduler. + */ + +struct timeval* +TaskScheduler_get_actualTimer(TaskScheduler* scheduler) +{ + assert(scheduler != NULL); + if (scheduler == NULL) { + return NULL; + } + return Task_get_timer(TaskListNode_get_task(scheduler->actualTask)); +} + +/* + * Function name: TaskScheduler_hasMoreTasks + * Description: Checks if there is more tasks in the scheduler. + * Arguments: scheduler - pointer to TaskScheduler structure + * Returns: 0 - there is no more tasks in the scheduler, + * n>0 - there is more (n) tasks in the scheduler. + */ + +int +TaskScheduler_hasMoreTasks(TaskScheduler* scheduler) +{ + assert(scheduler != NULL); + if (scheduler == NULL) { + return 0; + } + return scheduler->numberOfTasks; +} + +/* + * Function name: TaskScheduler_addTask + * Description: Adds the task to the scheduler. + * Arguments: scheduler - pointer to TaskScheduler structure + * task - the task to add to the scheduler + * Returns: 0 - the task has been added successfully, + * 1 - the task has NOT been added. + */ + +int +TaskScheduler_addTask(TaskScheduler* scheduler, Task* task) +{ + TaskListNode* tmp; + assert(scheduler != NULL); + if (scheduler == NULL) { + return 1; + } + assert(task != NULL); + if (task == NULL) { + return 1; + } + tmp = TaskListNode_new(task); + assert(tmp != NULL); + if (tmp == NULL) { + return 1; + } + if (scheduler->head) { + TaskListNode_set_next(tmp, scheduler->head); + TaskListNode_set_previous(scheduler->head, tmp); + } + scheduler->head = tmp; + scheduler->numberOfTasks += 1; + if (scheduler->actualTask) { + if (timeval_compare(TaskScheduler_get_actualTimer(scheduler), Task_get_timer(task)) > 0) { + scheduler->actualTask = tmp; + } + } + else { + scheduler->actualTask = tmp; + } + return 0; +} + +/* + * Function name: find_tasknode_with_minimal_timer + * Description: Finds the task list node with minimal timer. + * Arguments: scheduler - pointer to TaskScheduler structure + * Returns: The task list node with minimal timer. + */ +static TaskListNode* +find_tasknode_with_minimal_timer(TaskScheduler* scheduler) +{ + TaskListNode* iterator; + TaskListNode* candidate; + assert(scheduler != NULL); + if (scheduler == NULL) { + return NULL; + } + if (scheduler->head == NULL) { + return NULL; + } + candidate = scheduler->head; + iterator = scheduler->head; + iterator = iterator->next; + while (iterator) { + if (timeval_compare(Task_get_timer(TaskListNode_get_task(iterator)), + Task_get_timer(TaskListNode_get_task(candidate))) == -1) { + candidate = iterator; + } + iterator = iterator->next; + } + return candidate; +} + +/* + * Function name: TaskScheduler_removeTask + * Description: Removes the task from the scheduler. + * Arguments: scheduler - pointer to TaskScheduler structure + * task - the task to remove from the scheduler + * Returns: 0 - the task has been removed successfully, + * 1 - the task has NOT been removed (probably there was no such task in the scheduler). + */ + +int +TaskScheduler_removeTask(TaskScheduler* scheduler, Task* task) +{ + TaskListNode* iterator; + Task* tmp; + assert(scheduler != NULL); + if (scheduler == NULL) { + return 1; + } + assert(task != NULL); + if (task == NULL) { + return 1; + } + iterator = scheduler->head; + while (iterator) { + tmp = TaskListNode_get_task(iterator); + if (tmp == task) { + if (iterator->previous) { + TaskListNode_set_next(iterator->previous, iterator->next); + } + if (iterator->next) { + TaskListNode_set_previous(iterator->next, iterator->previous); + } + if (iterator == scheduler->head) { + scheduler->head = iterator->next; + } + if (iterator == scheduler->actualTask) { + scheduler->actualTask = find_tasknode_with_minimal_timer(scheduler); + } + scheduler->numberOfTasks -= 1; + TaskListNode_free(&iterator); + return 0; + } + iterator = iterator->next; + } + return 1; +} + +/* + * Function name: TaskScheduler_startWatching + * Description: Starts counting the time for the actual timer. + * Arguments: scheduler - pointer to TaskScheduler structure + * Returns: 0 - success, + * 1 - failure. + */ + +int +TaskScheduler_startWatching(TaskScheduler* scheduler) +{ + struct timeval* tmp; + assert(scheduler != NULL); + if (scheduler == NULL) { + return 1; + } + tmp = TaskScheduler_get_actualTimer(scheduler); + assert(tmp != NULL); + if (tmp == NULL) { + return 1; + } + scheduler->delta = *tmp; + return 0; +} + +/* + * Function name: TaskScheduler_stopWatching + * Description: Stops counting the time for the actual timer. + * Updates all the timers and destroys them if needed. + * Arguments: scheduler - pointer to TaskScheduler structure + * Returns: 0 - success, + * 1 - failure. + */ + +int +TaskScheduler_stopWatching(TaskScheduler* scheduler) +{ + TaskListNode* iterator; + TaskListNode* actualTask; + Task* backup; + struct timeval* tmp; + int result; + assert(scheduler != NULL); + if (scheduler == NULL) { + return 1; + } + tmp = TaskScheduler_get_actualTimer(scheduler); + assert(tmp != NULL); + if (tmp == NULL) { + return 1; + } + if (timeval_subtract(&(scheduler->delta), tmp)) { + return 1; + } + actualTask = scheduler->actualTask; + assert(scheduler->actualTask != NULL); + iterator = scheduler->head; + while (iterator) { + if (iterator != actualTask) { + result = timeval_subtract(Task_get_timer(TaskListNode_get_task(iterator)), &(scheduler->delta)); + assert(result == 0); + } + if (timeval_lq_zero(Task_get_timer(TaskListNode_get_task(iterator)))) { + Task_exec(TaskListNode_get_task(iterator)); + backup = TaskListNode_get_task(iterator); + iterator = iterator->next; + TaskScheduler_removeTask(scheduler, backup); + continue; + } + iterator = iterator->next; + } + TaskScheduler_update(scheduler); + return 0; +} + +/* + * Function name: TaskScheduler_update + * Description: Updates the actual timer. + * Arguments: scheduler - pointer to TaskScheduler structure + * Returns: 0 - success, + * 1 - failure. + */ + +int +TaskScheduler_update(TaskScheduler* scheduler) +{ + assert(scheduler != NULL); + if (scheduler == NULL) { + return 1; + } + scheduler->actualTask = find_tasknode_with_minimal_timer(scheduler); + return 0; +} diff --git a/src/task_scheduler_struct.h b/src/task_scheduler_struct.h new file mode 100644 index 0000000..4114f30 --- /dev/null +++ b/src/task_scheduler_struct.h @@ -0,0 +1,47 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003-2006 jeremian + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _JS_TASK_SCHEDULER_STRUCT_H +#define _JS_TASK_SCHEDULER_STRUCT_H + +#include "task_list_node_struct.h" + +typedef struct { + TaskListNode* head; + int numberOfTasks; + TaskListNode* actualTask; + struct timeval delta; +} TaskScheduler; + +/* 'constructor' */ +TaskScheduler* TaskScheduler_new(); +/* 'destructor' */ +void TaskScheduler_free(TaskScheduler** scheduler); +/* getters */ +struct timeval* TaskScheduler_get_actualTimer(TaskScheduler* scheduler); +/* other */ +int TaskScheduler_hasMoreTasks(TaskScheduler* scheduler); +int TaskScheduler_addTask(TaskScheduler* scheduler, Task* task); +int TaskScheduler_removeTask(TaskScheduler* scheduler, Task* task); +int TaskScheduler_startWatching(TaskScheduler* scheduler); +int TaskScheduler_stopWatching(TaskScheduler* scheduler); +int TaskScheduler_update(TaskScheduler* scheduler); + +#endif diff --git a/src/task_struct.c b/src/task_struct.c new file mode 100644 index 0000000..b422ffb --- /dev/null +++ b/src/task_struct.c @@ -0,0 +1,122 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003-2006 jeremian + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include +#include + +#include "task_struct.h" + +/* + * Function name: Task_new + * Description: Creates and initializes new task. User is responsible for + * allocating/freeing memory pointed by the pointers. + * Arguments: timerp - pointer to timeval structure used to counte time (required) + * function - pointer to function executed when the time is out (optional) + * data - pointer to data passed to function executed when the time is out (optional) + * clean - pointer to function that frees the data + * Returns: Pointer to newly created Task structure. + */ + +Task* +Task_new(struct timeval* timerp, void (*function)(void*), void* data, void (*clean)(void**)) +{ + Task* tmp; + assert(timerp != NULL); + if (timerp == NULL) { + return NULL; + } + tmp = calloc(1, sizeof(Task)); + assert(tmp != NULL); + if (tmp == NULL) { + return NULL; + } + tmp->timerp = timerp; + tmp->function = function; + tmp->data = data; + tmp->clean = clean; + + return tmp; +} + +/* + * Function name: Task_free + * Description: Frees the memory allocated for Task structure. User has to free the memory at the + * pointers by his own. + * Arguments: task - pointer to pointer to Task structure + */ + +void +Task_free(Task** task) +{ + assert(task != NULL); + if (task == NULL) { + return; + } + assert((*task) != NULL); + if ((*task) == NULL) { + return; + } + + if ((*task)->clean) { + if ((*task)->data) { + (*task)->clean(&((*task)->data)); + } + } + + free((*task)); + (*task) = NULL; +} + +/* + * Function name: Task_get_timer + * Description: Returns the timer of the task. + * Arguments: task - pointer to Task structure + * Returns: The timer of the task. + */ + +struct timeval* +Task_get_timer(Task* task) +{ + assert(task != NULL); + if (task == NULL) { + return NULL; + } + return task->timerp; +} + +/* + * Function name: Task_exec + * Description: Executes the function encapsulated in the task. + * Arguments: task - pointer to Task structure + */ + +void +Task_exec(Task* task) +{ + assert(task != NULL); + if (task == NULL) { + return; + } + if (task->function) { + task->function(task->data); + } +} diff --git a/src/task_struct.h b/src/task_struct.h new file mode 100644 index 0000000..334e97d --- /dev/null +++ b/src/task_struct.h @@ -0,0 +1,39 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003-2006 jeremian + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _JS_TASK_STRUCT_H +#define _JS_TASK_STRUCT_H + +typedef struct { + struct timeval* timerp; + void (*function)(void*); + void* data; + void (*clean)(void**); +} Task; + +/* 'constructor' */ +Task* Task_new(struct timeval*, void (*function)(void*), void*, void (*clean)(void**)); +/* 'destructor' */ +void Task_free(Task** task); +/* getters */ +struct timeval* Task_get_timer(Task* task); +void Task_exec(Task* task); + +#endif diff --git a/src/timeval_functions.c b/src/timeval_functions.c index 84bfe7e..394b654 100644 --- a/src/timeval_functions.c +++ b/src/timeval_functions.c @@ -20,6 +20,9 @@ #include +#include +#include + #include "timeval_functions.h" /* @@ -38,3 +41,94 @@ timeval_create(long tv_sec, long tv_usec) tmp.tv_usec = tv_usec; return tmp; } + +/* + * Function name: timeval_compare + * Description: Compares two pointers to timeval structures. + * Arguments: first - the first timeval structure to compare + * second - the second timeval structure to compare + * Returns: -1 - the second structure is bigger + * 0 - structures are equals + * 1 - the first structure is bigger + */ + +int +timeval_compare(struct timeval* first, struct timeval* second) +{ + if (first == NULL) { + if (second == NULL) { + return 0; + } + else { + return -1; + } + } + if (second == NULL) { + return 1; + } + if (first->tv_sec < second->tv_sec) { + return -1; + } + if (first->tv_sec > second->tv_sec) { + return 1; + } + if (first->tv_usec < second->tv_usec) { + return -1; + } + if (first->tv_usec > second->tv_usec) { + return 1; + } + return 0; +} + +/* + * Function name: timeval_subtract + * Description: Substracts second timeval structure from the first, updating the latter one. + * Arguments: first - the first timeval structure to subtract operation + * second - the second timeval structure to subtract operation + * Returns: 0 - success, + * 1 - failure. + */ + +int +timeval_subtract(struct timeval* first, struct timeval* second) +{ + assert(first != NULL); + assert(second != NULL); + if ((first == NULL) || (second == NULL)) { + return 1; + } + if (first->tv_usec < second->tv_usec) { + first->tv_sec -= 1; + first->tv_usec = 1000000 - second->tv_usec + first->tv_usec; + } + else { + first->tv_usec -= second->tv_usec; + } + first->tv_sec -= second->tv_sec; + return 0; +} + +/* + * Function name: timeval_lq_zero + * Description: Checks if the timer is less or equiv zero. + * Arguments: timer - the timeval structure to check + * Returns: 1 - the timer is less or equiv zero, + * 0 - the timer is bigger than zero. + */ + +int +timeval_lq_zero(struct timeval* timer) +{ + assert(timer != NULL); + if (timer == NULL) { + return 0; + } + if (timer->tv_sec < 0) { + return 1; + } + if ((timer->tv_sec == 0) && (timer->tv_usec == 0)) { + return 1; + } + return 0; +} diff --git a/src/timeval_functions.h b/src/timeval_functions.h index 8741442..8472760 100644 --- a/src/timeval_functions.h +++ b/src/timeval_functions.h @@ -24,6 +24,9 @@ #include struct timeval timeval_create(long tv_sec, long tv_usec); +int timeval_compare(struct timeval* first, struct timeval* second); +int timeval_subtract(struct timeval* first, struct timeval* second); +int timeval_lq_zero(struct timeval* timer); #endif diff --git a/src/usage.c b/src/usage.c index 2241228..3f13a78 100644 --- a/src/usage.c +++ b/src/usage.c @@ -72,9 +72,11 @@ server_long_usage(char* info) printf(" -f, --cfgfile - the name of the file with the configuration for the\n"); printf(" active forwarder (server)\n"); printf(" -D, --dateformat - format of the date printed in logs (see 'man strftime'\n"); - printf(" for details) (default: %%Y-%%m-%%d %%H:%%M:%%S)\n\n"); + printf(" for details) (default: %%Y-%%m-%%d %%H:%%M:%%S)\n"); printf(" -t, --timeout - the timeout value for the client's connection\n"); printf(" (default: 5)\n"); + printf(" --maxidle - the maximum idle time for the client's connection\n"); + printf(" (default: disabled)\n"); printf(" -u, --users - the amount of users allowed to use this server\n"); printf(" (default: 5)\n"); printf(" -C, --clients - the number of allowed clients to use this server\n"); -- cgit v1.1