[ovs-dev] [PATCH v3 3/3] stream-ssl: Add support for windows platform.

Gurucharan Shetty shettyg at nicira.com
Mon Feb 10 23:25:38 UTC 2014


This commit creates events and through poll_fd_wait_event()
associates them with socket file descriptors to get woken up
from poll_block().

Some other changes:

* Windows does not have sys/fcntl.h but has a fcntl.h
On Linux, there is fctnl.h too.

* include <openssl/applink.c> to handle different C-Runtime linking
of OVS and openssl libraries as suggested at
https://www.openssl.org/support/faq.html#PROG2

The above include will not be needed if we compile Open vSwitch with
/MD compiler option.

* SHUT_RDWR is equivalent to SD_BOTH on Windows.

Signed-off-by: Gurucharan Shetty <gshetty at nicira.com>
---
 lib/socket-util.h |   11 +++++++
 lib/stream-ssl.c  |   86 +++++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 82 insertions(+), 15 deletions(-)

diff --git a/lib/socket-util.h b/lib/socket-util.h
index d2b9f38..977714a 100644
--- a/lib/socket-util.h
+++ b/lib/socket-util.h
@@ -81,4 +81,15 @@ int af_inet_ifreq_ioctl(const char *name, struct ifreq *,
 
 const char *sock_strerror(int error);
 
+#ifdef _WIN32
+/* Windows defines the 'optval' argument as char * instead of void *. */
+#define setsockopt(sock, level, optname, optval, optlen) \
+    rpl_setsockopt(sock, level, optname, optval, optlen)
+static inline int rpl_setsockopt(int sock, int level, int optname,
+                                 const void *optval, socklen_t optlen)
+{
+    return (setsockopt)(sock, level, optname, optval, optlen);
+}
+#endif
+
 #endif /* socket-util.h */
diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c
index 2ed5282..8af4e63 100644
--- a/lib/stream-ssl.c
+++ b/lib/stream-ssl.c
@@ -29,7 +29,7 @@
 #include <openssl/ssl.h>
 #include <openssl/x509v3.h>
 #include <poll.h>
-#include <sys/fcntl.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include "coverage.h"
@@ -47,6 +47,13 @@
 #include "timeval.h"
 #include "vlog.h"
 
+#ifdef _WIN32
+#include <openssl/applink.c>
+#define SHUT_RDWR SD_BOTH
+#else
+#define closesocket close
+#endif
+
 VLOG_DEFINE_THIS_MODULE(stream_ssl);
 
 /* Active SSL. */
@@ -67,6 +74,7 @@ struct ssl_stream
     enum ssl_state state;
     enum session_type type;
     int fd;
+    HANDLE wevent;
     SSL *ssl;
     struct ofpbuf *txbuf;
     unsigned int session_nr;
@@ -183,6 +191,8 @@ static void stream_ssl_set_ca_cert_file__(const char *file_name,
 static void ssl_protocol_cb(int write_p, int version, int content_type,
                             const void *, size_t, SSL *, void *sslv_);
 static bool update_ssl_config(struct ssl_config_file *, const char *file_name);
+static int sock_errno(void);
+static void clear_handle(int fd, HANDLE wevent);
 
 static short int
 want_to_poll_events(int want)
@@ -245,8 +255,9 @@ new_ssl_stream(const char *name, int fd, enum session_type type,
     /* Disable Nagle. */
     retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on);
     if (retval) {
-        VLOG_ERR("%s: setsockopt(TCP_NODELAY): %s", name, ovs_strerror(errno));
-        retval = errno;
+        retval = sock_errno();
+        VLOG_ERR("%s: setsockopt(TCP_NODELAY): %s", name,
+                 sock_strerror(retval));
         goto error;
     }
 
@@ -272,6 +283,9 @@ new_ssl_stream(const char *name, int fd, enum session_type type,
     sslv->state = state;
     sslv->type = type;
     sslv->fd = fd;
+#ifdef _WIN32
+    sslv->wevent = CreateEvent(NULL, FALSE, FALSE, NULL);
+#endif
     sslv->ssl = ssl;
     sslv->txbuf = NULL;
     sslv->rx_want = sslv->tx_want = SSL_NOTHING;
@@ -290,7 +304,7 @@ error:
     if (ssl) {
         SSL_free(ssl);
     }
-    close(fd);
+    closesocket(fd);
     return retval;
 }
 
@@ -500,7 +514,8 @@ ssl_close(struct stream *stream)
     ERR_clear_error();
 
     SSL_free(sslv->ssl);
-    close(sslv->fd);
+    clear_handle(sslv->fd, sslv->wevent);
+    closesocket(sslv->fd);
     free(sslv);
 }
 
@@ -691,7 +706,8 @@ ssl_run_wait(struct stream *stream)
     struct ssl_stream *sslv = ssl_stream_cast(stream);
 
     if (sslv->tx_want != SSL_NOTHING) {
-        poll_fd_wait(sslv->fd, want_to_poll_events(sslv->tx_want));
+        poll_fd_wait_event(sslv->fd, sslv->wevent,
+                           want_to_poll_events(sslv->tx_want));
     }
 }
 
