Browse code

Send push reply right after async auth complete

v3:
* better comments
* better variable naming
* include sys/inotify.h if HAVE_SYS_INOTIFY_H is defined

v2:
More careful inotify_watchers handling
* Ensure that same multi_instance is added only once
* Ensure that multi_instance is always removed

v1:
This feature speeds up connection establishment in cases when async
authentication result is not ready when first push request arrives. At
the moment server sends push reply only when it receives next push
request, which comes 5 seconds later.

Implementation overview.

Add new configure option ENABLE_ASYNC_PUSH, which can be enabled if
system supports inotify.

Add inotify descriptor to an event loop. Add inotify watch for a
authentication control file. Store mapping between watch descriptor and
multi_instance in a dictionary. When file is closed, inotify fires an
event and we continue with connection establishment - call client-
connect etc and send push reply.

Inotify watch descriptor got automatically deleted after file is closed
or when file is removed. We catch that event and remove it from the
dictionary.

Feature is easily tested with sample "defer" plugin and following settings:

auth-user-pass-optional
setenv test_deferred_auth 3
plugin simple.so

Signed-off-by: Lev Stipakov <lstipakov@gmail.com>

Add doxygen comment
Acked-by: David Sommerseth <davids@redhat.com>
Message-Id: <1444493065-13506-1-git-send-email-lstipakov@gmail.com>
URL: http://article.gmane.org/gmane.network.openvpn.devel/10248
Signed-off-by: David Sommerseth <davids@redhat.com>

Lev Stipakov authored on 2015/10/11 01:04:25
Showing 9 changed files
... ...
@@ -271,6 +271,13 @@ AC_ARG_ENABLE(
271 271
 	[enable_systemd="no"]
272 272
 )
273 273
 
274
+AC_ARG_ENABLE(
275
+	[async-push],
276
+	[AS_HELP_STRING([--enable-async-push], [enable async-push support @<:@default=no@:>@])],
277
+	[enable_async_push="yes"],
278
+	[enable_async_push="no"]
279
+)
280
+
274 281
 AC_ARG_WITH(
275 282
 	[special-build],
276 283
 	[AS_HELP_STRING([--with-special-build=STRING], [specify special build string])],
... ...
@@ -1155,6 +1162,14 @@ if test "${enable_plugin_auth_pam}" = "yes"; then
1155 1155
 	fi
1156 1156
 fi
1157 1157
 
1158
+if test "${enable_async_push}" = "yes"; then
1159
+	AC_CHECK_HEADERS(
1160
+		[sys/inotify.h],
1161
+		AC_DEFINE([ENABLE_ASYNC_PUSH], [1], [Enable async push]),
1162
+		AC_MSG_ERROR([inotify.h not found.])
1163
+	)
1164
+fi
1165
+
1158 1166
 CONFIGURE_DEFINES="`set | grep '^enable_.*=' ; set | grep '^with_.*='`"
1159 1167
 AC_DEFINE_UNQUOTED([CONFIGURE_DEFINES], ["`echo ${CONFIGURE_DEFINES}`"], [Configuration settings])
1160 1168
 
... ...
@@ -1384,6 +1384,9 @@ io_wait_dowork (struct context *c, const unsigned int flags)
1384 1384
 #ifdef ENABLE_MANAGEMENT
1385 1385
   static int management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */
1386 1386
 #endif
1387
+#ifdef ENABLE_ASYNC_PUSH
1388
+  static int file_shift = 8;       /* listening inotify events */
1389
+#endif
1387 1390
 
1388 1391
   /*
1389 1392
    * Decide what kind of events we want to wait for.
... ...
@@ -1478,6 +1481,11 @@ io_wait_dowork (struct context *c, const unsigned int flags)
1478 1478
     management_socket_set (management, c->c2.event_set, (void*)&management_shift, NULL);
1479 1479
 #endif
1480 1480
 
1481
+#ifdef ENABLE_ASYNC_PUSH
1482
+  /* arm inotify watcher */
1483
+  event_ctl (c->c2.event_set, c->c2.inotify_fd, EVENT_READ, (void*)&file_shift);
1484
+#endif
1485
+
1481 1486
   /*
1482 1487
    * Possible scenarios:
1483 1488
    *  (1) tcp/udp port has data available to read
... ...
@@ -62,6 +62,10 @@
62 62
 # define MTCP_MANAGEMENT ((void*)4)
63 63
 #endif
64 64
 
65
+#ifdef ENABLE_ASYNC_PUSH
66
+#define MTCP_FILE_CLOSE_WRITE ((void*)5)
67
+#endif
68
+
65 69
 #define MTCP_N           ((void*)16) /* upper bound on MTCP_x */
66 70
 
67 71
 struct ta_iow_flags
... ...
@@ -245,6 +249,12 @@ multi_tcp_wait (const struct context *c,
245 245
   if (management)
246 246
     management_socket_set (management, mtcp->es, MTCP_MANAGEMENT, &mtcp->management_persist_flags);
247 247
 #endif
248
+
249
+#ifdef ENABLE_ASYNC_PUSH
250
+  /* arm inotify watcher */
251
+  event_ctl (mtcp->es, c->c2.inotify_fd, EVENT_READ, MTCP_FILE_CLOSE_WRITE);
252
+#endif
253
+
248 254
   status = event_wait (mtcp->es, &c->c2.timeval, mtcp->esr, mtcp->maxevents);
249 255
   update_time ();
250 256
   mtcp->n_esr = 0;
... ...
@@ -636,6 +646,12 @@ multi_tcp_process_io (struct multi_context *m)
636 636
 	    {
637 637
 	      get_signal (&m->top.sig->signal_received);
638 638
 	    }
639
+#ifdef ENABLE_ASYNC_PUSH
640
+	  else if (e->arg == MTCP_FILE_CLOSE_WRITE)
641
+	    {
642
+	      multi_process_file_closed (m, MPP_PRE_SELECT | MPP_RECORD_TOUCH);
643
+	    }
644
+#endif
639 645
 	}
640 646
       if (IS_SIG (&m->top))
641 647
 	break;
... ...
@@ -684,6 +700,14 @@ tunnel_server_tcp (struct context *top)
684 684
   /* finished with initialization */
685 685
   initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto tcp-server */
686 686
 
687
+#ifdef ENABLE_ASYNC_PUSH
688
+  multi.top.c2.inotify_fd = inotify_init();
689
+  if (multi.top.c2.inotify_fd < 0)
690
+    {
691
+      msg (D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno));
692
+    }
693
+#endif
694
+
687 695
   /* per-packet event loop */
