diff mbox

[ovs-dev,V11,11/17] python tests: Ported UNIX sockets to Windows

Message ID 1470159883-4648-12-git-send-email-pboca@cloudbasesolutions.com
State Changes Requested
Headers show

Commit Message

Paul Boca Aug. 2, 2016, 5:45 p.m. UTC
AF_UNIX sockets are not supported on Windows.
Instead of an AF_UNIX socket use localhost tcp connections to communicate
between components. This makes the python sockets compatible with
the ones used in Windows applications.

In case the socket returns WSAEWOULDBLOCK, it is replaced by EAGAIN error
in order to be compatible with Windows.

Signed-off-by: Paul-Daniel Boca <pboca@cloudbasesolutions.com>
Acked-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com>
---
V2: Fixed Python function inet_open_active, treat WSAEWOULDBLOCK error as
    EINPROGRESS on Windows
V3: Use context managers for file handle leaks
V4: No changes
V5: No changes
V6: No changes
V7: Fix for JSON-RPC tests - treat WSAEWOULDBLOCK error as EAGAIN
    for compatibility
V8: No changes
V9: No changes
V10: No changes
V11: No changes
---
 python/ovs/jsonrpc.py        |  4 ++++
 python/ovs/socket_util.py    | 56 +++++++++++++++++++++++++++++++++++++-------
 python/ovs/stream.py         |  9 +++++--
 python/ovs/unixctl/server.py |  6 +++--
 4 files changed, 62 insertions(+), 13 deletions(-)

Comments

Gurucharan Shetty Aug. 3, 2016, 4 p.m. UTC | #1
On 2 August 2016 at 10:45, Paul Boca <pboca@cloudbasesolutions.com> wrote:

> AF_UNIX sockets are not supported on Windows.
> Instead of an AF_UNIX socket use localhost tcp connections to communicate
> between components. This makes the python sockets compatible with
> the ones used in Windows applications.
>
> In case the socket returns WSAEWOULDBLOCK, it is replaced by EAGAIN error
> in order to be compatible with Windows.
>
> Signed-off-by: Paul-Daniel Boca <pboca@cloudbasesolutions.com>
> Acked-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com>
>

I am skipping this. I suppose this does not work anymore as the servers can
use named pipes.


