]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
watcher: Add Windows support
authorMartin Willi <martin@revosec.ch>
Thu, 17 Oct 2013 09:56:15 +0000 (11:56 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 4 Jun 2014 13:52:59 +0000 (15:52 +0200)
Instead of a pipe we use a TCP socketpair (can't select() a _pipe()), and
Windsock2 send/recv functions instead of read/write.

Currently supported (and required) are file descriptors provided by Winsock
only; we might use a separate mechanism for traditional file handles if
required (or switch to Windows events and WaitForMultipleObjects) for a future
version.

src/libstrongswan/processing/watcher.c

index 09905646c641fd430eb0d100699d698f064fa5e6..560e47299a8420fbb898392cbbcb2f408f3d6146 100644 (file)
@@ -24,7 +24,9 @@
 
 #include <unistd.h>
 #include <errno.h>
+#ifndef WIN32
 #include <sys/select.h>
+#endif
 #include <fcntl.h>
 
 typedef struct private_watcher_t private_watcher_t;
@@ -119,7 +121,14 @@ static void update(private_watcher_t *this)
        this->pending = TRUE;
        if (this->notify[1] != -1)
        {
-               ignore_result(write(this->notify[1], buf, sizeof(buf)));
+#ifdef WIN32
+               if (send(this->notify[1], buf, sizeof(buf), 0) == -1)
+#else
+               if (write(this->notify[1], buf, sizeof(buf)) == -1)
+#endif
+               {
+                       DBG1(DBG_JOB, "notifying watcher failed: %s", strerror(errno));
+               }
        }
 }
 
@@ -293,21 +302,40 @@ static job_requeue_t watch(private_watcher_t *this)
        {
                char buf[1];
                bool old;
+               ssize_t len;
                job_t *job;
 
                DBG2(DBG_JOB, "watcher going to select()");
                thread_cleanup_push((void*)activate_all, this);
                old = thread_cancelability(TRUE);
+
                res = select(maxfd + 1, &rd, &wr, &ex, NULL);
                thread_cancelability(old);
                thread_cleanup_pop(FALSE);
+
                if (res > 0)
                {
                        if (this->notify[0] != -1 && FD_ISSET(this->notify[0], &rd))
                        {
-                               DBG2(DBG_JOB, "watcher got notification, rebuilding");
-                               while (read(this->notify[0], buf, sizeof(buf)) > 0);
+                               while (TRUE)
+                               {
+#ifdef WIN32
+                                       len = recv(this->notify[0], buf, sizeof(buf), 0);
+#else
+                                       len = read(this->notify[0], buf, sizeof(buf));
+#endif
+                                       if (len == -1)
+                                       {
+                                               if (errno != EAGAIN && errno != EWOULDBLOCK)
+                                               {
+                                                       DBG1(DBG_JOB, "reading watcher notify failed: %s",
+                                                                strerror(errno));
+                                               }
+                                               break;
+                                       }
+                               }
                                this->pending = FALSE;
+                               DBG2(DBG_JOB, "watcher got notification, rebuilding");
                                return JOB_REQUEUE_DIRECT;
                        }
 
@@ -446,13 +474,60 @@ METHOD(watcher_t, destroy, void,
        free(this);
 }
 
+#ifdef WIN32
+
+/**
+ * Create notify pipe with a TCP socketpair
+ */
+static bool create_notify(private_watcher_t *this)
+{
+       u_long on = 1;
+
+       if (socketpair(AF_INET, SOCK_STREAM, 0, this->notify) == 0)
+       {
+               /* use non-blocking I/O on read-end of notify pipe */
+               if (ioctlsocket(this->notify[0], FIONBIO, &on) == 0)
+               {
+                       return TRUE;
+               }
+               DBG1(DBG_LIB, "setting watcher notify pipe read-end non-blocking "
+                        "failed: %s", strerror(errno));
+       }
+       return FALSE;
+}
+
+#else /* !WIN32 */
+
+/**
+ * Create a notify pipe with a one-directional pipe
+ */
+static bool create_notify(private_watcher_t *this)
+{
+       int flags;
+
+       if (pipe(this->notify) == 0)
+       {
+               /* use non-blocking I/O on read-end of notify pipe */
+               flags = fcntl(this->notify[0], F_GETFL);
+               if (flags != -1 &&
+                       fcntl(this->notify[0], F_SETFL, flags | O_NONBLOCK) != -1)
+               {
+                       return TRUE;
+               }
+               DBG1(DBG_LIB, "setting watcher notify pipe read-end non-blocking "
+                        "failed: %s", strerror(errno));
+       }
+       return FALSE;
+}
+
+#endif /* !WIN32 */
+
 /**
  * See header
  */
 watcher_t *watcher_create()
 {
        private_watcher_t *this;
-       int flags;
 
        INIT(this,
                .public = {
@@ -467,18 +542,7 @@ watcher_t *watcher_create()
                .notify = {-1, -1},
        );
 
-       if (pipe(this->notify) == 0)
-       {
-               /* use non-blocking I/O on read-end of notify pipe */
-               flags = fcntl(this->notify[0], F_GETFL);
-               if (flags == -1 ||
-                       fcntl(this->notify[0], F_SETFL, flags | O_NONBLOCK) == -1)
-               {
-                       DBG1(DBG_LIB, "setting watcher notify pipe read-end non-blocking "
-                                "failed: %s", strerror(errno));
-               }
-       }
-       else
+       if (!create_notify(this))
        {
                DBG1(DBG_LIB, "creating watcher notify pipe failed: %s",
                         strerror(errno));