688 696
   while (true)
689 697
     {
... ...
@@ -712,6 +736,10 @@ tunnel_server_tcp (struct context *top)
712 712
       perf_pop ();
713 713
     }
714 714
 
715
+#ifdef ENABLE_ASYNC_PUSH
716
+  close(top->c2.inotify_fd);
717
+#endif
718
+
715 719
   /* shut down management interface */
716 720
   uninit_management_callback_multi (&multi);
717 721
 
... ...
@@ -38,6 +38,10 @@
38 38
 
39 39
 #include "memdbg.h"
40 40
 
41
+#ifdef HAVE_SYS_INOTIFY_H
42
+#include <sys/inotify.h>
43
+#endif
44
+
41 45
 /*
42 46
  * Get a client instance based on real address.  If
43 47
  * the instance doesn't exist, create it while
... ...
@@ -177,6 +181,10 @@ multi_process_io_udp (struct multi_context *m)
177 177
     strcat (buf, "TR/");
178 178
   else if (status & TUN_WRITE)
179 179
     strcat (buf, "TW/");
180
+#ifdef ENABLE_ASYNC_PUSH
181
+  else if (status & FILE_CLOSED)
182
+    strcat (buf, "FC/");
183
+#endif
180 184
   printf ("IO %s\n", buf);
181 185
 #endif
182 186
 
... ...
@@ -214,6 +222,13 @@ multi_process_io_udp (struct multi_context *m)
214 214
       if (!IS_SIG (&m->top))
215 215
 	multi_process_incoming_tun (m, mpp_flags);
216 216
     }
217
+#ifdef ENABLE_ASYNC_PUSH
218
+  /* INOTIFY callback */
219
+  else if (status & FILE_CLOSED)
220
+    {
221
+      multi_process_file_closed(m, mpp_flags);
222
+    }
223
+#endif
217 224
 }
218 225
 
