When server gets shutdown signal (SIGUSR1, SIGTERM, SIGHUP, SIGINT), it
broadcasts new OCC_SHUTTING_DOWN command to all clients and reschedules
received signal in 2 secs.

When client receives OCC_SHUTTING_DOWN, it fires SIGUSR1 and switches to
the next remote.
---
 src/openvpn/multi.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++----
 src/openvpn/multi.h | 14 +++++++++++-
 src/openvpn/occ.c   |  8 +++++++
 src/openvpn/occ.h   |  6 +++++
 4 files changed, 86 insertions(+), 5 deletions(-)

diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 4412491..b5f2dd2 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -396,6 +396,8 @@ multi_init (struct multi_context *m, struct context *t, 
bool tcp_mode, int threa
         t->options.stale_routes_check_interval, 
t->options.stale_routes_ageing_time);
       event_timeout_init (&m->stale_routes_check_et, 
t->options.stale_routes_check_interval, 0);
     }
+
+  m->deferred_signal.signal_received = 0;
 }

 const char *
@@ -603,6 +605,25 @@ multi_close_instance (struct multi_context *m,
   perf_pop ();
 }

+void
+multi_broadcast_shutdown (struct multi_context *m)
+{
+  msg (D_LOW, "multi_broadcast_shutdown");
+
+  struct gc_arena gc = gc_new ();
+  struct buffer buf = alloc_buf_gc (BUF_SIZE (&m->top.c2.frame), &gc);
+
+  buf_init (&buf, FRAME_HEADROOM (&m->top.c2.frame));
+  buf_safe (&buf, MAX_RW_SIZE_TUN (&m->top.c2.frame));
+  buf_write (&buf, occ_magic, OCC_STRING_SIZE);
+
+  buf_write_u8 (&buf, OCC_SHUTTING_DOWN);
+
+  multi_bcast (m, &buf, NULL, NULL);
+
+  gc_free (&gc);
+}
+
 /*
  * Called on shutdown or restart.
  */
@@ -1952,7 +1973,7 @@ multi_unicast (struct multi_context *m,
 /*
  * Broadcast a packet to all clients.
  */
-static void
+void
 multi_bcast (struct multi_context *m,
             const struct buffer *buf,
             const struct multi_instance *sender_instance,
@@ -2571,10 +2592,18 @@ multi_process_timeout (struct multi_context *m, const 
unsigned int mpp_flags)
   /* instance marked for wakeup? */
   if (m->earliest_wakeup)
     {
-      set_prefix (m->earliest_wakeup);
-      ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+      if (m->earliest_wakeup == (struct multi_instance*)&m->deferred_signal)
+       {
+         schedule_remove_entry(m->schedule, (struct schedule_entry*) 
&m->deferred_signal);
+         throw_signal(m->deferred_signal.signal_received);
+        }
+      else
+       {
+         set_prefix (m->earliest_wakeup);
+         ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+         clear_prefix ();
+       }
       m->earliest_wakeup = NULL;
-      clear_prefix ();
     }
   return ret;
 }
@@ -2699,6 +2728,10 @@ multi_top_free (struct multi_context *m)
   free_context_buffers (m->top.c2.buffers);
 }

+bool is_shutdown_signal(int sig) {
+    return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == 
SIGINT);
+}
+
 /*
  * Return true if event loop should break,
  * false if it should continue.
@@ -2714,6 +2747,28 @@ multi_process_signal (struct multi_context *m)
       m->top.sig->signal_received = 0;
       return false;
     }
+  else if (proto_is_dgram(m->top.options.ce.proto) &&
+      is_shutdown_signal(m->top.sig->signal_received) &&
+      (m->deferred_signal.signal_received == 0))
+    {
+      // broadcast OCC_SHUTTING_DOWN to all connected clients
+      multi_broadcast_shutdown(m);
+
+      // schedule signal
+      openvpn_gettimeofday (&m->deferred_signal.wakeup, NULL);
+      struct timeval tv;
+      tv.tv_sec = 2;
+      tv.tv_usec = 0;
+      tv_add (&m->deferred_signal.wakeup, &tv);
+
+      m->deferred_signal.signal_received = m->top.sig->signal_received;
+
+      schedule_add_entry (m->schedule, (struct schedule_entry *) 
&m->deferred_signal,
+                     &m->deferred_signal.wakeup, compute_wakeup_sigma 
(&m->deferred_signal.wakeup));
+
+      m->top.sig->signal_received = 0;
+      return false;
+  }
   return true;
 }

diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h
index 32b89d2..c9c1940 100644
--- a/src/openvpn/multi.h
+++ b/src/openvpn/multi.h
@@ -57,6 +57,13 @@ struct multi_reap
 };


+struct deferred_signal_schedule_entry
+{
+  struct schedule_entry se;
+  int signal_received;
+  struct timeval wakeup;
+};
+
 /**
  * Server-mode state structure for one single VPN tunnel.
  *
@@ -172,6 +179,8 @@ struct multi_context {
    * Timer object for stale route check
    */
   struct event_timeout stale_routes_check_et;
+
+  struct deferred_signal_schedule_entry deferred_signal;
 };

 /*
@@ -190,7 +199,6 @@ struct multi_route
   time_t last_reference;
 };

-
 /**************************************************************************/
 /**
  * Main event loop for OpenVPN in server mode.
@@ -290,6 +298,10 @@ bool multi_process_post (struct multi_context *m, struct 
multi_instance *mi, con
 bool multi_process_incoming_link (struct multi_context *m, struct 
multi_instance *instance, const unsigned int mpp_flags);


+void multi_bcast (struct multi_context *m, const struct buffer *buf,
+                 const struct multi_instance *sender_instance,
+                 const struct mroute_addr *sender_addr);
+
 /**
  * Determine the destination VPN tunnel of a packet received over the
  * virtual tun/tap network interface and then process it accordingly.
diff --git a/src/openvpn/occ.c b/src/openvpn/occ.c
index ff48706..3695b07 100644
--- a/src/openvpn/occ.c
+++ b/src/openvpn/occ.c
@@ -390,6 +390,14 @@ process_received_occ_msg (struct context *c)
       c->sig->signal_received = SIGTERM;
       c->sig->signal_text = "remote-exit";
       break;
+
+    case OCC_SHUTTING_DOWN:
+      msg (D_LOW, "RECEIVED OCC_SHUTTING_DOWN");
+      c->sig->signal_received = SIGUSR1;
+      c->sig->signal_text = "remote-shutdown";
+      c->options.no_advance = false;
+      break;
+
     }
   c->c2.buf.len = 0; /* don't pass packet on */
 }
diff --git a/src/openvpn/occ.h b/src/openvpn/occ.h
index 5d88cc9..0d10f2e 100644
--- a/src/openvpn/occ.h
+++ b/src/openvpn/occ.h
@@ -69,6 +69,12 @@
  */
 #define OCC_EXIT               6

+
+/*
+ * Notifies clients that server is shutting down
+ */
+#define OCC_SHUTTING_DOWN      7
+
 /*
  * Used to conduct a load test command sequence
  * of UDP connection for empirical MTU measurement.
-- 
1.9.1


Reply via email to