From 922247c68438d5718dbfbbb11d6c4bb0799105c7 Mon Sep 17 00:00:00 2001 From: Alin Serdean Date: Tue, 2 Aug 2016 18:19:34 +0000 Subject: [PATCH] Windows: Local named pipe implementation Currently in the case of command line arguments punix/unix, on Windows we create a file, write a TCP port number to connect. This is a security concern. This patch adds support for the command line arguments punix/unix trying to mimic AF_UNIX behind a local named pipe. This patch drops the TCP socket implementation behind command line arguments punix/unix and switches to the local named pipe implementation. Since we do not write anything to the file created by the punix/unix arguments, switch tests to plain file existence. Man pages and code comments have been updated. Signed-off-by: Alin Gabriel Serdean Acked-by: Paul Boca Signed-off-by: Gurucharan Shetty --- lib/automake.mk | 1 + lib/stream-tcp.c | 115 -------- lib/stream-windows.c | 581 +++++++++++++++++++++++++++++++++++++++ lib/unixctl.c | 5 +- lib/unixctl.man | 10 +- lib/vconn-active.man | 4 +- ovsdb/remote-active.man | 5 +- ovsdb/remote-passive.man | 4 +- tests/ovsdb-server.at | 6 +- 9 files changed, 601 insertions(+), 130 deletions(-) create mode 100644 lib/stream-windows.c diff --git a/lib/automake.mk b/lib/automake.mk index 646306deb..97c83e9c3 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -302,6 +302,7 @@ lib_libopenvswitch_la_SOURCES += \ lib/latch-windows.c \ lib/route-table-stub.c \ lib/if-notifier-stub.c \ + lib/stream-windows.c \ lib/strsep.c else lib_libopenvswitch_la_SOURCES += \ diff --git a/lib/stream-tcp.c b/lib/stream-tcp.c index 2b57ca71a..1749fadbf 100644 --- a/lib/stream-tcp.c +++ b/lib/stream-tcp.c @@ -74,64 +74,6 @@ const struct stream_class tcp_stream_class = { NULL, /* run_wait */ NULL, /* wait */ }; - -#ifdef _WIN32 -#include "dirs.h" - -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 = xstrdup(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 /* Passive TCP. */ @@ -198,60 +140,3 @@ const struct pstream_class ptcp_pstream_class = { NULL, NULL, }; - -#ifdef _WIN32 -static int -pwindows_open(const char *name, 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"); - - /* 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 = xstrdup(suffix); - } - - error = new_pstream(suffix_new, name, pstreamp, dscp, path, false); - if (error) { - goto exit; - } - listener = *pstreamp; - - 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); - -exit: - free(suffix_new); - return error; -} - -const struct pstream_class pwindows_pstream_class = { - "punix", - false, - pwindows_open, - NULL, - NULL, - NULL, -}; -#endif diff --git a/lib/stream-windows.c b/lib/stream-windows.c new file mode 100644 index 000000000..e0fe012fb --- /dev/null +++ b/lib/stream-windows.c @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2016 Cloudbase Solutions Srl + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include "poll-loop.h" +#include "dirs.h" +#include "util.h" +#include "stream-provider.h" +#include "openvswitch/vlog.h" + +VLOG_DEFINE_THIS_MODULE(stream_windows); + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 25); + +static void maybe_unlink_and_free(char *path); + +/* Suggested buffer size at the creation of the named pipe for reading and + * and writing operations. */ +#define BUFSIZE 65000 + +/* Default prefix of a local named pipe. */ +#define LOCAL_PREFIX "\\\\.\\pipe\\" + +/* This function has the purpose to remove all the slashes received in s. */ +static char * +remove_slashes(char *s) +{ + char *p1, *p2; + p1 = p2 = s; + + while (*p1) { + if ((*p1) == '\\' || (*p1) == '/') { + p1++; + } else { + *p2 = *p1; + p2++; + p1++; + } + } + *p2 = '\0'; + return s; +} + +/* Active named pipe. */ +struct windows_stream +{ + struct stream stream; + HANDLE fd; + /* Overlapped operations used for reading/writing. */ + OVERLAPPED read; + OVERLAPPED write; + /* Flag to check if a reading/writing operation is pending. */ + bool read_pending; + bool write_pending; + /* Flag to check if fd is a server HANDLE. In the case of a server handle + * we have to issue a disconnect before closing the actual handle. */ + bool server; + bool retry_connect; + char *pipe_path; +}; + +static struct windows_stream * +stream_windows_cast(struct stream *stream) +{ + stream_assert_class(stream, &windows_stream_class); + return CONTAINER_OF(stream, struct windows_stream, stream); +} + +static HANDLE +create_snpipe(char *path) +{ + return CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | + FILE_FLAG_NO_BUFFERING, + NULL); +} + +/* Active named pipe open. */ +static int +windows_open(const char *name, char *suffix, struct stream **streamp, + uint8_t dscp OVS_UNUSED) +{ + char *connect_path; + HANDLE npipe; + DWORD mode = PIPE_READMODE_BYTE; + char *path; + FILE *file; + bool retry = false; + /* 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 = xstrdup(suffix); + } + + /* In case of "unix:" argument, the assumption is that there is a file + * created in the path (name). */ + file = fopen(path, "r"); + if (!file) { + free(path); + VLOG_DBG_RL(&rl, "%s: could not open %s (%s)", name, suffix, + ovs_strerror(errno)); + return ENOENT; + } else { + fclose(file); + } + + /* Valid pipe names do not have slashes. The assumption is that the named + * pipe was created with the name "path", with slashes removed and the + * default prefix \\.\pipe\ appended. + * Strip the slashes from the parameter name and append the default prefix. + */ + connect_path = xasprintf("%s%s", LOCAL_PREFIX, remove_slashes(path)); + free(path); + + /* Try to connect to the named pipe. In case all pipe instances are + * busy we set the retry flag to true and retry again during the + * connect function. Use overlapped flag and file no buffering to ensure + * asynchronous operations. */ + npipe = create_snpipe(connect_path); + + if (npipe == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PIPE_BUSY) { + retry = true; + } + + if (!retry && npipe == INVALID_HANDLE_VALUE) { + VLOG_ERR_RL(&rl, "Could not connect to named pipe: %s", + ovs_lasterror_to_string()); + free(connect_path); + return ENOENT; + } + if (!retry && !SetNamedPipeHandleState(npipe, &mode, NULL, NULL)) { + VLOG_ERR_RL(&rl, "Could not set named pipe options: %s", + ovs_lasterror_to_string()); + free(connect_path); + CloseHandle(npipe); + return ENOENT; + } + struct windows_stream *s = xmalloc(sizeof *s); + stream_init(&s->stream, &windows_stream_class, 0, name); + s->pipe_path = connect_path; + s->fd = npipe; + /* This is an active stream. */ + s->server = false; + /* Create events for reading and writing to be signaled later. */ + memset(&s->read, 0, sizeof(s->read)); + memset(&s->write, 0, sizeof(s->write)); + s->read.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + s->write.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + /* Initial read and write operations are not pending. */ + s->read_pending = false; + s->write_pending = false; + s->retry_connect = retry; + *streamp = &s->stream; + return 0; +} + +/* Active named pipe close. */ +static void +windows_close(struct stream *stream) +{ + struct windows_stream *s = stream_windows_cast(stream); + /* Disconnect the named pipe in case it was created from a passive stream. + */ + if (s->server) { + DisconnectNamedPipe(s->fd); + } + CloseHandle(s->fd); + CloseHandle(s->read.hEvent); + CloseHandle(s->write.hEvent); + if (s->pipe_path) { + free(s->pipe_path); + } + free(s); +} + +/* Active named pipe connect. */ +static int +windows_connect(struct stream *stream) +{ + struct windows_stream *s = stream_windows_cast(stream); + + if (!s->retry_connect) { + return 0; + } else { + HANDLE npipe; + npipe = create_snpipe(s->pipe_path); + if (npipe == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_PIPE_BUSY) { + return EAGAIN; + } else { + s->retry_connect = false; + return ENOENT; + } + } + s->retry_connect = false; + s->fd = npipe; + return 0; + } +} + +/* Active named pipe receive. */ +static ssize_t +windows_recv(struct stream *stream, void *buffer, size_t n) +{ + struct windows_stream *s = stream_windows_cast(stream); + ssize_t retval = 0; + boolean result = false; + DWORD last_error = 0; + LPOVERLAPPED ov = NULL; + ov = &s->read; + + /* If the read operation was pending, we verify its result. */ + if (s->read_pending) { + if (!GetOverlappedResult(s->fd, ov, &(DWORD)retval, FALSE)) { + last_error = GetLastError(); + if (last_error == ERROR_IO_INCOMPLETE) { + /* If the operation is still pending, retry again. */ + s->read_pending = true; + return -EAGAIN; + } else if (last_error == ERROR_PIPE_NOT_CONNECTED + || last_error == ERROR_BAD_PIPE + || last_error == ERROR_NO_DATA + || last_error == ERROR_BROKEN_PIPE) { + /* If the pipe was disconnected, return 0. */ + return 0; + } else { + VLOG_ERR_RL(&rl, "Could not receive data on named pipe. Last " + "error: %s", ovs_lasterror_to_string()); + return -EINVAL; + } + } + s->read_pending = false; + return retval; + } + + result = ReadFile(s->fd, buffer, n, &(DWORD)retval, ov); + + if (!result && GetLastError() == ERROR_IO_PENDING) { + /* Mark the read operation as pending. */ + s->read_pending = true; + return -EAGAIN; + } else if (!result) { + last_error = GetLastError(); + if (last_error == ERROR_PIPE_NOT_CONNECTED + || last_error == ERROR_BAD_PIPE + || last_error == ERROR_NO_DATA + || last_error == ERROR_BROKEN_PIPE) { + /* If the pipe was disconnected, return 0. */ + return 0; + } + VLOG_ERR_RL(&rl, "Could not receive data synchronous on named pipe." + "Last error: %s", ovs_lasterror_to_string()); + return -EINVAL; + } + + return retval; +} + +/* Active named pipe send. */ +static ssize_t +windows_send(struct stream *stream, const void *buffer, size_t n) +{ + struct windows_stream *s = stream_windows_cast(stream); + ssize_t retval = 0; + boolean result = false; + DWORD last_error = 0; + LPOVERLAPPED ov = NULL; + ov = &s->write; + + /* If the send operation was pending, we verify the result. */ + if (s->write_pending) { + if (!GetOverlappedResult(s->fd, ov, &(DWORD)retval, FALSE)) { + last_error = GetLastError(); + if (last_error == ERROR_IO_INCOMPLETE) { + /* If the operation is still pending, retry again. */ + s->write_pending = true; + return -EAGAIN; + } else if (last_error == ERROR_PIPE_NOT_CONNECTED + || last_error == ERROR_BAD_PIPE + || last_error == ERROR_NO_DATA + || last_error == ERROR_BROKEN_PIPE) { + /* If the pipe was disconnected, return connection reset. */ + return -WSAECONNRESET; + } else { + VLOG_ERR_RL(&rl, "Could not send data on named pipe. Last " + "error: %s", ovs_lasterror_to_string()); + return -EINVAL; + } + } + s->write_pending = false; + return retval; + } + + result = WriteFile(s->fd, buffer, n, &(DWORD)retval, ov); + last_error = GetLastError(); + if (!result && GetLastError() == ERROR_IO_PENDING) { + /* Mark the send operation as pending. */ + s->write_pending = true; + return -EAGAIN; + } else if (!result && (last_error == ERROR_PIPE_NOT_CONNECTED + || last_error == ERROR_BAD_PIPE + || last_error == ERROR_NO_DATA + || last_error == ERROR_BROKEN_PIPE)) { + /* If the pipe was disconnected, return connection reset. */ + return -WSAECONNRESET; + } else if (!result) { + VLOG_ERR_RL(&rl, "Could not send data on synchronous named pipe. Last " + "error: %s", ovs_lasterror_to_string()); + return -EINVAL; + } + return (retval > 0 ? retval : -EAGAIN); +} + +/* Active named pipe wait. */ +static void +windows_wait(struct stream *stream, enum stream_wait_type wait) +{ + struct windows_stream *s = stream_windows_cast(stream); + switch (wait) { + case STREAM_SEND: + poll_wevent_wait(s->write.hEvent); + break; + + case STREAM_CONNECT: + poll_immediate_wake(); + break; + + case STREAM_RECV: + poll_wevent_wait(s->read.hEvent); + break; + + default: + OVS_NOT_REACHED(); + } +} + +/* Passive named pipe. */ +const struct stream_class windows_stream_class = { + "unix", /* name */ + false, /* needs_probes */ + windows_open, /* open */ + windows_close, /* close */ + windows_connect, /* connect */ + windows_recv, /* recv */ + windows_send, /* send */ + NULL, /* run */ + NULL, /* run_wait */ + windows_wait, /* wait */ +}; + +struct pwindows_pstream +{ + struct pstream pstream; + HANDLE fd; + /* Unlink path to be deleted during close. */ + char *unlink_path; + /* Overlapped operation used for connect. */ + OVERLAPPED connect; + /* Flag to check if an operation is pending. */ + bool pending; + /* String used to create the named pipe. */ + char *pipe_path; +}; + +const struct pstream_class pwindows_pstream_class; + +static struct pwindows_pstream * +pwindows_pstream_cast(struct pstream *pstream) +{ + pstream_assert_class(pstream, &pwindows_pstream_class); + return CONTAINER_OF(pstream, struct pwindows_pstream, pstream); +} + +/* Create a named pipe with read/write access, overlapped, message mode for + * writing, byte mode for reading and with a maximum of 64 active instances. */ +static HANDLE +create_pnpipe(char *name) +{ + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + if (strlen(name) > 256) { + VLOG_ERR_RL(&rl, "Named pipe name too long."); + return INVALID_HANDLE_VALUE; + } + return CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_BYTE | PIPE_WAIT, + 64, BUFSIZE, BUFSIZE, 0, &sa); +} + +/* Passive named pipe connect. This function creates a new named pipe and + * passes the old handle to the active stream. */ +static int +pwindows_accept(struct pstream *pstream, struct stream **new_streamp) +{ + struct pwindows_pstream *p = pwindows_pstream_cast(pstream); + DWORD last_error = 0; + DWORD cbRet; + HANDLE npipe; + + /* If the connect operation was pending, verify the result. */ + if (p->pending) { + if (!GetOverlappedResult(p->fd, &p->connect, &cbRet, FALSE)) { + last_error = GetLastError(); + if (last_error == ERROR_IO_INCOMPLETE) { + /* If the operation is still pending, retry again. */ + p->pending = true; + return EAGAIN; + } else { + VLOG_ERR_RL(&rl, "Could not connect named pipe. Last " + "error: %s", ovs_lasterror_to_string()); + return EINVAL; + } + } + p->pending = false; + } + + if (!p->pending && !ConnectNamedPipe(p->fd, &p->connect)) { + last_error = GetLastError(); + if (last_error == ERROR_IO_PENDING) { + /* Mark the accept operation as pending. */ + p->pending = true; + return EAGAIN; + } else if (last_error != ERROR_PIPE_CONNECTED) { + VLOG_ERR_RL(&rl, "Could not connect synchronous named pipe. Last " + "error: %s", ovs_lasterror_to_string()); + return EINVAL; + } else { + /* If the pipe is connected, signal an event. */ + SetEvent(&p->connect.hEvent); + } + } + + npipe = create_pnpipe(p->pipe_path); + if (npipe == INVALID_HANDLE_VALUE) { + VLOG_ERR_RL(&rl, "Could not create a new named pipe after connect. ", + ovs_lasterror_to_string()); + return ENOENT; + } + + /* Give the handle p->fd to the new created active stream and specify it + * was created by an active stream. */ + struct windows_stream *p_temp = xmalloc(sizeof *p_temp); + stream_init(&p_temp->stream, &windows_stream_class, 0, "unix"); + p_temp->fd = p->fd; + /* Specify it was created by a passive stream. */ + p_temp->server = true; + /* Create events for read/write operations. */ + memset(&p_temp->read, 0, sizeof(p_temp->read)); + memset(&p_temp->write, 0, sizeof(p_temp->write)); + p_temp->read.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + p_temp->write.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + p_temp->read_pending = false; + p_temp->write_pending = false; + p_temp->retry_connect = false; + p_temp->pipe_path = NULL; + *new_streamp = &p_temp->stream; + + /* The passive handle p->fd will be the new created handle. */ + p->fd = npipe; + memset(&p->connect, 0, sizeof(p->connect)); + p->connect.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + p->pending = false; + return 0; +} + +/* Passive named pipe close. */ +static void +pwindows_close(struct pstream *pstream) +{ + struct pwindows_pstream *p = pwindows_pstream_cast(pstream); + DisconnectNamedPipe(p->fd); + CloseHandle(p->fd); + CloseHandle(p->connect.hEvent); + maybe_unlink_and_free(p->unlink_path); + free(p->pipe_path); + free(p); +} + +/* Passive named pipe wait. */ +static void +pwindows_wait(struct pstream *pstream) +{ + struct pwindows_pstream *p = pwindows_pstream_cast(pstream); + poll_wevent_wait(p->connect.hEvent); +} + +/* Passive named pipe. */ +static int +pwindows_open(const char *name OVS_UNUSED, char *suffix, + struct pstream **pstreamp, uint8_t dscp OVS_UNUSED) +{ + char *bind_path; + int error; + HANDLE npipe; + char *orig_path; + + char *path; + if (!strchr(suffix, ':')) { + path = xasprintf("%s/%s", ovs_rundir(), suffix); + } else { + path = xstrdup(suffix); + } + + /* Try to create a file under the path location. */ + FILE *file = fopen(path, "w"); + if (!file) { + free(path); + error = errno; + VLOG_DBG_RL(&rl, "could not open %s (%s)", path, ovs_strerror(error)); + return error; + } else { + fclose(file); + } + + orig_path = xstrdup(path); + /* Strip slashes from path and create a named pipe using that newly created + * string. */ + bind_path = xasprintf("%s%s", LOCAL_PREFIX, remove_slashes(path)); + free(path); + + npipe = create_pnpipe(bind_path); + + if (npipe == INVALID_HANDLE_VALUE) { + VLOG_ERR_RL(&rl, "Could not create named pipe. Last error: %s", + ovs_lasterror_to_string()); + return ENOENT; + } + + struct pwindows_pstream *p = xmalloc(sizeof *p); + pstream_init(&p->pstream, &pwindows_pstream_class, name); + p->fd = npipe; + p->unlink_path = orig_path; + memset(&p->connect, 0, sizeof(p->connect)); + p->connect.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + p->pending = false; + p->pipe_path = bind_path; + *pstreamp = &p->pstream; + return 0; +} + +const struct pstream_class pwindows_pstream_class = { + "punix", + false, /* probes */ + pwindows_open, /* open */ + pwindows_close, /* close */ + pwindows_accept, /* accept */ + pwindows_wait, /* wait */ +}; + +/* Helper functions. */ +static void +maybe_unlink_and_free(char *path) +{ + if (path) { + fatal_signal_unlink_file_now(path); + free(path); + } +} diff --git a/lib/unixctl.c b/lib/unixctl.c index 5e5d26c68..57d6577b2 100644 --- a/lib/unixctl.c +++ b/lib/unixctl.c @@ -195,7 +195,7 @@ unixctl_command_reply_error(struct unixctl_conn *conn, const char *error) * - An absolute path (starting with '/') that gives the exact name of * the Unix domain socket to listen on. * - * For Windows, a kernel assigned TCP port is used and written in 'path' + * For Windows, a local named pipe is used. A file is created in 'path' * which may be: * * - NULL, in which case /.ctl is used. @@ -442,7 +442,8 @@ unixctl_server_destroy(struct unixctl_server *server) * be the name of a unixctl server socket. If it does not start with '/', it * will be prefixed with the rundir (e.g. /usr/local/var/run/openvswitch). * - * On Windows, connects to a localhost TCP port as written inside 'path'. + * On Windows, connects to a local named pipe. A file which resides in + * 'path' is used to mimic the behavior of a Unix domain socket. * 'path' should be an absolute path of the file. * * Returns 0 if successful, otherwise a positive errno value. If successful, diff --git a/lib/unixctl.man b/lib/unixctl.man index b681c7d2e..f72eae8d7 100644 --- a/lib/unixctl.man +++ b/lib/unixctl.man @@ -7,11 +7,11 @@ not used at all, the default socket is \fB@RUNDIR@/\*(PN.\fIpid\fB.ctl\fR, where \fIpid\fR is \fB\*(PN\fR's process ID. .IP -On Windows, uses a kernel chosen TCP port on the localhost to listen -for runtime management commands. The kernel chosen TCP port value is written -in a file whose absolute path is pointed by \fIsocket\fR. If \fB\-\-unixctl\fR -is not used at all, the file is created as \fB\*(PN.ctl\fR in the configured -\fIOVS_RUNDIR\fR directory. +On Windows a local named pipe is used to listen for runtime management +commands. A file is created in the absolute path as pointed by +\fIsocket\fR or if \fB\-\-unixctl\fR is not used at all, a file is +created as \fB\*(PN.ctl\fR in the configured \fIOVS_RUNDIR\fR +directory. The file exists just to mimic the behavior of a Unix domain socket. .IP Specifying \fBnone\fR for \fIsocket\fR disables the control socket feature. diff --git a/lib/vconn-active.man b/lib/vconn-active.man index 252438da7..3e789cc88 100644 --- a/lib/vconn-active.man +++ b/lib/vconn-active.man @@ -11,4 +11,6 @@ If \fIport\fR is not specified, it defaults to 6653. \fBunix:\fIfile\fR On POSIX, a Unix domain server socket named \fIfile\fR. .IP -On Windows, a localhost TCP port written in \fIfile\fR. +On Windows, connect to a local named pipe that is represented by a +file created in the path \fIfile\fR to mimic the behavior of a Unix +domain socket. diff --git a/ovsdb/remote-active.man b/ovsdb/remote-active.man index 22b350c1a..83d64652d 100644 --- a/ovsdb/remote-active.man +++ b/ovsdb/remote-active.man @@ -14,5 +14,6 @@ square brackets, e.g.: \fBtcp:[::1]:6640\fR. .IP "\fBunix:\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. +On Windows, connect to a local named pipe that is represented by a file +created in the path \fIfile\fR to mimic the behavior of a Unix domain +socket. diff --git a/ovsdb/remote-passive.man b/ovsdb/remote-passive.man index a05f79695..5da2de87b 100644 --- a/ovsdb/remote-passive.man +++ b/ovsdb/remote-passive.man @@ -22,5 +22,5 @@ an IPv6 address, then wrap \fIip\fR with square brackets, e.g.: 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. +On Windows, listen on a local named pipe. A file is created in the +path \fIfile\fR to mimic the behavior of a Unix domain socket. diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index e70498dfd..d9d24690b 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -388,7 +388,7 @@ AT_CHECK([ovsdb-server --detach --no-chdir --pidfile db]) AT_CHECK([test ! -e socket1]) AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-remote punix:socket1]) if test "$IS_WIN32" = "yes"; then - OVS_WAIT_UNTIL([test -s socket1]) + OVS_WAIT_UNTIL([test -e socket1]) else OVS_WAIT_UNTIL([test -S socket1]) fi @@ -399,7 +399,7 @@ AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes], AT_CHECK([test ! -e socket2]) AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-remote punix:socket2]) if test "$IS_WIN32" = "yes"; then - OVS_WAIT_UNTIL([test -s socket2]) + OVS_WAIT_UNTIL([test -e socket2]) else OVS_WAIT_UNTIL([test -S socket2]) fi @@ -416,7 +416,7 @@ ovs-appctl: ovsdb-server: server returned an error AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-remote punix:socket1]) OVS_WAIT_UNTIL([test ! -e socket1]) if test "$IS_WIN32" = "yes"; then - AT_CHECK([test -s socket2]) + AT_CHECK([test -e socket2]) else AT_CHECK([test -S socket2]) fi -- 2.39.5