219 226
 /*
... ...
@@ -276,6 +291,14 @@ tunnel_server_udp_single_threaded (struct context *top)
276 276
   /* finished with initialization */
277 277
   initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto udp */
278 278
 
279
+#ifdef ENABLE_ASYNC_PUSH
280
+  multi.top.c2.inotify_fd = inotify_init();
281
+  if (multi.top.c2.inotify_fd < 0)
282
+    {
283
+      msg (D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno));
284
+    }
285
+#endif
286
+
279 287
   /* per-packet event loop */
280 288
   while (true)
281 289
     {
... ...
@@ -304,6 +327,10 @@ tunnel_server_udp_single_threaded (struct context *top)
304 304
       perf_pop ();
305 305
     }
306 306
 
307
+#ifdef ENABLE_ASYNC_PUSH
308
+  close(top->c2.inotify_fd);
309
+#endif
310
+
307 311
   /* shut down management interface */
308 312
   uninit_management_callback_multi (&multi);
309 313
 
... ...
@@ -28,6 +28,11 @@
28 28
 #include "config-msvc.h"
29 29
 #endif
30 30
 
31
+#ifdef HAVE_SYS_INOTIFY_H
32
+#include <sys/inotify.h>
33
+#define INOTIFY_EVENT_BUFFER_SIZE 16384
34
+#endif
35
+
31 36
 #include "syshead.h"
32 37
 
33 38
 #if P2MP_SERVER
... ...
@@ -243,6 +248,23 @@ cid_compare_function (const void *key1, const void *key2)
243 243
 
244 244
 #endif
245 245
 
246
+#ifdef ENABLE_ASYNC_PUSH
247
+static uint32_t
248
+/*
249
+ * inotify watcher descriptors are used as hash value
250
+ */
251
+int_hash_function (const void *key, uint32_t iv)
252
+{
253
+  return (unsigned long)key;
254
+}
255
+
256
+static bool
257
+int_compare_function (const void *key1, const void *key2)
258
+{
259
+  return (unsigned long)key1 == (unsigned long)key2;
260
+}
261
+#endif
262
+
246 263
 /*
247 264
  * Main initialization function, init multi_context object.
248 265
  */
... ...
@@ -304,6 +326,17 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
304 304
 			   cid_compare_function);
305 305
 #endif
306 306
 
307
+#ifdef ENABLE_ASYNC_PUSH
308
+  /*
309
+   * Mapping between inotify watch descriptors and
310
+   * multi_instances.
311
+   */
312
+  m->inotify_watchers = hash_init (t->options.real_hash_size,
313
+                        get_random(),
314
+                        int_hash_function,
315
+                        int_compare_function);
316
+#endif
317
+
307 318
   /*
308 319
    * This is our scheduler, for time-based wakeup
309 320
    * events.
... ...
@@ -562,6 +595,14 @@ multi_close_instance (struct multi_context *m,
562 562
 	}
563 563
 #endif
564 564
 
565
+#ifdef ENABLE_ASYNC_PUSH
566
+      if (mi->inotify_watch != -1)
567
+	{
568
+	  hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch);
569
+	  mi->inotify_watch = -1;
570
+	}
571
+#endif
572
+
565 573
       m->instances[mi->context.c2.tls_multi->peer_id] = NULL;
566 574
 
567 575
       schedule_remove_entry (m->schedule, (struct schedule_entry *) mi);
... ...
@@ -642,6 +683,11 @@ multi_uninit (struct multi_context *m)
642 642
 
643 643
 	  free(m->instances);
644 644
 
645
+#ifdef ENABLE_ASYNC_PUSH
646
+	  hash_free (m->inotify_watchers);
647
+	  m->inotify_watchers = NULL;
648
+#endif
649
+
645 650
 	  schedule_free (m->schedule);
646 651
 	  mbuf_free (m->mbuf);
647 652
 	  ifconfig_pool_free (m->ifconfig_pool);
... ...
@@ -718,6 +764,11 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real)
718 718
 
719 719
   mi->context.c2.push_reply_deferred = true;
720 720
 
721
+#ifdef ENABLE_ASYNC_PUSH
722
+  mi->context.c2.push_request_received = false;
723
+  mi->inotify_watch = -1;
724
+#endif
725
+
721 726
   if (!multi_process_post (m, mi, MPP_PRE_SELECT))
722 727
     {
723 728
       msg (D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization");
... ...
@@ -923,6 +974,13 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
923 923
       status_flush (so);
924 924
       gc_free (&gc_top);
925 925
     }
926
+
927
+#ifdef ENABLE_ASYNC_PUSH
928
+  if (m->inotify_watchers)
929
+  {
930
+    msg (D_MULTI_DEBUG, "inotify watchers count: %d\n", hash_n_elements(m->inotify_watchers));
931
+  }
932
+#endif
926 933
 }
927 934
 
928 935
 /*
... ...
@@ -1877,6 +1935,14 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
1877 1877
 
1878 1878
 	  /* set context-level authentication flag */