> ---
> V2: Fixed Python function inet_open_active, treat WSAEWOULDBLOCK error as
>     EINPROGRESS on Windows
> V3: Use context managers for file handle leaks
> V4: No changes
> V5: No changes
> V6: No changes
> V7: Fix for JSON-RPC tests - treat WSAEWOULDBLOCK error as EAGAIN
>     for compatibility
> V8: No changes
> V9: No changes
> V10: No changes
> V11: No changes
> ---
>  python/ovs/jsonrpc.py        |  4 ++++
>  python/ovs/socket_util.py    | 56
> +++++++++++++++++++++++++++++++++++++-------
>  python/ovs/stream.py         |  9 +++++--
>  python/ovs/unixctl/server.py |  6 +++--
>  4 files changed, 62 insertions(+), 13 deletions(-)
>
> diff --git a/python/ovs/jsonrpc.py b/python/ovs/jsonrpc.py
> index 6300c67..1bc3493 100644
> --- a/python/ovs/jsonrpc.py
> +++ b/python/ovs/jsonrpc.py
> @@ -14,6 +14,7 @@
>
>  import errno
>  import os
> +import sys
>
>  import six
>
> @@ -274,6 +275,9 @@ class Connection(object):
>                      except UnicodeError:
>                          error = errno.EILSEQ
>                  if error:
> +                    if (sys.platform == "win32"
> +                       and error == errno.WSAEWOULDBLOCK):
> +                        error = errno.EAGAIN
>                      if error == errno.EAGAIN:
>                          return error, None
>                      else:
> diff --git a/python/ovs/socket_util.py b/python/ovs/socket_util.py
> index b358b05..949d27a 100644
> --- a/python/ovs/socket_util.py
> +++ b/python/ovs/socket_util.py
> @@ -17,6 +17,7 @@ import os
>  import os.path
>  import random
>  import socket
> +import sys
>
>  import six
>  from six.moves import range
> @@ -54,6 +55,26 @@ def free_short_name(short_name):
>      ovs.fatal_signal.unlink_file_now(link_name)
>
>
> +def compat_read_unix_socket(path):
> +    try:
> +        with open(path, "r+") as file_handle:
> +            ret = int(file_handle.readline())
> +    except IOError as e:
> +        vlog.warn("%s: open: %s" % (path, e.strerror))
> +        raise socket.error(errno.ENOENT)
> +
> +    return ret
> +
> +
> +def compat_write_unix_socket(path, port):
> +    try:
> +        with open(path, "w") as file_handle:
> +            file_handle.write(str(port))
> +    except IOError as e:
> +        vlog.warn("%s: open: %s" % (path, e.strerror))
> +        raise socket.error(errno.ENOENT)
> +
> +
>  def make_unix_socket(style, nonblock, bind_path, connect_path,
> short=False):
>      """Creates a Unix domain socket in the given 'style' (either
>      socket.SOCK_DGRAM or socket.SOCK_STREAM) that is bound to 'bind_path'
> (if
> @@ -65,7 +86,10 @@ def make_unix_socket(style, nonblock, bind_path,
> connect_path, short=False):
>      None."""
>
>      try:
> -        sock = socket.socket(socket.AF_UNIX, style)
> +        if sys.platform == "win32":
> +            sock = socket.socket(socket.AF_INET, style)
> +        else:
> +            sock = socket.socket(socket.AF_UNIX, style)
>      except socket.error as e:
>          return get_exception_errno(e), None
>
> @@ -81,17 +105,28 @@ def make_unix_socket(style, nonblock, bind_path,
> connect_path, short=False):
>                      return e.errno, None
>
>              ovs.fatal_signal.add_file_to_unlink(bind_path)
> -            sock.bind(bind_path)
> +            if sys.platform == "win32":
> +                sock.bind(("127.0.0.1", 0))
> +                compat_write_unix_socket(bind_path, sock.getsockname()[1])
> +            else:
> +                sock.bind(bind_path)
>
> -            try:
> -                os.fchmod(sock.fileno(), 0o700)
> -            except OSError as e:
> -                pass
> +                try:
> +                    os.fchmod(sock.fileno(), 0o700)
> +                except OSError as e:
> +                    pass
>          if connect_path is not None:
>              try:
> -                sock.connect(connect_path)
> +                if sys.platform == "win32":
> +                    port = compat_read_unix_socket(connect_path)
> +                    sock.connect(("127.0.0.1", port))
> +                else:
> +                    sock.connect(connect_path)
>              except socket.error as e:
> -                if get_exception_errno(e) != errno.EINPROGRESS:
> +                error = get_exception_errno(e)
> +                if sys.platform == "win32" and error ==
> errno.WSAEWOULDBLOCK:
> +                    error = errno.EINPROGRESS
> +                if error != errno.EINPROGRESS:
>                      raise
>          return 0, sock
>      except socket.error as e:
> @@ -228,7 +263,10 @@ def inet_open_active(style, target, default_port,
> dscp):
>          try:
>              sock.connect(address)
>          except socket.error as e:
> -            if get_exception_errno(e) != errno.EINPROGRESS:
> +            error = get_exception_errno(e)
> +            if sys.platform == "win32" and error == errno.WSAEWOULDBLOCK:
> +                error = errno.EINPROGRESS
> +            if error != errno.EINPROGRESS:
>                  raise
>          return 0, sock
>      except socket.error as e:
> diff --git a/python/ovs/stream.py b/python/ovs/stream.py
> index 97b22ac..b3aa5d9 100644
> --- a/python/ovs/stream.py
> +++ b/python/ovs/stream.py
> @@ -15,7 +15,7 @@
>  import errno
>  import os
>  import socket
> -
> +import sys
>  import six
>
>  import ovs.poller
> @@ -136,6 +136,8 @@ class Stream(object):
>          if not error:
>              while True:
>                  error = stream.connect()
> +                if sys.platform == "win32" and error ==
> errno.WSAEWOULDBLOCK:
> +                    error = errno.EAGAIN
>                  if error != errno.EAGAIN:
>                      break
>                  stream.run()
> @@ -338,12 +340,15 @@ class PassiveStream(object):
>              try:
>                  sock, addr = self.socket.accept()
>                  ovs.socket_util.set_nonblocking(sock)
> -                if (sock.family == socket.AF_UNIX):
> +                if (sys.platform != "win32"
> +                   and sock.family == socket.AF_UNIX):
>                      return 0, Stream(sock, "unix:%s" % addr, 0)
>                  return 0, Stream(sock, 'ptcp:%s:%s' % (addr[0],
>                                                         str(addr[1])), 0)
>              except socket.error as e:
>                  error = ovs.socket_util.get_exception_errno(e)
> +                if sys.platform == "win32" and error ==
> errno.WSAEWOULDBLOCK:
> +                    error = errno.EAGAIN
>                  if error != errno.EAGAIN:
>                      # XXX rate-limit
>                      vlog.dbg("accept: %s" % os.strerror(error))
> diff --git a/python/ovs/unixctl/server.py b/python/ovs/unixctl/server.py
> index 8595ed8..749a335 100644
> --- a/python/ovs/unixctl/server.py
> +++ b/python/ovs/unixctl/server.py
> @@ -148,6 +148,8 @@ class UnixctlServer(object):
>      def run(self):
>          for _ in range(10):
>              error, stream = self._listener.accept()
> +            if sys.platform == "win32" and error == errno.WSAEWOULDBLOCK:
> +                error = errno.EAGAIN
>              if not error:
>                  rpc = ovs.jsonrpc.Connection(stream)
>                  self._conns.append(UnixctlConnection(rpc))
> @@ -155,8 +157,8 @@ class UnixctlServer(object):
>                  break
>              else:
>                  # XXX: rate-limit
> -                vlog.warn("%s: accept failed: %s" % (self._listener.name,
> -                                                     os.strerror(error)))
> +                vlog.warn("%s: accept failed: %s %d %d"
> +                          % (self._listener.name, os.strerror(error),
> error))
>
>          for conn in copy.copy(self._conns):
>              error = conn.run()
> --
> 2.7.2.windows.1
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>
diff mbox

