From patchwork Thu Jul 28 16:41:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gurucharan Shetty X-Patchwork-Id: 653823 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (archives.nicira.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id 3s0d0g0tmXz9t1M for ; Fri, 29 Jul 2016 02:41:23 +1000 (AEST) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id 22B6F112AB; Thu, 28 Jul 2016 09:41:22 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v3.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id C1593111E9 for ; Thu, 28 Jul 2016 09:41:20 -0700 (PDT) Received: from bar6.cudamail.com (localhost [127.0.0.1]) by mx3v3.cudamail.com (Postfix) with ESMTPS id 5214F162575 for ; Thu, 28 Jul 2016 10:41:20 -0600 (MDT) X-ASG-Debug-ID: 1469724077-0b323747722b3590001-byXFYA Received: from mx1-pf1.cudamail.com ([192.168.24.1]) by bar6.cudamail.com with ESMTP id I86BLyXTLLKtLkLy (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Thu, 28 Jul 2016 10:41:17 -0600 (MDT) X-Barracuda-Envelope-From: guru@ovn.org X-Barracuda-RBL-Trusted-Forwarder: 192.168.24.1 Received: from unknown (HELO relay9-d.mail.gandi.net) (217.70.183.199) by mx1-pf1.cudamail.com with ESMTPS (DHE-RSA-AES256-SHA encrypted); 28 Jul 2016 16:41:16 -0000 Received-SPF: pass (mx1-pf1.cudamail.com: SPF record at ovn.org designates 217.70.183.199 as permitted sender) X-Barracuda-Apparent-Source-IP: 217.70.183.199 X-Barracuda-RBL-IP: 217.70.183.199 Received: from mfilter25-d.gandi.net (mfilter25-d.gandi.net [217.70.178.153]) by relay9-d.mail.gandi.net (Postfix) with ESMTP id A738E406E0 for ; Thu, 28 Jul 2016 18:41:14 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at mfilter25-d.gandi.net Received: from relay9-d.mail.gandi.net ([IPv6:::ffff:217.70.183.199]) by mfilter25-d.gandi.net (mfilter25-d.gandi.net [::ffff:10.0.15.180]) (amavisd-new, port 10024) with ESMTP id iMyw1OlZIhEF for ; Thu, 28 Jul 2016 18:41:09 +0200 (CEST) X-Originating-IP: 209.85.215.53 Received: from mail-lf0-f53.google.com (mail-lf0-f53.google.com [209.85.215.53]) (Authenticated sender: guru@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id A272140367 for ; Thu, 28 Jul 2016 18:41:09 +0200 (CEST) Received: by mail-lf0-f53.google.com with SMTP id f93so53656183lfi.2 for ; Thu, 28 Jul 2016 09:41:09 -0700 (PDT) X-Gm-Message-State: AEkoouvSgw/JUUjrP52YthUe3lunzGVf7VS2s3EbRKkpdo3v460tUvZPFczFB3BAMxiAwLqSBNQ9RrEdUTyDag== X-Received: by 10.25.166.2 with SMTP id p2mr12073021lfe.134.1469724068796; Thu, 28 Jul 2016 09:41:08 -0700 (PDT) MIME-Version: 1.0 Received: by 10.114.182.75 with HTTP; Thu, 28 Jul 2016 09:41:08 -0700 (PDT) In-Reply-To: <1469563048-2576-1-git-send-email-aserdean@cloudbasesolutions.com> References: <1469563048-2576-1-git-send-email-aserdean@cloudbasesolutions.com> X-CudaMail-Envelope-Sender: guru@ovn.org From: Guru Shetty Date: Thu, 28 Jul 2016 09:41:08 -0700 X-Gmail-Original-Message-ID: Message-ID: X-CudaMail-Whitelist-To: dev@openvswitch.org X-CudaMail-MID: CM-E1-727039665 X-CudaMail-DTE: 072816 X-CudaMail-Originating-IP: 217.70.183.199 To: Alin Serdean X-ASG-Orig-Subj: [##CM-E1-727039665##]Re: [ovs-dev] [PATCH v4] Windows: Local named pipe implementation X-Barracuda-Connect: UNKNOWN[192.168.24.1] X-Barracuda-Start-Time: 1469724077 X-Barracuda-Encrypted: ECDHE-RSA-AES256-GCM-SHA384 X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-ASG-Whitelist: Header =?UTF-8?B?eFwtY3VkYW1haWxcLXdoaXRlbGlzdFwtdG8=?= X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 X-Content-Filtered-By: Mailman/MimeDel 2.1.16 Cc: "dev@openvswitch.org" Subject: Re: [ovs-dev] [PATCH v4] Windows: Local named pipe implementation X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@openvswitch.org Sender: "dev" On 26 July 2016 at 12:57, Alin Serdean 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 > Acked-by: Paul Boca > 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 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#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 /.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 > 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