Handle write stalls
authorDavid Woodhouse <David.Woodhouse@intel.com>
Thu, 2 Oct 2008 10:58:43 +0000 (11:58 +0100)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Thu, 2 Oct 2008 10:58:43 +0000 (11:58 +0100)
anyconnect.h
mainloop.c
ssl.c

index 696101e..da76987 100644 (file)
@@ -160,6 +160,7 @@ int vpn_mainloop(struct anyconnect_info *vpninfo);
 int queue_new_packet(struct pkt **q, int type, void *buf, int len);
 void queue_packet(struct pkt **q, struct pkt *new);
 int keepalive_action(struct keepalive_info *ka, int *timeout);
+int ka_stalled_dpd_time(struct keepalive_info *ka, int *timeout);
 
 /* xml.c */
 int config_lookup_host(struct anyconnect_info *vpninfo, const char *host);
index c01fba9..ff9e052 100644 (file)
@@ -134,6 +134,31 @@ int vpn_mainloop(struct anyconnect_info *vpninfo)
        return 0;
 }
 
+/* Called when the socket is unwritable, to get the deadline for DPD.
+   Returns 1 if DPD deadline has already arrived. */
+int ka_stalled_dpd_time(struct keepalive_info *ka, int *timeout)
+{
+       time_t now, due;
+
+       if (!ka->dpd) {
+               printf("no dpd\n");
+               return 0;
+       }
+
+       time(&now);
+       due = ka->last_rx + (2 * ka->dpd);
+
+       if (now > due)
+               return 1;
+
+       printf("ka_stalled in %d seconds\n", (int)(due - now));
+       if (*timeout > (due - now) * 1000)
+               *timeout = (due - now) * 1000;
+
+       return 0;
+}
+
+
 int keepalive_action(struct keepalive_info *ka, int *timeout)
 {
        time_t now = time(NULL);
diff --git a/ssl.c b/ssl.c
index 9258828..b31ff5d 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -612,15 +612,23 @@ int ssl_mainloop(struct anyconnect_info *vpninfo, int *timeout)
        if (vpninfo->current_ssl_pkt) {
        handle_outgoing:
                vpninfo->ssl_times.last_tx = time(NULL);
+               vpninfo->pfds[vpninfo->ssl_pfd].events &= ~POLLOUT;
                ret = SSL_write(vpninfo->https_ssl,
                                vpninfo->current_ssl_pkt->hdr,
                                vpninfo->current_ssl_pkt->len + 8);
                if (ret <= 0) {
                        ret = SSL_get_error(vpninfo->https_ssl, ret);
                        switch (ret) {
-                       case SSL_ERROR_WANT_READ:
                        case SSL_ERROR_WANT_WRITE:
-                               /* FIXME: Set pollfd flags accordingly */
+                               /* Waiting for the socket to become writable -- it's
+                                  probably stalled, and/or the buffers are full */
+                               printf("SSL want write\n");
+                               vpninfo->pfds[vpninfo->ssl_pfd].events |= POLLOUT;
+                       case SSL_ERROR_WANT_READ:
+                               if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout)) {
+                                       vpninfo->quit_reason = "SSL DPD detected dead peer";
+                                       return 1;
+                               }
                                return work_done;
                        default:
                                fprintf(stderr, "SSL_write failed: %d", ret);
@@ -655,7 +663,6 @@ int ssl_mainloop(struct anyconnect_info *vpninfo, int *timeout)
                work_done = 1;
                break;
 
-
        case KA_DPD_DEAD:
                fprintf(stderr, "CSTP Dead Peer Detection detected dead peer!\n");
                vpninfo->quit_reason = "SSL DPD detected dead peer";