From 823e562964636fc5959d720a5fe2ca4d52e69f69 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Sat, 16 May 2020 17:06:10 -0700 Subject: [PATCH] add delay_tunnel_reason and delay_close - If delay_tunnel_reason is set, mainloop will defer tunnel device creation for one more iteration. - If delay_close is set, mainloop will continue to iterate even if cancel_cmd or pause_cmd is set. - If delay_close==1, we don't set did_work; if >=1 we do. - This allows a protocol to set delay_close=2 for the case where its mainloop needs an immediate callback to send a termination request, and delay_close=1 for the case where a protocol needs to wait for a termination acknowledgment. openconnect_mainloop() decrements delay_close, and set delay_tunnel_reason to NULL, on each iteration. A protocol mainloop must thus affirmatively extend a delay in order for it to continue. Signed-off-by: Daniel Lenski --- dtls.c | 1 - mainloop.c | 70 +++++++++++++++++++++++++++++------------- openconnect-internal.h | 2 ++ 3 files changed, 50 insertions(+), 23 deletions(-) diff --git a/dtls.c b/dtls.c index ca68fede..5025f6b0 100644 --- a/dtls.c +++ b/dtls.c @@ -712,4 +712,3 @@ void dtls_detect_mtu(struct openconnect_info *vpninfo) skip_mtu: free(buf); } - diff --git a/mainloop.c b/mainloop.c index e58e87a0..e2afe443 100644 --- a/mainloop.c +++ b/mainloop.c @@ -204,7 +204,7 @@ int openconnect_mainloop(struct openconnect_info *vpninfo, else timeout = 1000; - if (vpninfo->dtls_state > DTLS_DISABLED) { + if (!tun_is_up(vpninfo)) { /* Postpone tun device creation after DTLS is connected so * we have a better knowledge of the link MTU. We also * force the creation if DTLS enters sleeping mode - i.e., @@ -212,21 +212,26 @@ int openconnect_mainloop(struct openconnect_info *vpninfo, if (!tun_is_up(vpninfo) && (vpninfo->dtls_state == DTLS_CONNECTED || vpninfo->dtls_state == DTLS_SLEEPING)) { ret = setup_tun_device(vpninfo); - if (ret) { + if (ret) + break; + } else if (vpninfo->delay_tunnel_reason) { + vpn_progress(vpninfo, PRG_INFO, _("Delaying tunnel for %d ms with reason: %s\n"), + timeout, vpninfo->delay_tunnel_reason); + /* XX: don't let this spin forever */ + vpninfo->delay_tunnel_reason = NULL; + } else { + /* No DTLS, or DTLS failed; setup TUN device unconditionally */ + ret = setup_tun_device(vpninfo); + if (ret) break; - } } + } + if (vpninfo->dtls_state > DTLS_DISABLED) { ret = vpninfo->proto->udp_mainloop(vpninfo, &timeout, udp_r); if (vpninfo->quit_reason) break; did_work += ret; - - } else if (!tun_is_up(vpninfo)) { - /* No DTLS - setup TUN device unconditionally */ - ret = setup_tun_device(vpninfo); - if (ret) - break; } ret = vpninfo->proto->tcp_mainloop(vpninfo, &timeout, tcp_r); @@ -242,28 +247,49 @@ int openconnect_mainloop(struct openconnect_info *vpninfo, poll_cmd_fd(vpninfo, 0); if (vpninfo->got_cancel_cmd) { - if (vpninfo->cancel_type == OC_CMD_CANCEL) { + if (vpninfo->delay_close > 0) { + if (vpninfo->delay_close > 1) { + vpn_progress(vpninfo, PRG_DEBUG, _("Delaying cancel in order to send again.\n")); + did_work++; + } else + vpn_progress(vpninfo, PRG_DEBUG, _("Delaying cancel for %d ms in order to receive again).\n"), timeout); + /* XX: don't let this spin forever */ + --vpninfo->delay_close; + } else if (vpninfo->cancel_type == OC_CMD_CANCEL) { vpninfo->quit_reason = "Aborted by caller"; + vpninfo->got_cancel_cmd = 0; ret = -EINTR; + break; } else { + vpninfo->got_cancel_cmd = 0; ret = -ECONNABORTED; + break; } - vpninfo->got_cancel_cmd = 0; - break; } if (vpninfo->got_pause_cmd) { - /* close all connections and wait for the user to call - openconnect_mainloop() again */ - openconnect_close_https(vpninfo, 0); - if (vpninfo->dtls_state > DTLS_DISABLED) { - vpninfo->proto->udp_close(vpninfo); - vpninfo->new_dtls_started = 0; - } + if (vpninfo->delay_close > 0) { + /* XX: don't let this spin forever */ + if (vpninfo->delay_close > 1) { + vpn_progress(vpninfo, PRG_DEBUG, _("Delaying cancel (need to send again).\n")); + did_work++; + } else + vpn_progress(vpninfo, PRG_DEBUG, _("Delaying cancel (need to receive again).\n")); + /* XX: don't let this spin forever */ + --vpninfo->delay_close; + } else { + /* close all connections and wait for the user to call + openconnect_mainloop() again */ + openconnect_close_https(vpninfo, 0); + if (vpninfo->dtls_state > DTLS_DISABLED) { + vpninfo->proto->udp_close(vpninfo); + vpninfo->new_dtls_started = 0; + } - vpninfo->got_pause_cmd = 0; - vpn_progress(vpninfo, PRG_INFO, _("Caller paused the connection\n")); - return 0; + vpninfo->got_pause_cmd = 0; + vpn_progress(vpninfo, PRG_INFO, _("Caller paused the connection\n")); + return 0; + } } if (did_work) diff --git a/openconnect-internal.h b/openconnect-internal.h index 92edf763..fc50de42 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -667,6 +667,8 @@ struct openconnect_info { char *version_string; const char *quit_reason; + const char *delay_tunnel_reason; /* Delay tunnel setup */ + int delay_close; /* Delay close of mainloop (2 for immediate callback, 1 for wait) */ int verbose; void *cbdata; -- 2.50.1