stream: Introduce [p]windows_[p]stream_class.
authorGurucharan Shetty <gshetty@nicira.com>
Fri, 4 Apr 2014 21:13:32 +0000 (14:13 -0700)
committerGurucharan Shetty <gshetty@nicira.com>
Tue, 22 Apr 2014 22:16:40 +0000 (15:16 -0700)
On Linux, we heavily use --remote=punix:* to listen for
connections through unix domain sockets. We also use, unix:*
to connect to a daemon that is listening on unix domain sockets.
Many times, we create default unix domain sockets for listening
and many utilities connect to these sockets by default.

Windows does not have unix domain sockets. So far, we could just use
ptcp:* and tcp:* for listening and initiating connections respectively.
The drawback here is that one has to provide a specific TCP port.

For unit tests, it looks useful to let kernel choose that port.
As such, we can let that chosen kernel port be stored in the
file specified with punix:* and unix:*. For this purpose, introduce
a new [p]windows_[p]stream_class. Since it is just a wrapper around
[p]tcp_[p]stream_class, add it to stream-tcp.c.

commit cb54a8c (unixctl: Add support for Windows.) used the above concept
for only control channel connections (i.e., --unixctl for daemons and its
interaction with ovs-appctl). This commit adds the same support for
all unix domain sockets.  Now that we have a separate class
[p]stream_class for hiding kernel assigned TCP port inside a file meant for
unix domain sockets in windows, make unixctl use it.

Signed-off-by: Gurucharan Shetty <gshetty@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
lib/stream-provider.h
lib/stream-tcp.c
lib/stream.c
lib/unixctl.c
lib/vconn-active.man
ovsdb/remote-active.man
ovsdb/remote-passive.man