@@ -707,14 +723,14 @@ ssl_wait(struct stream *stream, enum stream_wait_type wait)
         } else {
             switch (sslv->state) {
             case STATE_TCP_CONNECTING:
-                poll_fd_wait(sslv->fd, POLLOUT);
+                poll_fd_wait_event(sslv->fd, sslv->wevent, POLLOUT);
                 break;
 
             case STATE_SSL_CONNECTING:
                 /* ssl_connect() called SSL_accept() or SSL_connect(), which
                  * set up the status that we test here. */
-                poll_fd_wait(sslv->fd,
-                             want_to_poll_events(SSL_want(sslv->ssl)));
+                poll_fd_wait_event(sslv->fd, sslv->wevent,
+                                   want_to_poll_events(SSL_want(sslv->ssl)));
                 break;
 
             default:
@@ -725,7 +741,8 @@ ssl_wait(struct stream *stream, enum stream_wait_type wait)
 
     case STREAM_RECV:
         if (sslv->rx_want != SSL_NOTHING) {
-            poll_fd_wait(sslv->fd, want_to_poll_events(sslv->rx_want));
+            poll_fd_wait_event(sslv->fd, sslv->wevent,
+                               want_to_poll_events(sslv->rx_want));
         } else {
             poll_immediate_wake();
         }
@@ -765,6 +782,7 @@ struct pssl_pstream
 {
     struct pstream pstream;
     int fd;
+    HANDLE wevent;
 };
 
 const struct pstream_class pssl_pstream_class;
@@ -802,6 +820,9 @@ pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
     pstream_init(&pssl->pstream, &pssl_pstream_class, bound_name);
     pstream_set_bound_port(&pssl->pstream, sin.sin_port);
     pssl->fd = fd;
+#ifdef _WIN32
+    pssl->wevent = CreateEvent(NULL, FALSE, FALSE, NULL);
+#endif
     *pstreamp = &pssl->pstream;
     return 0;
 }
@@ -810,7 +831,8 @@ static void
 pssl_close(struct pstream *pstream)
 {
     struct pssl_pstream *pssl = pssl_pstream_cast(pstream);
-    close(pssl->fd);
+    clear_handle(pssl->fd, pssl->wevent);
+    closesocket(pssl->fd);
     free(pssl);
 }
 
@@ -826,16 +848,21 @@ pssl_accept(struct pstream *pstream, struct stream **new_streamp)
 
     new_fd = accept(pssl->fd, (struct sockaddr *) &sin, &sin_len);
     if (new_fd < 0) {
-        error = errno;
+        error = sock_errno();
+#ifdef _WIN32
+        if (error == WSAEWOULDBLOCK) {
+            error = EAGAIN;
+        }
+#endif
         if (error != EAGAIN) {
-            VLOG_DBG_RL(&rl, "accept: %s", ovs_strerror(error));
+            VLOG_DBG_RL(&rl, "accept: %s", sock_strerror(error));
         }
         return error;
     }
 
     error = set_nonblocking(new_fd);
     if (error) {
-        close(new_fd);
+        closesocket(new_fd);
         return error;
     }
 
@@ -851,7 +878,7 @@ static void
 pssl_wait(struct pstream *pstream)
 {
     struct pssl_pstream *pssl = pssl_pstream_cast(pstream);
-    poll_fd_wait(pssl->fd, POLLIN);
+    poll_fd_wait_event(pssl->fd, pssl->wevent, POLLIN);
 }
 
 static int
@@ -899,6 +926,10 @@ do_ssl_init(void)
 {
     SSL_METHOD *method;
 
+#ifdef _WIN32
+    /* The following call is needed if we "#include <openssl/applink.c>". */
+    CRYPTO_malloc_init();
+#endif
     SSL_library_init();
     SSL_load_error_strings();
 
@@ -1370,3 +1401,28 @@ ssl_protocol_cb(int write_p, int version OVS_UNUSED, int content_type,
 
     ds_destroy(&details);
 }
+
+/* In Windows platform, errno is not set for socket calls.
+ * The last error has to be gotten from WSAGetLastError(). */
+static int
+sock_errno(void)
+{
+#ifdef _WIN32
+    return WSAGetLastError();
+#else
+    return errno;
+#endif
+}
+
+static void
+clear_handle(int fd OVS_UNUSED, HANDLE wevent OVS_UNUSED)
+{
+#ifdef _WIN32
+    if (fd) {
+        WSAEventSelect(fd, NULL, 0);
+    }
+    if (wevent) {
+        CloseHandle(wevent);
+    }
+#endif
+}
-- 
1.7.9.5




More information about the dev mailing list