1879 1879
 	  mi->context.c2.context_auth = CAS_SUCCEEDED;
1880
+
1881
+#ifdef ENABLE_ASYNC_PUSH
1882
+	  /* authentication complete, send push reply */
1883
+	  if (mi->context.c2.push_request_received)
1884
+	    {
1885
+	      process_incoming_push_request(&mi->context);
1886
+	    }
1887
+#endif
1880 1888
 	}
1881 1889
       else
1882 1890
 	{
... ...
@@ -1906,6 +1972,58 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
1906 1906
   mi->context.c2.push_reply_deferred = false;
1907 1907
 }
1908 1908
 
1909
+#ifdef ENABLE_ASYNC_PUSH
1910
+/*
1911
+ * Called when inotify event is fired, which happens when acf file is closed or deleted.
1912
+ * Continues authentication and sends push_reply.
1913
+ */
1914
+void
1915
+multi_process_file_closed (struct multi_context *m, const unsigned int mpp_flags)
1916
+{
1917
+  char buffer[INOTIFY_EVENT_BUFFER_SIZE];
1918
+  size_t buffer_i = 0;
1919
+  int r = read (m->top.c2.inotify_fd, buffer, INOTIFY_EVENT_BUFFER_SIZE);
1920
+
1921
+  while (buffer_i < r)
1922
+    {
1923
+      /* parse inotify events */
1924
+      struct inotify_event *pevent = (struct inotify_event *) &buffer[buffer_i];
1925
+      size_t event_size = sizeof (struct inotify_event) + pevent->len;
1926
+      buffer_i += event_size;
1927
+
1928
+      msg(D_MULTI_DEBUG, "MULTI: modified fd %d, mask %d", pevent->wd, pevent->mask);
1929
+
1930
+      struct multi_instance* mi = hash_lookup(m->inotify_watchers, (void*) (unsigned long) pevent->wd);
1931
+
1932
+      if (pevent->mask & IN_CLOSE_WRITE)
1933
+	{
1934
+	  if (mi)
1935
+	    {
1936
+	      /* continue authentication and send push_reply */
1937
+	      multi_process_post (m, mi, mpp_flags);
1938
+	    }
1939
+	  else
1940
+	    {
1941
+	      msg(D_MULTI_ERRORS, "MULTI: multi_instance not found!");
1942
+	    }
1943
+	}
1944
+      else if (pevent->mask & IN_IGNORED)
1945
+	{
1946
+	  /* this event is _always_ fired when watch is removed or file is deleted */
1947
+	  if (mi)
1948
+	    {
1949
+	      hash_remove(m->inotify_watchers, (void*) (unsigned long) pevent->wd);
1950
+	      mi->inotify_watch = -1;
1951
+	    }
1952
+	}
1953
+      else
1954
+	{
1955
+	  msg(D_MULTI_ERRORS, "MULTI: unknown mask %d", pevent->mask);
1956
+	}
1957
+    }
1958
+}
1959
+#endif
1960
+
1909 1961
 /*
1910 1962
  * Add a mbuf buffer to a particular
1911 1963
  * instance.
... ...
@@ -2066,19 +2184,50 @@ multi_process_post (struct multi_context *m, struct multi_instance *mi, const un
2066 2066
 
2067 2067
   if (!IS_SIG (&mi->context) && ((flags & MPP_PRE_SELECT) || ((flags & MPP_CONDITIONAL_PRE_SELECT) && !ANY_OUT (&mi->context))))
2068 2068
     {
2069
+#if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH)
2070
+      bool was_authenticated = false;
2071
+      struct key_state *ks = NULL;
2072
+      if (mi->context.c2.tls_multi)
2073
+        {
2074
+          ks = &mi->context.c2.tls_multi->session[TM_ACTIVE].key[KS_PRIMARY];
2075
+          was_authenticated = ks->authenticated;
2076
+        }
2077
+#endif
2078
+
2069 2079
       /* figure timeouts and fetch possible outgoing
2070 2080
 	 to_link packets (such as ping or TLS control) */