index 44d75d3..8347ac6 100644 (file)
@@ -191,8 +191,13 @@ struct pstream_class {
 /* Active and passive stream classes. */
 extern const struct stream_class tcp_stream_class;
 extern const struct pstream_class ptcp_pstream_class;
+#ifndef _WIN32
 extern const struct stream_class unix_stream_class;
 extern const struct pstream_class punix_pstream_class;
+#else
+extern const struct stream_class windows_stream_class;
+extern const struct pstream_class pwindows_pstream_class;
+#endif
 #ifdef HAVE_OPENSSL
 extern const struct stream_class ssl_stream_class;
 extern const struct pstream_class pssl_pstream_class;
index d62e9c3..74db2f1 100644 (file)
@@ -91,6 +91,62 @@ const struct stream_class tcp_stream_class = {
     NULL,                       /* run_wait */
     NULL,                       /* wait */
 };
+
+#ifdef _WIN32
+static int
+windows_open(const char *name, char *suffix, struct stream **streamp,
+             uint8_t dscp)
+{
+    int error, port;
+    FILE *file;
+    char *suffix_new, *path;
+
+    /* If the path does not contain a ':', assume it is relative to
+     * OVS_RUNDIR. */
+    if (!strchr(suffix, ':')) {
+        path = xasprintf("%s/%s", ovs_rundir(), suffix);
+    } else {
+        path = strdup(suffix);
+    }
+
+    file = fopen(path, "r");
+    if (!file) {
+        error = errno;
+        VLOG_DBG("%s: could not open %s (%s)", name, suffix,
+                 ovs_strerror(error));
+        return error;
+    }
+
+    error = fscanf(file, "%d", &port);
+    if (error != 1) {
+        VLOG_ERR("failed to read port from %s", suffix);
+        fclose(file);
+        return EINVAL;
+    }
+    fclose(file);
+
+    suffix_new = xasprintf("127.0.0.1:%d", port);
+
+    error = tcp_open(name, suffix_new, streamp, dscp);
+
+    free(suffix_new);
+    free(path);
+    return error;
+}
+
+const struct stream_class windows_stream_class = {
+    "unix",                     /* name */
+    false,                      /* needs_probes */
+    windows_open,                  /* open */
+    NULL,                       /* close */
+    NULL,                       /* connect */
+    NULL,                       /* recv */
+    NULL,                       /* send */
+    NULL,                       /* run */
+    NULL,                       /* run_wait */
+    NULL,                       /* wait */
+};
+#endif
 \f
 /* Passive TCP. */
 
@@ -148,3 +204,60 @@ const struct pstream_class ptcp_pstream_class = {
     NULL,
 };
 
+#ifdef _WIN32
+static int
+pwindows_open(const char *name OVS_UNUSED, char *suffix,
+              struct pstream **pstreamp, uint8_t dscp)
+{
+    int error;
+    char *suffix_new, *path;
+    FILE *file;
+    struct pstream *listener;
+
+    suffix_new = xstrdup("0:127.0.0.1");
+    error = ptcp_open(name, suffix_new, pstreamp, dscp);
+    if (error) {
+        goto exit;
+    }
+    listener = *pstreamp;
+
+    /* If the path does not contain a ':', assume it is relative to
+     * OVS_RUNDIR. */
+    if (!strchr(suffix, ':')) {
+        path = xasprintf("%s/%s", ovs_rundir(), suffix);
+    } else {
+        path = strdup(suffix);
+    }
+
+    file = fopen(path, "w");
+    if (!file) {
+        error = errno;
+        VLOG_DBG("could not open %s (%s)", path, ovs_strerror(error));
+        goto exit;
+    }
+
+    fprintf(file, "%d\n", ntohs(listener->bound_port));
+    if (fflush(file) == EOF) {
+        error = EIO;
+        VLOG_ERR("write failed for %s", path);
+        fclose(file);
+        goto exit;
+    }
+    fclose(file);
+    free(path);
+
+exit:
+    free(suffix_new);
+    return error;
+}
+
+const struct pstream_class pwindows_pstream_class = {
+    "punix",
+    false,
+    pwindows_open,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+};
+#endif
index fa5b6d6..55632fe 100644 (file)
@@ -55,6 +55,8 @@ static const struct stream_class *stream_classes[] = {
     &tcp_stream_class,
 #ifndef _WIN32
     &unix_stream_class,
+#else
+    &windows_stream_class,
 #endif
 #ifdef HAVE_OPENSSL
     &ssl_stream_class,
@@ -65,6 +67,8 @@ static const struct pstream_class *pstream_classes[] = {
     &ptcp_pstream_class,
 #ifndef _WIN32
     &punix_pstream_class,
+#else
+    &pwindows_pstream_class,
 #endif
 #ifdef HAVE_OPENSSL
     &pssl_pstream_class,
index 20acc3c..c982214 100644 (file)
@@ -211,28 +211,31 @@ unixctl_server_create(const char *path, struct unixctl_server **serverp)
 {
     struct unixctl_server *server;
     struct pstream *listener;
-    char *punix_path, *abs_path = NULL;
+    char *punix_path;
     int error;
-#ifdef _WIN32
-    FILE *file;
-#endif
 
     *serverp = NULL;
     if (path && !strcmp(path, "none")) {
         return 0;
     }
 
-#ifndef _WIN32
     if (path) {
+        char *abs_path;
+#ifndef _WIN32
         abs_path = abs_file_name(ovs_rundir(), path);
+#else
+        abs_path = strdup(path);
+#endif
         punix_path = xasprintf("punix:%s", abs_path);
+        free(abs_path);
     } else {
+#ifndef _WIN32
         punix_path = xasprintf("punix:%s/%s.%ld.ctl", ovs_rundir(),
                                program_name, (long int) getpid());
-    }
 #else
-    punix_path = xstrdup("ptcp:0:127.0.0.1");
+        punix_path = xasprintf("punix:%s/%s.ctl", ovs_rundir(), program_name);
 #endif
+    }
 
     error = pstream_open(punix_path, &listener, 0);
     if (error) {
@@ -240,30 +243,6 @@ unixctl_server_create(const char *path, struct unixctl_server **serverp)
         goto exit;
     }
 
-#ifdef _WIN32
-    if (path) {
-        abs_path = xstrdup(path);
-    } else {
-        abs_path = xasprintf("%s/%s.ctl", ovs_rundir(), program_name);
-    }
-
-    file = fopen(abs_path, "w");
-    if (!file) {
-        error = errno;
-        ovs_error(error, "could not open %s", abs_path);
-        goto exit;
-    }
-
-    fprintf(file, "%d\n", ntohs(listener->bound_port));
-    if (fflush(file) == EOF) {
-        error = EIO;
-        ovs_error(error, "write failed for %s", abs_path);
-        fclose(file);
-        goto exit;
-    }
-    fclose(file);
-#endif
-
     unixctl_command_register("help", "", 0, 0, unixctl_help, NULL);
     unixctl_command_register("version", "", 0, 0, unixctl_version, NULL);
 
@@ -273,9 +252,6 @@ unixctl_server_create(const char *path, struct unixctl_server **serverp)
     *serverp = server;
 
 exit:
-    if (abs_path) {
-        free(abs_path);
-    }
     free(punix_path);
     return error;
 }
@@ -460,32 +436,13 @@ unixctl_client_create(const char *path, struct jsonrpc **client)
     char *abs_path, *unix_path;
     struct stream *stream;
     int error;
-#ifdef _WIN32
-    FILE *file;
-    int port;
 
+#ifdef _WIN32
     abs_path = strdup(path);
-    file = fopen(abs_path, "r");
-    if (!file) {
-        int error = errno;
-        ovs_error(error, "could not open %s", abs_path);
-        free(abs_path);
-        return error;
-    }
-
-    error = fscanf(file, "%d", &port);
-    if (error != 1) {
-        ovs_error(errno, "failed to read port from %s", abs_path);
-        free(abs_path);
-        return EINVAL;
-    }
-    fclose(file);
-
-    unix_path = xasprintf("tcp:127.0.0.1:%d", port);
 #else
     abs_path = abs_file_name(ovs_rundir(), path);
-    unix_path = xasprintf("unix:%s", abs_path);
 #endif
+    unix_path = xasprintf("unix:%s", abs_path);
 
     *client = NULL;
 
index c1e9281..b0c4ace 100644 (file)
@@ -11,4 +11,6 @@ future, the default will change to 6653, which is the IANA-defined
 value.
 .TP
 \fBunix:\fIfile\fR
-The Unix domain server socket named \fIfile\fR.
+On POSIX, a Unix domain server socket named \fIfile\fR.
+.IP
+On Windows, a localhost TCP port written in \fIfile\fR.
index 419b1c8..5facf0a 100644 (file)
@@ -12,4 +12,7 @@ or IPv6 address. If \fIip\fR is an IPv6 address, then wrap \fIip\fR with
 square brackets, e.g.: \fBtcp:[::1]:6632\fR.
 .
 .IP "\fBunix:\fIfile\fR"
-Connect to the Unix domain server socket named \fIfile\fR.
+On POSIX, connect to the Unix domain server socket named \fIfile\fR.
+.IP
+On Windows, connect to a localhost TCP port whose value is written in
+\fIfile\fR.
index 200651b..e5e5c98 100644 (file)
@@ -19,5 +19,8 @@ an IPv6 address, then wrap \fIip\fR with square brackets, e.g.:
 \fBptcp:6632:[::1]\fR.
 .
 .IP "\fBpunix:\fIfile\fR"
-Listen on the Unix domain server socket named \fIfile\fR for a
+On POSIX, listen on the Unix domain server socket named \fIfile\fR for a
 connection.
+.IP
+On Windows, listen on a kernel chosen TCP port on the localhost. The kernel
+chosen TCP port value is written in \fIfile\fR.