[ovs-dev,v4] Windows: Local named pipe implementation
diff mbox

Message ID CAM_3v9+CZR5Cap3jxpt-qZJfzEvzBGBrvjrsigW47629G0WCVQ@mail.gmail.com
State Not Applicable
Headers show

Commit Message

Gurucharan Shetty July 28, 2016, 4:41 p.m. UTC
On 26 July 2016 at 12:57, Alin Serdean <aserdean@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 <aserdean@cloudbasesolutions.com>
> Acked-by: Paul Boca <pboca@cloudbasesolutions.com>
>

Thank you for this. This is a very useful addition. Does adding this commit
fail any currently running unit tests on Windows?
I have a few trivial comments below.

Does the following incremental for the documentation make sense? If so, add
them.

 path \fIfile\fR to mimic the behavior of a Unix domain socket.


---
> 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     | 587
> +++++++++++++++++++++++++++++++++++++++++++++++
>  lib/unixctl.c            |   5 +-
>  lib/unixctl.man          |  11 +-
>  lib/vconn-active.man     |   3 +-
>  ovsdb/remote-active.man  |   4 +-
>  ovsdb/remote-passive.man |   4 +-
>  tests/ovsdb-server.at    |   6 +-
>  9 files changed, 606 insertions(+), 130 deletions(-)
>  create mode 100644 lib/stream-windows.c
>
> diff --git a/lib/automake.mk b/lib/automake.mk
> index 71c9d41..9067c95 100644
> --- a/lib/automake.mk
> +++ b/lib/automake.mk
> @@ -293,6 +293,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 += \
>


.....snip.......



> new file mode 100644
> index 0000000..88fe17d
> --- /dev/null
> +++ b/lib/stream-windows.c
> @@ -0,0 +1,587 @@
> +/*
> + * 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 <inttypes.h>
> +#include <netdb.h>
> +#include <poll.h>
> +#include <sys/socket.h>
> +#include <sys/types.h>
> +#include <sys/un.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <strsafe.h>
> +#include <unistd.h>
> +#include "packets.h"
> +#include "poll-loop.h"
> +#include "socket-util.h"
> +#include "dirs.h"
> +#include "util.h"
> +#include "stream-provider.h"
> +#include "openvswitch/vlog.h"
>

Do you need all the headers above?


> +
> +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);
> +
> +/* Buffer size suggested at the creation of the named pipe for reading and
> + * and writing operations */
> +#define BUFSIZE 65000
> +
> +/* Default local prefix of a named pipe */
> +#define LOCAL_PREFIX "\\\\.\\pipe\\"
> +
> +/* This function has the purpose to remove all the slashes received in s
> */
> +char*
>

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 descriptor stream. */
> +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 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;
> +};
>
Please use a full stop at the end of the sentences (for all the comments in
this file) and two spaces between sentences.



> +
> +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);
> +}
> +
> +HANDLE
>
static HANDLE
same issue at other places.


> +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;
>
I think the Windows coding style is making into this file. Please go
through the code again and fix the issues like above.


> +    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 the punix/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 the named
> pipe
> +     * was created on the same path with the slash stripped path and the
> +     * default prefix \\.\pipe\ appended.
> +     * Strip the slashed from the parameter name and append the default
> prefix
> +     */
>

s/slashed/slashes ?


> +    connect_path = xasprintf("%s%s", LOCAL_PREFIX, remove_slashes(path));
> +    free(path);
> +
> +    /* Try to connect to the named pipe. In the case all pipe instances
> are
> +     * busy we set the retry flag to true and we retry  again during the
> +     * connect function. Use overlapped flag and no buffering to ensure
> +     * an asynchronous operations */
>
s/operations/operation


> +    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 a 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 a passive stream at first
> */
> +    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)
> +{
> +    /* Stub function for connect. We already to the connect in the open
> +     * function */
> +    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) {
> +        /* Pend the read operation */
> +        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) {
> +        /* Pend the send operation */
> +        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 descriptor stream. */
> +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;
> +    /* Named pipe path used for creation */
> +    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 with a maximum of 64 active instances */
> +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. Creation terminated");
> +        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) {
> +            /* Pend the connect operation */
> +            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 */
> +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 name */
> +    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..b6a65ec 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 and a file is created in the
> '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, and 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..b27ec85 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 socket 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..8c12fbd 100644
> --- a/lib/vconn-active.man
> +++ b/lib/vconn-active.man
> @@ -11,4 +11,5 @@ 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, a local named pipe and a file is 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..eb1c827 100644
> --- a/ovsdb/remote-active.man
> +++ b/ovsdb/remote-active.man
> @@ -14,5 +14,5 @@ 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 and a file is 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..f2eddd7 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
>

Patch
diff mbox

diff --git a/lib/unixctl.man b/lib/unixctl.man
index b27ec85..a7967c4 100644
--- a/lib/unixctl.man
+++ b/lib/unixctl.man
@@ -11,8 +11,7 @@  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 socket domain
-socket.
+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/ovsdb/remote-active.man b/ovsdb/remote-active.man
index eb1c827..8cce6ea 100644
--- a/ovsdb/remote-active.man
+++ b/ovsdb/remote-active.man
@@ -14,5 +14,5 @@  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 local named pipe and a file is created in the
-path \fIfile\fR to mimic the behavior of a Unix domain socket.
+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 f2eddd7..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 local named pipe. A file is created in the
+On Windows, listen on a local named pipe.  A file is created in the