2071 2081
       pre_select (&mi->context);
2072 2082
 
2073
-      if (!IS_SIG (&mi->context))
2083
+#if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH)
2084
+      if (ks && ks->auth_control_file && ks->auth_deferred && !was_authenticated)
2074 2085
 	{
2075
-	  /* tell scheduler to wake us up at some point in the future */
2076
-	  multi_schedule_context_wakeup(m, mi);
2086
+	  /* watch acf file */
2087
+	  long watch_descriptor = inotify_add_watch(m->top.c2.inotify_fd, ks->auth_control_file, IN_CLOSE_WRITE | IN_ONESHOT);
2088
+	  if (watch_descriptor >= 0)
2089
+	    {
2090
+	      if (mi->inotify_watch != -1)
2091
+		{
2092
+		  hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch);
2093
+		}
2094
+	      hash_add (m->inotify_watchers, (const uintptr_t*)watch_descriptor, mi, true);
2095
+	      mi->inotify_watch = watch_descriptor;
2096
+	    }
2097
+	  else
2098
+	    {
2099
+	      msg(M_NONFATAL, "MULTI: inotify_add_watch error: %s", strerror(errno));
2100
+	    }
2101
+	}
2102
+#endif
2077 2103
 
2104
+      if (!IS_SIG (&mi->context))
2105
+	{
2078 2106
 	  /* connection is "established" when SSL/TLS key negotiation succeeds
2079 2107
 	     and (if specified) auth user/pass succeeds */
2080 2108
 	  if (!mi->connection_established_flag && CONNECTION_ESTABLISHED (&mi->context))
2081 2109
 	    multi_connection_established (m, mi);
2110
+
2111
+	  /* tell scheduler to wake us up at some point in the future */
2112
+	  multi_schedule_context_wakeup(m, mi);
2082 2113
 	}
2083 2114
     }
2084 2115
 
... ...
@@ -105,6 +105,10 @@ struct multi_instance {
105 105
 
106 106
   struct context context;       /**< The context structure storing state
107 107
                                  *   for this VPN tunnel. */
108
+
109
+#ifdef ENABLE_ASYNC_PUSH
110
+  int inotify_watch; /* watch descriptor for acf */
111
+#endif
108 112
 };
109 113
 
110 114
 
... ...
@@ -172,6 +176,11 @@ struct multi_context {
172 172
    * Timer object for stale route check
173 173
    */
174 174
   struct event_timeout stale_routes_check_et;
175
+
176
+#ifdef ENABLE_ASYNC_PUSH
177
+  /* mapping between inotify watch descriptors and multi_instances */
178
+  struct hash *inotify_watchers;
179
+#endif
175 180
 };
176 181
 
177 182
 /*
... ...
@@ -327,6 +336,18 @@ void multi_close_instance_on_signal (struct multi_context *m, struct multi_insta
327 327
 void init_management_callback_multi (struct multi_context *m);
328 328
 void uninit_management_callback_multi (struct multi_context *m);
329 329
 
330
+
331
+#ifdef ENABLE_ASYNC_PUSH
332
+/**
333
+ * Called when inotify event is fired, which happens when acf file is closed or deleted.
334
+ * Continues authentication and sends push_repl
335
+ *
336
+ * @param m multi_context
337
+ * @param mpp_flags
338
+ */
339
+void multi_process_file_closed (struct multi_context *m, const unsigned int mpp_flags);
340
+#endif
341
+
330 342
 /*
331 343
  * Return true if our output queue is not full
332 344
  */
... ...
@@ -241,6 +241,9 @@ struct context_2
241 241
 #  define MANAGEMENT_READ  (1<<6)
242 242
 #  define MANAGEMENT_WRITE (1<<7)
243 243
 # endif
244
+#ifdef ENABLE_ASYNC_PUSH
245
+# define FILE_CLOSED       (1<<8)
246
+#endif
244 247
 
