diff --git a/server/core/config.c b/server/core/config.c index ad7c6fd6b..309f5e709 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -40,6 +40,7 @@ * internal router suppression of messages * 30/10/14 Massimiliano Pinto Added disable_master_failback parameter * 07/11/14 Massimiliano Pinto Addition of monitor timeouts for connect/read/write + * 20/02/15 Markus Mäkelä Added connection_timeout parameter for services * * @endverbatim */ @@ -278,6 +279,7 @@ int error_count = 0; char *user; char *auth; char *enable_root_user; + char *connection_timeout; char *weightby; char *version_string; bool is_rwsplit = false; @@ -288,6 +290,9 @@ int error_count = 0; enable_root_user = config_get_value( obj->parameters, "enable_root_user"); + connection_timeout = config_get_value( + obj->parameters, + "connection_timeout"); weightby = config_get_value(obj->parameters, "weightby"); version_string = config_get_value(obj->parameters, @@ -332,6 +337,11 @@ int error_count = 0; serviceEnableRootUser( obj->element, config_truth_value(enable_root_user)); + if (connection_timeout) + serviceSetTimeout( + obj->element, + atoi(connection_timeout)); + if (weightby) serviceWeightBy(obj->element, weightby); @@ -1281,13 +1291,15 @@ SERVER *server; char *user; char *auth; char *enable_root_user; + char *connection_timeout; char* max_slave_conn_str; char* max_slave_rlag_str; char *version_string; char *allow_localhost_match_wildcard_host; enable_root_user = config_get_value(obj->parameters, "enable_root_user"); - + connection_timeout = config_get_value(obj->parameters, "connection_timeout"); + user = config_get_value(obj->parameters, "user"); auth = config_get_value(obj->parameters, @@ -1310,6 +1322,8 @@ SERVER *server; auth); if (enable_root_user) serviceEnableRootUser(service, atoi(enable_root_user)); + if (connection_timeout) + serviceSetTimeout(service, atoi(connection_timeout)); if (allow_localhost_match_wildcard_host) serviceEnableLocalhostMatchWildcardHost( @@ -1415,11 +1429,17 @@ SERVER *server; char *user; char *auth; char *enable_root_user; + char *connection_timeout; char *allow_localhost_match_wildcard_host; enable_root_user = config_get_value(obj->parameters, "enable_root_user"); + + connection_timeout = + config_get_value(obj->parameters, + "connection_timeout"); + allow_localhost_match_wildcard_host = config_get_value(obj->parameters, "localhost_match_wildcard_host"); @@ -1438,6 +1458,9 @@ SERVER *server; if (enable_root_user) serviceEnableRootUser(obj->element, atoi(enable_root_user)); + if (connection_timeout) + serviceSetTimeout(obj->element, atoi(connection_timeout)); + if (allow_localhost_match_wildcard_host) serviceEnableLocalhostMatchWildcardHost( obj->element, @@ -1661,6 +1684,7 @@ static char *service_params[] = "user", "passwd", "enable_root_user", + "connection_timeout", "localhost_match_wildcard_host", "max_slave_connections", "max_slave_replication_lag", diff --git a/server/core/service.c b/server/core/service.c index 167f8a4e7..f3535ea6a 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -57,6 +57,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -431,6 +432,8 @@ int listeners = 0; service->stats.started = time(0); } + hktask_add("connection_timeout",session_close_timeouts,NULL,5); + return listeners; } @@ -803,6 +806,23 @@ serviceEnableRootUser(SERVICE *service, int action) return 1; } +/** + * Sets the session timeout for the service. + * @param service Service to configure + * @param val Timeout in seconds + * @return 1 on success, 0 when the value is invalid + */ +int +serviceSetTimeout(SERVICE *service, int val) +{ + + if(val < 0) + return 0; + service->conn_timeout = val; + + return 1; +} + /** * Trim whitespace from the from an rear of a string * diff --git a/server/core/session.c b/server/core/session.c index fb1dda79f..f5fe2770c 100644 --- a/server/core/session.c +++ b/server/core/session.c @@ -42,6 +42,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -909,3 +910,35 @@ SESSION *get_all_sessions() { return allSessions; } + +/** + * Close sessions that have been idle for too long. + * + * If the time since a session last sent data is grater than the set value in the + * service, it is disconnected. The default value for the timeout for a service is 0. + * This means that connections are never timed out. + * @param data NULL, this is only here to satisfy the housekeeper function requirements. + */ +void session_close_timeouts(void* data) +{ + SESSION* ses; + + spinlock_acquire(&session_spin); + ses = get_all_sessions(); + spinlock_release(&session_spin); + + while(ses) + { + if(ses->client && ses->client->state == DCB_STATE_POLLING && + ses->service->conn_timeout > 0 && + hkheartbeat - ses->client->last_read > ses->service->conn_timeout * 10) + { + ses->client->func.hangup(ses->client); + } + + spinlock_acquire(&session_spin); + ses = ses->next; + spinlock_release(&session_spin); + + } +} \ No newline at end of file diff --git a/server/include/dcb.h b/server/include/dcb.h index e360a8fbb..020b30e8b 100644 --- a/server/include/dcb.h +++ b/server/include/dcb.h @@ -261,7 +261,7 @@ typedef struct dcb { SPINLOCK polloutlock; int polloutbusy; int writecheck; - + time_t last_read; /*< Last time the DCB received data */ unsigned int high_water; /**< High water mark */ unsigned int low_water; /**< Low water mark */ struct server *server; /**< The associated backend server */ diff --git a/server/include/service.h b/server/include/service.h index ab18e5d29..7d7391ca6 100644 --- a/server/include/service.h +++ b/server/include/service.h @@ -142,6 +142,7 @@ typedef struct service { rate_limit; /**< The refresh rate limit for users table */ FILTER_DEF **filters; /**< Ordered list of filters */ int n_filters; /**< Number of filters */ + int conn_timeout; /*< Session timeout in seconds */ char *weightby; struct service *next; /**< The next service in the linked list */ } SERVICE; @@ -172,6 +173,7 @@ extern int serviceSetUser(SERVICE *, char *, char *); extern int serviceGetUser(SERVICE *, char **, char **); extern void serviceSetFilters(SERVICE *, char *); extern int serviceEnableRootUser(SERVICE *, int ); +extern int serviceSetTimeout(SERVICE *, int ); extern void serviceWeightBy(SERVICE *, char *); extern char *serviceGetWeightingParameter(SERVICE *); extern int serviceEnableLocalhostMatchWildcardHost(SERVICE *, int); diff --git a/server/include/session.h b/server/include/session.h index e008cc4ff..fd76eb2b1 100644 --- a/server/include/session.h +++ b/server/include/session.h @@ -33,6 +33,7 @@ * 02-09-2013 Massimiliano Pinto Added session ref counter * 29-05-2014 Mark Riddoch Support for filter mechanism * added + * 20-02-2015 Markus Mäkelä Added session timeouts * * @endverbatim */ @@ -167,5 +168,6 @@ bool session_link_dcb(SESSION *, struct dcb *); SESSION* get_session_by_router_ses(void* rses); void session_enable_log(SESSION* ses, logfile_id_t id); void session_disable_log(SESSION* ses, logfile_id_t id); +void session_close_timeouts(void* data); #endif diff --git a/server/modules/include/maxscaled.h b/server/modules/include/maxscaled.h index 01a3da227..5d398f1c0 100644 --- a/server/modules/include/maxscaled.h +++ b/server/modules/include/maxscaled.h @@ -31,7 +31,7 @@ */ #include #include - +#include /** * The telnetd specific protocol structure to put in the DCB. */ diff --git a/server/modules/include/mysql_client_server_protocol.h b/server/modules/include/mysql_client_server_protocol.h index bef74f45c..38226ac79 100644 --- a/server/modules/include/mysql_client_server_protocol.h +++ b/server/modules/include/mysql_client_server_protocol.h @@ -61,6 +61,7 @@ #include #include #include +#include #define GW_MYSQL_VERSION "MaxScale " MAXSCALE_VERSION #define GW_MYSQL_LOOP_TIMEOUT 300000000 diff --git a/server/modules/include/telnetd.h b/server/modules/include/telnetd.h index c427c2e8b..0d3d35179 100644 --- a/server/modules/include/telnetd.h +++ b/server/modules/include/telnetd.h @@ -30,7 +30,7 @@ * @endverbatim */ #include - +#include /** * The telnetd specific protocol structure to put in the DCB. */ diff --git a/server/modules/protocol/maxscaled.c b/server/modules/protocol/maxscaled.c index 052026fbe..962bdafd8 100644 --- a/server/modules/protocol/maxscaled.c +++ b/server/modules/protocol/maxscaled.c @@ -144,6 +144,9 @@ char *password; if ((n = dcb_read(dcb, &head)) != -1) { + + dcb->last_read = hkheartbeat; + if (head) { unsigned char *ptr = GWBUF_DATA(head); diff --git a/server/modules/protocol/mysql_backend.c b/server/modules/protocol/mysql_backend.c index e52d996bd..7741fdcc4 100644 --- a/server/modules/protocol/mysql_backend.c +++ b/server/modules/protocol/mysql_backend.c @@ -448,6 +448,8 @@ static int gw_read_backend_event(DCB *dcb) { /* read available backend data */ rc = dcb_read(dcb, &read_buffer); + dcb->last_read = hkheartbeat; + if (rc < 0) { GWBUF* errbuf; diff --git a/server/modules/protocol/mysql_client.c b/server/modules/protocol/mysql_client.c index f78bb4537..14279c4f0 100644 --- a/server/modules/protocol/mysql_client.c +++ b/server/modules/protocol/mysql_client.c @@ -576,6 +576,8 @@ int gw_read_client_event( CHK_PROTOCOL(protocol); rc = dcb_read(dcb, &read_buffer); + dcb->last_read = hkheartbeat; + if (rc < 0) { dcb_close(dcb); diff --git a/server/modules/protocol/mysql_common.c b/server/modules/protocol/mysql_common.c index c9340b325..919c7bae8 100644 --- a/server/modules/protocol/mysql_common.c +++ b/server/modules/protocol/mysql_common.c @@ -170,6 +170,9 @@ int gw_read_backend_handshake( if ((n = dcb_read(dcb, &head)) != -1) { + + dcb->last_read = hkheartbeat; + if (head) { payload = GWBUF_DATA(head); @@ -420,6 +423,8 @@ int gw_receive_backend_auth( n = dcb_read(dcb, &head); + dcb->last_read = hkheartbeat; + /*< * Read didn't fail and there is enough data for mysql packet. */ diff --git a/server/modules/protocol/telnetd.c b/server/modules/protocol/telnetd.c index f73a2942b..29bc6dd4f 100644 --- a/server/modules/protocol/telnetd.c +++ b/server/modules/protocol/telnetd.c @@ -156,6 +156,9 @@ char *password, *t; if ((n = dcb_read(dcb, &head)) != -1) { + + dcb->last_read = hkheartbeat; + if (head) { unsigned char *ptr = GWBUF_DATA(head);