Patch

diff --git a/python/ovs/jsonrpc.py b/python/ovs/jsonrpc.py
index 6300c67..1bc3493 100644
--- a/python/ovs/jsonrpc.py
+++ b/python/ovs/jsonrpc.py
@@ -14,6 +14,7 @@ 
 
 import errno
 import os
+import sys
 
 import six
 
@@ -274,6 +275,9 @@  class Connection(object):
                     except UnicodeError:
                         error = errno.EILSEQ
                 if error:
+                    if (sys.platform == "win32"
+                       and error == errno.WSAEWOULDBLOCK):
+                        error = errno.EAGAIN
                     if error == errno.EAGAIN:
                         return error, None
                     else:
diff --git a/python/ovs/socket_util.py b/python/ovs/socket_util.py
index b358b05..949d27a 100644
--- a/python/ovs/socket_util.py
+++ b/python/ovs/socket_util.py
@@ -17,6 +17,7 @@  import os
 import os.path
 import random
 import socket
+import sys
 
 import six
 from six.moves import range
@@ -54,6 +55,26 @@  def free_short_name(short_name):
     ovs.fatal_signal.unlink_file_now(link_name)
 
 
+def compat_read_unix_socket(path):
+    try:
+        with open(path, "r+") as file_handle:
+            ret = int(file_handle.readline())
+    except IOError as e:
+        vlog.warn("%s: open: %s" % (path, e.strerror))
+        raise socket.error(errno.ENOENT)
+
+    return ret
+
+
+def compat_write_unix_socket(path, port):
+    try:
+        with open(path, "w") as file_handle:
+            file_handle.write(str(port))
+    except IOError as e:
+        vlog.warn("%s: open: %s" % (path, e.strerror))
+        raise socket.error(errno.ENOENT)
+
+
 def make_unix_socket(style, nonblock, bind_path, connect_path, short=False):
     """Creates a Unix domain socket in the given 'style' (either
     socket.SOCK_DGRAM or socket.SOCK_STREAM) that is bound to 'bind_path' (if
@@ -65,7 +86,10 @@  def make_unix_socket(style, nonblock, bind_path, connect_path, short=False):
     None."""
 
     try:
-        sock = socket.socket(socket.AF_UNIX, style)
+        if sys.platform == "win32":
+            sock = socket.socket(socket.AF_INET, style)
+        else:
+            sock = socket.socket(socket.AF_UNIX, style)
     except socket.error as e:
         return get_exception_errno(e), None
 
