char *res_buf = NULL;
int ret;
- /* XX: handle clean PPP termination?
- ppp_bye(vpninfo); */
-
/* We need to close and reopen the HTTPS connection (to kill
* the f5 tunnel) and submit a new HTTPS request to logout.
*/
poll_cmd_fd(vpninfo, 0);
if (vpninfo->got_cancel_cmd) {
- if (vpninfo->cancel_type == OC_CMD_CANCEL) {
+ if (vpninfo->delay_close > 0) {
+ vpn_progress(vpninfo, PRG_DEBUG, _("Delaying cancel.\n"));
+ /* XX: don't let this spin forever */
+ if (--vpninfo->delay_close > 0)
+ did_work++;
+ } 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) {
+ vpn_progress(vpninfo, PRG_DEBUG, _("Delaying pause.\n"));
+ /* XX: don't let this spin forever */
+ if (--vpninfo->delay_close > 0)
+ did_work++;
+ } 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)
int ssl_fd;
int dtls_fd;
int delay_tunnel; /* Delay tunnel setup */
+ int delay_close; /* Delay close of mainloop */
int dtls_tos_current;
int dtls_pass_tos;
vpninfo->quit_reason);
}
ppp->ppp_state = PPPS_TERMINATE;
+ vpninfo->delay_close = 0;
break;
case ECHOREP:
break;
ppp->ppp_state = PPPS_NETWORK;
- vpninfo->delay_tunnel = 0;
+ vpninfo->delay_tunnel = 0; /* tunnel can start now */
+ vpninfo->delay_close = 2; /* need two mainloop iterations on close (send TERMREQ; receive TERMACK) */
/* fall through */
case PPPS_NETWORK:
- break;
+ if (vpninfo->got_pause_cmd || vpninfo->got_cancel_cmd)
+ ppp->ppp_state = PPPS_TERMINATE;
+ else
+ break;
+ /* fall through */
+
case PPPS_TERMINATE:
- if (!vpninfo->quit_reason)
- vpninfo->quit_reason = "Unknown";
- return -EPIPE;
+ /* XX: If server terminated, we already ACK'ed it */
+ if (ppp->lcp.state & NCP_TERM_REQ_RECEIVED)
+ return -EPIPE;
+ else if (!(ppp->lcp.state & NCP_TERM_ACK_RECEIVED)) {
+ /* We need to send a TERMREQ and wait for a TERMACK, but not keep retrying if it
+ * fails. We attempt to send TERMREQ once, then wait for 3 seconds, and
+ * send once more TERMREQ if that fails. */
+ if (!(ppp->lcp.state & NCP_TERM_REQ_SENT)) {
+ ppp->lcp.state |= NCP_TERM_REQ_SENT;
+ ppp->lcp.last_req = now;
+ (void) queue_config_packet(vpninfo, PPP_LCP, ++ppp->lcp.id, TERMREQ, 0, NULL);
+ }
+ if (!ka_check_deadline(timeout, now, ppp->lcp.last_req + 3))
+ vpninfo->delay_close = 1;
+ else
+ (void) queue_config_packet(vpninfo, PPP_LCP, ++ppp->lcp.id, TERMREQ, 0, NULL);
+ }
+ break;
case PPPS_AUTHENTICATE: /* XX: should never */
default:
vpninfo->quit_reason = "Unexpected state";