Fix connection_life_time broken by authentication_timeout
authorYugo Nagata <nagata@sraoss.co.jp>
Wed, 4 Jan 2017 05:20:24 +0000 (14:20 +0900)
committerYugo Nagata <nagata@sraoss.co.jp>
Wed, 4 Jan 2017 05:20:24 +0000 (14:20 +0900)
When authentication_timeout is enabled,
connection_life_time could never be expired, because
alarm(0) is called at reading start-up packet.

When there only one connection pool is used, this
problem doesn't occur because the signal handler
for connection_life_time is always set at the end
of the session. However, if more than one connection
pools exist, the handler isn't set but only the time
to colse the connection is calculated.

To fix it, when authentication_timeout is enabled,
save the signal handler for conneciont_life_time
and the remaining time, and undo the handler when
authentication_timeout is disabled.

src/context/pool_process_context.c
src/include/context/pool_process_context.h
src/protocol/child.c
src/protocol/pool_connection_pool.c

index cfc2369c6667335eac4d8203e5caff3fd2ae2aa7..f29553a56a248df1cedb6b004111d3e5d762df19 100644 (file)
@@ -52,6 +52,11 @@ void pool_init_process_context(void)
        process_context->proc_id = my_proc_id;
 
        process_context->local_session_id = 0;          /* initialize local session counter */
+
+       process_context->last_alarm_handler = SIG_IGN;
+       process_context->last_alarm_time = 0;
+       process_context->last_alarm_second = 0;
+       process_context->undo_alarm_second = 0;
 }
 
 /*
@@ -318,3 +323,47 @@ void pool_coninfo_unset_frontend_connected(int proc_id, int pool_index)
                con->connected = false;
        }
 }
+
+/*
+ * Set an alarm clock and a signal handler.
+ * For pool_alarm_undo(), the alarm second and the old handler
+ * are saved, and the remaining time is calculated.
+ */
+void pool_alarm(pool_sighandler_t handler, unsigned int second)
+{
+       POOL_PROCESS_CONTEXT *p = pool_get_process_context();
+       time_t  now = time(NULL);
+
+       alarm(second);
+       p->last_alarm_handler = pool_signal(SIGALRM, handler);
+
+       if (p->last_alarm_second)
+       {
+               p->undo_alarm_second = p->last_alarm_second - (now - p->last_alarm_time);
+               if (p->undo_alarm_second <= 0)
+                 p->undo_alarm_second = 1;
+       }
+
+       p->last_alarm_time = now;
+       p->last_alarm_second = second;
+}
+
+/*
+ * Undo the alarm signal handler using the remaining time.
+ */
+void pool_undo_alarm()
+{
+       POOL_PROCESS_CONTEXT *p = pool_get_process_context();
+
+       if (p->undo_alarm_second)
+       {
+               alarm(p->undo_alarm_second);
+               pool_signal(SIGALRM, p->last_alarm_handler);
+               p->undo_alarm_second = 0;
+       }
+       else
+       {
+               alarm(0);
+               pool_signal(SIGALRM, SIG_IGN);
+       }
+}
index 5bdc49819cc668a9601a1ceba2f163ead849a24e..caab7b19c1fe55f64413672aca6d23d85c77c21c 100644 (file)
@@ -46,6 +46,11 @@ typedef struct {
 
        int local_session_id;   /* local session id */
 
+       pool_sighandler_t last_alarm_handler;
+       time_t  last_alarm_time;
+       unsigned int last_alarm_second;
+       unsigned int undo_alarm_second;
+
 } POOL_PROCESS_CONTEXT;
 
 extern void pool_init_process_context(void);
@@ -64,4 +69,7 @@ extern bool pool_is_my_coninfo(ConnectionInfo* connInfo);
 extern void pool_set_connection_will_be_terminated(ConnectionInfo* connInfo);
 extern void pool_unset_connection_will_be_terminated(ConnectionInfo* connInfo);
 
+extern void pool_alarm(pool_sighandler_t handler, unsigned int second);
+extern void pool_undo_alarm();
+
 #endif /* POOL_PROCESS_CONTEXT_H */
index db58723396bb8088a3e21cbce93b21ae258ca5d1..797a976813cc2a7969041e601c218a4909fbef06 100644 (file)
@@ -1034,8 +1034,7 @@ static void enable_authentication_timeout(void)
 {
        if(pool_config->authentication_timeout <= 0)
                return;
-       alarm(pool_config->authentication_timeout);
-       pool_signal(SIGALRM, authentication_timeout);
+       pool_alarm(authentication_timeout, pool_config->authentication_timeout);
        alarm_enabled = true;
 }
 
@@ -1043,8 +1042,7 @@ static void disable_authentication_timeout(void)
 {
        if(alarm_enabled)
        {
-               alarm(0);
-               pool_signal(SIGALRM, SIG_IGN);
+               pool_undo_alarm();
                alarm_enabled = false;
        }
 }
index 537ea93bf757ee299febb4775fd95a9632a54b50..289cec4881fb90b388e40ee07b3da4143c401698 100644 (file)
@@ -353,8 +353,7 @@ void pool_connection_pool_timer(POOL_CONNECTION_POOL *backend)
                (errmsg("setting backend connection close timer"),
                         errdetail("setting alarm after %d seconds", pool_config->connection_life_time)));
 
-       pool_signal(SIGALRM, pool_backend_timer_handler);
-       alarm(pool_config->connection_life_time);
+       pool_alarm(pool_backend_timer_handler, pool_config->connection_life_time);
 }
 
 /*
@@ -444,8 +443,7 @@ void pool_backend_timer(void)
                nearest = pool_config->connection_life_time - (now - nearest);
                if (nearest <= 0)
                  nearest = 1;
-               pool_signal(SIGALRM, pool_backend_timer_handler);
-               alarm(nearest);
+               pool_alarm(pool_backend_timer_handler, nearest);
        }
 
        POOL_SETMASK(&UnBlockSig);