Guido van Rossum added the comment:

Here's a new version along the lines I described. Please test on
Windows. It works on Linux and OSX. What this includes:

- the dup-on-windows implementation by R Oudkerk, with the
GetLastError() suggestion from Thomas Heller.

- Replace the C implementations of dup() and accept() with _dup() and
_accept() that return file descriptors instead of socket objects.

- Implement accept() and dup() in Python using _accept() and _dup().

- Get rid of socket.fromfd(). You can use socket.socket(..., fileno=...)
instead (it doesn't dup though).

Added file: http://bugs.python.org/file8747/socket.diff

__________________________________
Tracker <[EMAIL PROTECTED]>
<http://bugs.python.org/issue1378>
__________________________________
Index: Doc/library/socket.rst
===================================================================
--- Doc/library/socket.rst	(revision 58970)
+++ Doc/library/socket.rst	(working copy)
@@ -299,19 +299,6 @@
    Availability: Unix.
 
 
-.. function:: fromfd(fd, family, type[, proto])
-
-   Duplicate the file descriptor *fd* (an integer as returned by a file object's
-   :meth:`fileno` method) and build a socket object from the result.  Address
-   family, socket type and protocol number are as for the :func:`socket` function
-   above. The file descriptor should refer to a socket, but this is not checked ---
-   subsequent operations on the object may fail if the file descriptor is invalid.
-   This function is rarely needed, but can be used to get or set socket options on
-   a socket passed to a program as standard input or output (such as a server
-   started by the Unix inet daemon).  The socket is assumed to be in blocking mode.
-   Availability: Unix.
-
-
 .. function:: ntohl(x)
 
    Convert 32-bit positive integers from network to host byte order.  On machines
Index: Lib/socket.py
===================================================================
--- Lib/socket.py	(revision 58970)
+++ Lib/socket.py	(working copy)
@@ -79,28 +79,14 @@
     __all__.append("errorTab")
 
 
-# True if os.dup() can duplicate socket descriptors.
-# (On Windows at least, os.dup only works on files)
-_can_dup_socket = hasattr(_socket.socket, "dup")
-
-if _can_dup_socket:
-    def fromfd(fd, family=AF_INET, type=SOCK_STREAM, proto=0):
-        nfd = os.dup(fd)
-        return socket(family, type, proto, fileno=nfd)
-
 class socket(_socket.socket):
 
     """A subclass of _socket.socket adding the makefile() method."""
 
     __slots__ = ["__weakref__", "_io_refs", "_closed"]
-    if not _can_dup_socket:
-        __slots__.append("_base")
 
     def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
-        if fileno is None:
-            _socket.socket.__init__(self, family, type, proto)
-        else:
-            _socket.socket.__init__(self, family, type, proto, fileno)
+        _socket.socket.__init__(self, family, type, proto, fileno)
         self._io_refs = 0
         self._closed = False
 
@@ -114,19 +100,15 @@
                                 s[7:])
         return s
 
+    def dup(self):
+        """Wrap _dup() result in a socket object."""
+        fd = self._dup()
+        return self.__class__(self.family, self.type, self.proto, fileno=fd)
+
     def accept(self):
-        """Wrap accept() to give the connection the right type."""
-        conn, addr = _socket.socket.accept(self)
-        fd = conn.fileno()
-        nfd = fd
-        if _can_dup_socket:
-            nfd = os.dup(fd)
-        wrapper = socket(self.family, self.type, self.proto, fileno=nfd)
-        if fd == nfd:
-            wrapper._base = conn  # Keep the base alive
-        else:
-            conn.close()
-        return wrapper, addr
+        """Wrap _accept() result in a socket object."""
+        fd, addr = self._accept()
+        return socket(self.family, self.type, self.proto, fileno=fd), addr
 
     def makefile(self, mode="r", buffering=None, *,
                  encoding=None, newline=None):
@@ -184,21 +166,8 @@
 
     def close(self):
         self._closed = True
-        if self._io_refs < 1:
-            self._real_close()
-
-    # _real_close calls close on the _socket.socket base class.
-
-    if not _can_dup_socket:
-        def _real_close(self):
+        if self._io_refs <= 0:
             _socket.socket.close(self)
-            base = getattr(self, "_base", None)
-            if base is not None:
-                self._base = None
-                base.close()
-    else:
-        def _real_close(self):
-            _socket.socket.close(self)
 
 
 class SocketIO(io.RawIOBase):
Index: Lib/test/test_socket.py
===================================================================
--- Lib/test/test_socket.py	(revision 58970)
+++ Lib/test/test_socket.py	(working copy)
@@ -563,16 +563,16 @@
         big_chunk = b'f' * 2048
         self.serv_conn.sendall(big_chunk)
 
-    def testFromFd(self):
-        # Testing fromfd()
-        if not hasattr(socket, "fromfd"):
-            return # On Windows, this doesn't exist
-        fd = self.cli_conn.fileno()
-        sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
+    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 _testFromFd(self):
+    def _testDup(self):
         self.serv_conn.send(MSG)
 
     def testShutdown(self):
Index: Modules/socketmodule.c
===================================================================
--- Modules/socketmodule.c	(revision 58970)
+++ Modules/socketmodule.c	(working copy)
@@ -89,12 +89,12 @@
 \n\
 Methods of socket objects (keyword arguments not allowed):\n\
 \n\
-accept() -- accept a connection, returning new socket and client address\n\
+_accept() -- accept connection, returning new socket fd and client address\n\
 bind(addr) -- bind the socket to a local address\n\
 close() -- close the socket\n\
 connect(addr) -- connect the socket to a remote address\n\
 connect_ex(addr) -- connect, return an error code instead of an exception\n\