@@ -81,17 +105,28 @@  def make_unix_socket(style, nonblock, bind_path, connect_path, short=False):
                     return e.errno, None
 
             ovs.fatal_signal.add_file_to_unlink(bind_path)
-            sock.bind(bind_path)
+            if sys.platform == "win32":
+                sock.bind(("127.0.0.1", 0))
+                compat_write_unix_socket(bind_path, sock.getsockname()[1])
+            else:
+                sock.bind(bind_path)
 
-            try:
-                os.fchmod(sock.fileno(), 0o700)
-            except OSError as e:
-                pass
+                try:
+                    os.fchmod(sock.fileno(), 0o700)
+                except OSError as e:
+                    pass
         if connect_path is not None:
             try:
-                sock.connect(connect_path)
+                if sys.platform == "win32":
+                    port = compat_read_unix_socket(connect_path)
+                    sock.connect(("127.0.0.1", port))
+                else:
+                    sock.connect(connect_path)
             except socket.error as e:
-                if get_exception_errno(e) != errno.EINPROGRESS:
+                error = get_exception_errno(e)
+                if sys.platform == "win32" and error == errno.WSAEWOULDBLOCK:
+                    error = errno.EINPROGRESS
+                if error != errno.EINPROGRESS:
                     raise
         return 0, sock
     except socket.error as e:
@@ -228,7 +263,10 @@  def inet_open_active(style, target, default_port, dscp):
         try:
             sock.connect(address)
         except socket.error as e:
-            if get_exception_errno(e) != errno.EINPROGRESS:
+            error = get_exception_errno(e)
+            if sys.platform == "win32" and error == errno.WSAEWOULDBLOCK:
+                error = errno.EINPROGRESS
+            if error != errno.EINPROGRESS:
                 raise
         return 0, sock
     except socket.error as e:
diff --git a/python/ovs/stream.py b/python/ovs/stream.py
index 97b22ac..b3aa5d9 100644
--- a/python/ovs/stream.py
+++ b/python/ovs/stream.py
@@ -15,7 +15,7 @@ 
 import errno
 import os
 import socket
-
+import sys
 import six
 
 import ovs.poller
@@ -136,6 +136,8 @@  class Stream(object):
         if not error:
             while True:
                 error = stream.connect()
+                if sys.platform == "win32" and error == errno.WSAEWOULDBLOCK:
+                    error = errno.EAGAIN
                 if error != errno.EAGAIN:
                     break
                 stream.run()
@@ -338,12 +340,15 @@  class PassiveStream(object):
             try:
                 sock, addr = self.socket.accept()
                 ovs.socket_util.set_nonblocking(sock)
-                if (sock.family == socket.AF_UNIX):
+                if (sys.platform != "win32"
+                   and sock.family == socket.AF_UNIX):
                     return 0, Stream(sock, "unix:%s" % addr, 0)
                 return 0, Stream(sock, 'ptcp:%s:%s' % (addr[0],
                                                        str(addr[1])), 0)
             except socket.error as e:
                 error = ovs.socket_util.get_exception_errno(e)
+                if sys.platform == "win32" and error == errno.WSAEWOULDBLOCK:
+                    error = errno.EAGAIN
                 if error != errno.EAGAIN:
                     # XXX rate-limit
                     vlog.dbg("accept: %s" % os.strerror(error))
diff --git a/python/ovs/unixctl/server.py b/python/ovs/unixctl/server.py
index 8595ed8..749a335 100644
--- a/python/ovs/unixctl/server.py
+++ b/python/ovs/unixctl/server.py
@@ -148,6 +148,8 @@  class UnixctlServer(object):
     def run(self):
         for _ in range(10):
             error, stream = self._listener.accept()
+            if sys.platform == "win32" and error == errno.WSAEWOULDBLOCK:
+                error = errno.EAGAIN
             if not error:
                 rpc = ovs.jsonrpc.Connection(stream)
                 self._conns.append(UnixctlConnection(rpc))
@@ -155,8 +157,8 @@  class UnixctlServer(object):
                 break
             else:
                 # XXX: rate-limit
-                vlog.warn("%s: accept failed: %s" % (self._listener.name,
-                                                     os.strerror(error)))
+                vlog.warn("%s: accept failed: %s %d %d"
+                          % (self._listener.name, os.strerror(error), error))
 
         for conn in copy.copy(self._conns):
             error = conn.run()