245 248
   unsigned int event_set_status;
246 249
 
... ...
@@ -436,6 +439,9 @@ struct context_2
436 436
 #if P2MP_SERVER
437 437
   /* --ifconfig endpoints to be pushed to client */
438 438
   bool push_reply_deferred;
439
+#ifdef ENABLE_ASYNC_PUSH
440
+  bool push_request_received;
441
+#endif
439 442
   bool push_ifconfig_defined;
440 443
   time_t sent_push_reply_expiry;
441 444
   in_addr_t push_ifconfig_local;
... ...
@@ -479,6 +485,10 @@ struct context_2
479 479
 #ifdef MANAGEMENT_DEF_AUTH
480 480
   struct man_def_auth_context mda_context;
481 481
 #endif
482
+
483
+#ifdef ENABLE_ASYNC_PUSH
484
+  int inotify_fd; /* descriptor for monitoring file changes */
485
+#endif
482 486
 };
483 487
 
484 488
 
... ...
@@ -411,6 +411,46 @@ push_reset (struct options *o)
411 411
 #endif
412 412
 
413 413
 int
414
+process_incoming_push_request (struct context *c)
415
+{
416
+  int ret = PUSH_MSG_ERROR;
417
+
418
+#ifdef ENABLE_ASYNC_PUSH
419
+  c->c2.push_request_received = true;
420
+#endif
421
+  if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED)
422
+    {
423
+      const char *client_reason = tls_client_reason (c->c2.tls_multi);
424
+      send_auth_failed (c, client_reason);
425
+      ret = PUSH_MSG_AUTH_FAILURE;
426
+    }
427
+  else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED)
428
+    {
429
+      time_t now;
430
+
431
+      openvpn_time (&now);
432
+      if (c->c2.sent_push_reply_expiry > now)
433
+	{
434
+	  ret = PUSH_MSG_ALREADY_REPLIED;
435
+	}
436
+      else
437
+	{
438
+	  if (send_push_reply (c))
439
+	    {
440
+	      ret = PUSH_MSG_REQUEST;
441
+	      c->c2.sent_push_reply_expiry = now + 30;
442
+	    }
443
+	}
444
+    }
445
+  else
446
+    {
447
+      ret = PUSH_MSG_REQUEST_DEFERRED;
448
+    }
449
+
450
+  return ret;
451
+}
452
+
453
+int
414 454
 process_incoming_push_msg (struct context *c,
415 455
 			   const struct buffer *buffer,
416 456
 			   bool honor_received_options,
... ...
@@ -423,34 +463,7 @@ process_incoming_push_msg (struct context *c,
423 423
 #if P2MP_SERVER
424 424
   if (buf_string_compare_advance (&buf, "PUSH_REQUEST"))
425 425
     {
426
-      if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED)
427
-	{
428
-	  const char *client_reason = tls_client_reason (c->c2.tls_multi);
429
-	  send_auth_failed (c, client_reason);
430
-	  ret = PUSH_MSG_AUTH_FAILURE;
431
-	}
432
-      else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED)
433
-	{
434
-	  time_t now;
435
-
436
-	  openvpn_time(&now);
437
-	  if (c->c2.sent_push_reply_expiry > now)
438
-	    {
439
-	      ret = PUSH_MSG_ALREADY_REPLIED;
440
-	    }
441
-	  else
442
-	    {
443
-	      if (send_push_reply (c))
444
-		{
445
-		  ret = PUSH_MSG_REQUEST;
446
-		  c->c2.sent_push_reply_expiry = now + 30;
447
-		}
448
-	    }
449
-	}
450
-      else
451
-	{
452
-	  ret = PUSH_MSG_REQUEST_DEFERRED;
453
-	}
426
+      ret = process_incoming_push_request(c);
454 427
     }
455 428
   else
456 429
 #endif
... ...
@@ -40,6 +40,8 @@
40 40
 void incoming_push_message (struct context *c,
41 41
 			    const struct buffer *buffer);
42 42
 
43
+int process_incoming_push_request (struct context *c);
44
+
43 45
 int process_incoming_push_msg (struct context *c,
44 46
 			       const struct buffer *buffer,
45 47
 			       bool honor_received_options,