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 06:50:13 +0000 (15:50 +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 e1f560c35081085124219a4a0647710aa2cc3886..ecfdae4918c17806a8154323c8c792931dcf5095 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;
 }
 
 /*
@@ -237,3 +242,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 85ffb6039a8a052e0a1a3aa4ce10070cee9e2a18..de9ed02b19221767d9ff42aa5c33d352fbb94fa6 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);
@@ -59,4 +64,7 @@ extern ConnectionInfo *pool_coninfo_pid(int pid, int connection_pool, int backen
 extern void pool_coninfo_set_frontend_connected(int proc_id, int pool_index);
 extern void pool_coninfo_unset_frontend_connected(int proc_id, int pool_index);
 
+extern void pool_alarm(pool_sighandler_t handler, unsigned int second);
+extern void pool_undo_alarm();
+
 #endif /* POOL_PROCESS_CONTEXT_H */
index 31a3d343b8d11feb72561b3184c5ac0cf43a1bac..3280733d0bfdde1fb4cc06eb5531f30f70a76532 100644 (file)
@@ -1038,8 +1038,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;
 }
 
@@ -1047,8 +1046,7 @@ static void disable_authentication_timeout(void)
 {
        if(alarm_enabled)
        {
-               alarm(0);
-               pool_signal(SIGALRM, SIG_IGN);
+               pool_undo_alarm();
                alarm_enabled = false;
        }
 }
index 61046570b18e74a0c92af0ce37799425f4148d98..b58773dfddf1a38186981e60938d3bba8b9b781c 100644 (file)
@@ -356,8 +356,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);
 }
 
 /*
@@ -447,8 +446,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);