Handle cancellation in openconnect_SSL_gets()
authorDavid Woodhouse <David.Woodhouse@intel.com>
Sat, 12 May 2012 20:12:13 +0000 (13:12 -0700)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Sat, 12 May 2012 20:12:13 +0000 (13:12 -0700)
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
cstp.c
ssl.c

diff --git a/cstp.c b/cstp.c
index 0408dc0..98c5e55 100644 (file)
--- a/cstp.c
+++ b/cstp.c
@@ -128,8 +128,9 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
        openconnect_SSL_printf(vpninfo, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
                               vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
 
-       fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) & ~O_NONBLOCK);
-       if (openconnect_SSL_gets(vpninfo, buf, 65536) < 0) {
+       if ((i = openconnect_SSL_gets(vpninfo, buf, 65536) < 0)) {
+               if (i == -EINTR)
+                       return i;
                vpn_progress(vpninfo, PRG_ERR,
                             _("Error fetching HTTPS response\n"));
                if (!retried) {
@@ -177,7 +178,12 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
 
        while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
                struct vpn_option *new_option;
-               char *colon = strchr(buf, ':');
+               char *colon;
+
+               if (i < 0)
+                       return i;
+
+               colon = strchr(buf, ':');
                if (!colon)
                        continue;
 
@@ -356,7 +362,6 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
        BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
        BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
 
-       fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
        if (vpninfo->select_nfds <= vpninfo->ssl_fd)
                vpninfo->select_nfds = vpninfo->ssl_fd + 1;
 
diff --git a/ssl.c b/ssl.c
index 677d071..58c233f 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -138,25 +138,55 @@ int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len
        if (len < 2)
                return -EINVAL;
 
-       while ( (ret = SSL_read(vpninfo->https_ssl, buf + i, 1)) == 1) {
-               if (buf[i] == '\n') {
-                       buf[i] = 0;
-                       if (i && buf[i-1] == '\r') {
-                               buf[i-1] = 0;
-                               i--;
+       while (1) {
+               ret = SSL_read(vpninfo->https_ssl, buf + i, 1);
+               if (ret == 1) {
+                       if (buf[i] == '\n') {
+                               buf[i] = 0;
+                               if (i && buf[i-1] == '\r') {
+                                       buf[i-1] = 0;
+                                       i--;
+                               }
+                               return i;
                        }
-                       return i;
-               }
-               i++;
+                       i++;
 
-               if (i >= len - 1) {
-                       buf[i] = 0;
-                       return i;
+                       if (i >= len - 1) {
+                               buf[i] = 0;
+                               return i;
+                       }
+               } else {
+                       fd_set rd_set, wr_set;
+                       int maxfd = vpninfo->ssl_fd;
+                       
+                       FD_ZERO(&rd_set);
+                       FD_ZERO(&wr_set);
+                       
+                       ret = SSL_get_error(vpninfo->https_ssl, ret);
+                       if (ret == SSL_ERROR_WANT_READ)
+                               FD_SET(vpninfo->ssl_fd, &rd_set);
+                       else if (ret == SSL_ERROR_WANT_WRITE)
+                               FD_SET(vpninfo->ssl_fd, &wr_set);
+                       else {
+                               vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket\n"));
+                               report_ssl_errors(vpninfo);
+                               ret = -EIO;
+                               break;
+                       }
+                       if (vpninfo->cancel_fd != -1) {
+                               FD_SET(vpninfo->cancel_fd, &rd_set);
+                               if (vpninfo->cancel_fd > vpninfo->ssl_fd)
+                                       maxfd = vpninfo->cancel_fd;
+                       }
+                       select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
+                       if (vpninfo->cancel_fd != -1 &&
+                           FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
+                               vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
+                               ret = -EINTR;
+                               break;
+                       }
                }
        }
-       if (ret == 0) {
-               ret = -SSL_get_error(vpninfo->https_ssl, ret);
-       }
        buf[i] = 0;
        return i ?: ret;
 }