Commits

Amaury Forgeot d'Arc committed ea8199d

Add a cross-platform rsocket.dup(), which also works on win32.
py3k needs it, but it's not exposed in any way on 2.7.

Comments (0)

Files changed (3)

rpython/rlib/_rsocket_rffi.py

          ('iErrorCode', rffi.CFixedArray(rffi.INT, 10)), #FD_MAX_EVENTS
          ])
 
+    CConfig.WSAPROTOCOL_INFO = platform.Struct(
+        'struct WSAPROTOCOL_INFO',
+        [])  # Struct is just passed between functions
+    CConfig.FROM_PROTOCOL_INFO = platform.DefinedConstantInteger(
+        'FROM_PROTOCOL_INFO')
+
 CConfig.timeval = platform.Struct('struct timeval',
                                          [('tv_sec', rffi.LONG),
                                           ('tv_usec', rffi.LONG)])
                         rffi.INT)
     tcp_keepalive = cConfig.tcp_keepalive
 
+    WSAPROTOCOL_INFO = cConfig.WSAPROTOCOL_INFO
+    FROM_PROTOCOL_INFO = cConfig.FROM_PROTOCOL_INFO
+    WSADuplicateSocket = external('WSADuplicateSocket', 
+                                  [socketfd_type, rwin32.DWORD,
+                                   lltype.Ptr(WSAPROTOCOL_INFO)],
+                                  rffi.INT)
+    WSASocket = external('WSASocket', 
+                         [rffi.INT, rffi.INT, rffi.INT,
+                          lltype.Ptr(WSAPROTOCOL_INFO),
+                          rffi.DWORD, rffi.DWORD],
+                         socketfd_type)
+
 if WIN32:
     WSAData = cConfig.WSAData
     WSAStartup = external('WSAStartup', [rffi.INT, lltype.Ptr(WSAData)],

rpython/rlib/rsocket.py

         return (make_socket(fd0, family, type, proto, SocketClass),
                 make_socket(fd1, family, type, proto, SocketClass))
 
-if hasattr(_c, 'dup'):
+if _c.WIN32:
+    def dup(fd):
+        with lltype.scoped_alloc(_c.WSAData, zero=True) as info:
+            if _c.WSADuplicateSocket(fd, rwin32.GetCurrentProcessId(), info):
+                raise last_error()
+            result = _c.WSASocket(
+                _c.FROM_PROTOCOL_INFO, _c.FROM_PROTOCOL_INFO,
+                _c.FROM_PROTOCOL_INFO, info, 0, 0)
+            if result == INVALID_SOCKET:
+                raise last_error()
+            return result
+else:
+    def dup(fd):
+        return _c.dup(fd)
+
     def fromfd(fd, family, type, proto=0, SocketClass=RSocket):
         # Dup the fd so it and the socket can be closed independently
         fd = _c.dup(fd)

rpython/rlib/test/test_rsocket.py

     assert s.fd != s2.fd
     assert s.getsockname().eq(s2.getsockname())
 
+def test_c_dup():
+    # rsocket.dup() duplicates fd, it also works on Windows
+    # (but only on socket handles!)
+    s = RSocket(AF_INET, SOCK_STREAM)
+    s.setsockopt_int(SOL_SOCKET, SO_REUSEADDR, 1)
+    s.bind(INETAddress('localhost', 50007))
+    fd2 = dup(s.fd)
+    assert s.fd != fd2
+
 def test_inet_aton():
     assert inet_aton('1.2.3.4') == '\x01\x02\x03\x04'
     assert inet_aton('127.0.0.1') == '\x7f\x00\x00\x01'