Add cancellable openconnect_SSL_write(), use it from openconnect_SSL_printf()
authorDavid Woodhouse <David.Woodhouse@intel.com>
Sat, 12 May 2012 19:34:56 +0000 (12:34 -0700)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Sat, 12 May 2012 19:34:56 +0000 (12:34 -0700)
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
cstp.c
openconnect-internal.h
ssl.c

diff --git a/cstp.c b/cstp.c
index dc826b8..0408dc0 100644 (file)
--- a/cstp.c
+++ b/cstp.c
@@ -111,9 +111,6 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
        }
 
  retry:
-       /* We don't cope with nonblocking mode... yet */
-       fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) & ~O_NONBLOCK);
-
        openconnect_SSL_printf(vpninfo, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
        openconnect_SSL_printf(vpninfo, "Host: %s\r\n", vpninfo->hostname);
        openconnect_SSL_printf(vpninfo, "User-Agent: %s\r\n", vpninfo->useragent);
@@ -131,6 +128,7 @@ 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) {
                vpn_progress(vpninfo, PRG_ERR,
                             _("Error fetching HTTPS response\n"));
index 2a68b96..c86f474 100644 (file)
@@ -279,6 +279,7 @@ int cstp_reconnect(struct openconnect_info *vpninfo);
 int  __attribute__ ((format (printf, 2, 3)))
     openconnect_SSL_printf(struct openconnect_info *vpninfo, const char *fmt, ...);
 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len);
+int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len);
 int openconnect_open_https(struct openconnect_info *vpninfo);
 void openconnect_close_https(struct openconnect_info *vpninfo);
 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo, X509 *cert,
diff --git a/ssl.c b/ssl.c
index 9ee182f..677d071 100644 (file)
--- a/ssl.c
+++ b/ssl.c
 /* Helper functions for reading/writing lines over SSL.
    We could use cURL for the HTTP stuff, but it's overkill */
 
+int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len)
+{
+       size_t orig_len = len;
+
+       while (len) {
+               int done = SSL_write(vpninfo->https_ssl, buf, len);
+
+               if (done > 0)
+                       len -= done;
+               else {
+                       int err = SSL_get_error(vpninfo->https_ssl, done);
+                       fd_set wr_set, rd_set;
+                       int maxfd = vpninfo->ssl_fd;
+
+                       FD_ZERO(&wr_set);
+                       FD_ZERO(&rd_set);
+                       
+                       if (err == SSL_ERROR_WANT_READ)
+                               FD_SET(vpninfo->ssl_fd, &rd_set);
+                       else if (err == SSL_ERROR_WANT_WRITE)
+                               FD_SET(vpninfo->ssl_fd, &wr_set);
+                       else {
+                               vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket"));
+                               report_ssl_errors(vpninfo);
+                               return -EIO;
+                       }
+                       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 write cancelled\n"));
+                               return -EINTR;
+                       }
+               }
+       }
+       return orig_len;
+}
+
 int  __attribute__ ((format (printf, 2, 3)))
     openconnect_SSL_printf(struct openconnect_info *vpninfo, const char *fmt, ...)
 {
@@ -71,7 +113,7 @@ int  __attribute__ ((format (printf, 2, 3)))
        va_start(args, fmt);
        vsnprintf(buf, 1023, fmt, args);
        va_end(args);
-       return SSL_write(vpninfo->https_ssl, buf, strlen(buf));
+       return openconnect_SSL_write(vpninfo, buf, strlen(buf));
 
 }