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,23 +100,27 @@ s[7:]) return s + def dup(self): + """dup() -> socket object + + Return a new socket object connected to the same system resource. + """ + 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 + """accept() -> (socket object, address info) + Wait for an incoming connection. Return a new socket + representing the connection, and the address of the client. + For IP sockets, the address info is a pair (hostaddr, port). + """ + 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): - """Return an I/O stream connected to the socket. + """makefile(...) -> an I/O stream connected to the socket The arguments are as for io.open() after the filename, except the only mode characters supported are 'r', 'w' and 'b'. @@ -184,21 +174,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