--- socketmodule.c.original 2007-11-03 13:39:01.531961600 +0000 +++ socketmodule.c 2007-11-03 13:39:01.241544000 +0000 @@ -336,11 +336,32 @@ #include "getnameinfo.c" #endif -#if defined(MS_WINDOWS) || defined(__BEOS__) +#ifdef MS_WINDOWS +/* On Windows a socket is really a handle not an fd */ +static SOCKET +duplicate_socket(SOCKET handle) +{ + HANDLE newhandle; + + if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)handle, + GetCurrentProcess(), &newhandle, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + WSASetLastError(WSAEBADF); + return INVALID_SOCKET; + } + return (SOCKET)newhandle; +} +#define dup(fd) duplicate_socket(fd) +#define SOCKETCLOSE closesocket +#define NO_MAKEFILE /* socket handles can't be treated like file handles */ +#endif + +#ifdef __BEOS__ /* BeOS suffers from the same socket dichotomy as Win32... - [cjh] */ /* seem to be a few differences in the API */ #define SOCKETCLOSE closesocket -#define NO_DUP /* Actually it exists on NT 3.5, but what the heck... */ +#define NO_DUP #endif #ifdef MS_WIN32 @@ -357,6 +378,10 @@ #define SOCKETCLOSE close #endif +#ifdef NO_DUP +#define NO_MAKEFILE +#endif + #if defined(HAVE_BLUETOOTH_H) || defined(HAVE_BLUETOOTH_BLUETOOTH_H) #define USE_BLUETOOTH 1 #if defined(__FreeBSD__) @@ -2037,7 +2062,11 @@ PyObject *sock; newfd = dup(s->sock_fd); +#ifdef MS_WINDOWS + if (newfd == INVALID_SOCKET) +#else if (newfd < 0) +#endif return s->errorhandler(); sock = (PyObject *) new_sockobject(newfd, s->sock_family, @@ -2145,7 +2174,7 @@ will allow before refusing new connections."); -#ifndef NO_DUP +#ifndef NO_MAKEFILE /* s.makefile(mode) method. Create a new open file object referring to a dupped version of the socket's file descriptor. (The dup() call is necessary so @@ -2206,7 +2235,7 @@ Return a regular file object corresponding to the socket.\n\ The mode and buffersize arguments are as for the built-in open() function."); -#endif /* NO_DUP */ +#endif /* NO_MAKEFILE */ /* * This is the guts of the recv() and recv_into() methods, which reads into a @@ -2760,7 +2789,7 @@ getsockopt_doc}, {"listen", (PyCFunction)sock_listen, METH_O, listen_doc}, -#ifndef NO_DUP +#ifndef NO_MAKEFILE {"makefile", (PyCFunction)sock_makefile, METH_VARARGS, makefile_doc}, #endif @@ -3451,7 +3480,11 @@ return NULL; /* Dup the fd so it and the socket can be closed independently */ fd = dup(fd); +#ifdef MS_WINDOWS + if (fd == INVALID_SOCKET) +#else if (fd < 0) +#endif return set_error(); s = new_sockobject(fd, family, type, proto); return (PyObject *) s; --- test_socket.py.original 2007-11-01 14:29:22.352180800 +0000 +++ test_socket.py 2007-11-02 14:54:03.898873600 +0000 @@ -544,7 +544,7 @@ def testFromFd(self): # Testing fromfd() if not hasattr(socket, "fromfd"): - return # On Windows, this doesn't exist + return # On BeOS, OS/2 and RiscOS this doesn't exist fd = self.cli_conn.fileno() sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM) msg = sock.recv(1024) @@ -553,6 +553,27 @@ def _testFromFd(self): self.serv_conn.send(MSG) + def testDup(self): + # Testing dup() + sock = self.cli_conn.dup() + msg = sock.recv(1024) + self.assertEqual(msg, MSG) + + def _testDup(self): + self.serv_conn.send(MSG) + + def testInnerDup(self): + # Testing dup() for the wrapped socket object + inner = self.cli_conn._sock + if not hasattr(inner, "dup"): + return # On BeOS, OS/2 and RiscOS this doesn't exist + sock = inner.dup() + msg = sock.recv(1024) + self.assertEqual(msg, MSG) + + def _testInnerDup(self): + self.serv_conn.send(MSG) + def testShutdown(self): # Testing shutdown() msg = self.cli_conn.recv(1024)