-dup() -- return a new socket object identical to the current one [*]\n\
+_dup() -- return a new socket fd duplicated from fileno()\n\
 fileno() -- return underlying file descriptor\n\
 getpeername() -- return remote address [*]\n\
 getsockname() -- return local address\n\
@@ -324,10 +324,24 @@
 #include "getnameinfo.c"
 #endif
 
-#if defined(MS_WINDOWS)
-/* seem to be a few differences in the API */
+#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(GetLastError());
+		return INVALID_SOCKET;
+	}
+	return (SOCKET)newhandle;
+}
+#define dup(fd) duplicate_socket(fd)
 #define SOCKETCLOSE closesocket
-#define NO_DUP /* Actually it exists on NT 3.5, but what the heck... */
 #endif
 
 #ifdef MS_WIN32
@@ -701,7 +715,7 @@
 		pollfd.events = writing ? POLLOUT : POLLIN;
 
 		/* s->sock_timeout is in seconds, timeout in ms */
-		timeout = (int)(s->sock_timeout * 1000 + 0.5); 
+		timeout = (int)(s->sock_timeout * 1000 + 0.5);
 		n = poll(&pollfd, 1, timeout);
 	}
 #else
@@ -721,7 +735,7 @@
 			n = select(s->sock_fd+1, &fds, NULL, NULL, &tv);
 	}
 #endif
-	
+
 	if (n < 0)
 		return -1;
 	if (n == 0)
@@ -1496,7 +1510,7 @@
 }
 
 
-/* s.accept() method */
+/* s._accept() -> (fd, address) */
 
 static PyObject *
 sock_accept(PySocketSockObject *s)
@@ -1530,17 +1544,12 @@
 	if (newfd == INVALID_SOCKET)
 		return s->errorhandler();
 
-	/* Create the new object with unspecified family,
-	   to avoid calls to bind() etc. on it. */
-	sock = (PyObject *) new_sockobject(newfd,
-					   s->sock_family,
-					   s->sock_type,
-					   s->sock_proto);
-
+	sock = PyInt_FromLong(newfd);
 	if (sock == NULL) {
 		SOCKETCLOSE(newfd);
 		goto finally;
 	}
+
 	addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
 			    addrlen, s->sock_proto);
 	if (addr == NULL)
@@ -1555,11 +1564,11 @@
 }
 
 PyDoc_STRVAR(accept_doc,
-"accept() -> (socket object, address info)\n\
+"_accept() -> (integer, address info)\n\
 \n\
-Wait for an incoming connection.  Return a new socket representing the\n\
-connection, and the address of the client.  For IP sockets, the address\n\
-info is a pair (hostaddr, port).");
+Wait for an incoming connection.  Return a new socket file descriptor\n\
+representing the connection, and the address of the client.\n\
+For IP sockets, the address info is a pair (hostaddr, port).");
 
 /* s.setblocking(flag) method.  Argument:
    False -- non-blocking mode; same as settimeout(0)
@@ -1969,7 +1978,7 @@
 
 
 #ifndef NO_DUP
-/* s.dup() method */
+/* s._dup() method */
 
 static PyObject *
 sock_dup(PySocketSockObject *s)
@@ -1978,21 +1987,19 @@
 	PyObject *sock;
 
 	newfd = dup(s->sock_fd);
-	if (newfd < 0)
+	if (newfd == INVALID_SOCKET) {
 		return s->errorhandler();
-	sock = (PyObject *) new_sockobject(newfd,
-					   s->sock_family,
-					   s->sock_type,
-					   s->sock_proto);
+	}
+	sock = PyInt_FromLong(newfd);
 	if (sock == NULL)
 		SOCKETCLOSE(newfd);
 	return sock;
 }
 
 PyDoc_STRVAR(dup_doc,
-"dup() -> socket object\n\
+"_dup() -> integer\n\
 \n\
-Return a new socket object connected to the same system resource.");
+Return a new socket file descriptor connected to the same system resource.");
 
 #endif
 
@@ -2615,7 +2622,7 @@
 /* List of methods for socket objects */
 
 static PyMethodDef sock_methods[] = {
-	{"accept",	  (PyCFunction)sock_accept, METH_NOARGS,
+	{"_accept",	  (PyCFunction)sock_accept, METH_NOARGS,
 			  accept_doc},
 	{"bind",	  (PyCFunction)sock_bind, METH_O,
 			  bind_doc},
@@ -2626,7 +2633,7 @@
 	{"connect_ex",	  (PyCFunction)sock_connect_ex, METH_O,
 			  connect_ex_doc},
 #ifndef NO_DUP
-	{"dup",		  (PyCFunction)sock_dup, METH_NOARGS,
+	{"_dup",	  (PyCFunction)sock_dup, METH_NOARGS,
 			  dup_doc},
 #endif
 	{"fileno",	  (PyCFunction)sock_fileno, METH_NOARGS,
@@ -2745,7 +2752,7 @@
 					 &family, &type, &proto, &fdobj))
 		return -1;
 
-	if (fdobj != NULL) {
+	if (fdobj != NULL && fdobj != Py_None) {
 		fd = PyLong_AsLongLong(fdobj);
 		if (fd == (SOCKET_T)(-1) && PyErr_Occurred())
 			return -1;
@@ -4178,7 +4185,7 @@
 	PyModule_AddIntConstant(m, "NETLINK_IP6_FW", NETLINK_IP6_FW);
 #ifdef NETLINK_DNRTMSG
 	PyModule_AddIntConstant(m, "NETLINK_DNRTMSG", NETLINK_DNRTMSG);
-#endif 
+#endif
 #ifdef NETLINK_TAPBASE
 	PyModule_AddIntConstant(m, "NETLINK_TAPBASE", NETLINK_TAPBASE);
 #endif
_______________________________________________
Python-bugs-list mailing list 
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to