On 2 August 2016 at 11:19, Alin Serdean <aserd...@cloudbasesolutions.com> wrote:
> 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 <aserd...@cloudbasesolutions.com> > Acked-by: Paul Boca <pb...@cloudbasesolutions.com> > Thank you, applied. > --- > v7: clarify that on 'unix' argument, we do not create a file > v6: resubmit for patchwork > v5: fix coding style > v4: improve spelling in man pages > v3: squash commits update documentation and code comments > v2: Address comments, fix handle leaks. > --- > lib/automake.mk | 1 + > lib/stream-tcp.c | 115 ---------- > lib/stream-windows.c | 581 > +++++++++++++++++++++++++++++++++++++++++++++++ > lib/unixctl.c | 5 +- > lib/unixctl.man | 11 +- > lib/vconn-active.man | 4 +- > ovsdb/remote-active.man | 7 +- > ovsdb/remote-passive.man | 4 +- > tests/ovsdb-server.at | 6 +- > 9 files changed, 603 insertions(+), 131 deletions(-) > create mode 100644 lib/stream-windows.c > > diff --git a/lib/automake.mk b/lib/automake.mk > index 646306d..97c83e9 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 2b57ca7..1749fad 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 0000000..e0fe012 > --- /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 <config.h> > +#include <errno.h> > +#include <sys/types.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#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 5e5d26c..57d6577 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 <rundir>/<program>.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 b681c7d..42d0d1e 100644 > --- a/lib/unixctl.man > +++ b/lib/unixctl.man > @@ -7,11 +7,12 @@ 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 252438d..3e789cc 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 22b350c..868271b 100644 > --- a/ovsdb/remote-active.man > +++ b/ovsdb/remote-active.man > @@ -8,11 +8,12 @@ options are mandatory when this form is used. > . > .IP "\fBtcp:\fIip\fB:\fIport\fR" > Connect to the given TCP \fIport\fR on \fIip\fR, where \fIip\fR can be > IPv4 > -or IPv6 address. If \fIip\fR is an IPv6 address, then wrap \fIip\fR with > +or IPv6 address. If \fIip\fR is an IPv6 address, then wrap \fIip\fR with > 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 a05f796..5da2de8 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 e70498d..d9d2469 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 > -- > 1.9.5.msysgit.0 > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev