Index: Include/longobject.h
===================================================================
--- Include/longobject.h (revision 58987)
+++ Include/longobject.h (working copy)
@@ -26,6 +26,15 @@
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *);
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *);
+/* Used by socketmodule.c */
+#if SIZEOF_SOCKET_T <= SIZEOF_LONG
+#define PyLong_FromSocket_t(fd) PyLong_FromLong((SOCKET_T)(fd))
+#define PyLong_AsSocket_t(fd) (SOCKET_T)PyLong_AsLong(fd)
+#else
+#define PyLong_FromSocket_t(fd) PyLong_FromLongLong(((SOCKET_T)(fd));
+#define PyLong_AsSocket_t(fd) (SOCKET_T)PyLong_AsLongLong(fd)
+#endif
+
/* For use by intobject.c only */
PyAPI_DATA(int) _PyLong_DigitValue[256];
Index: Lib/socket.py
===================================================================
--- Lib/socket.py (revision 58987)
+++ Lib/socket.py (working copy)
@@ -79,28 +79,19 @@
__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")
+def socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
+ """Factory function for socket objects."""
+ return Socket(family, type, proto, fileno)
-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):
+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 +105,27 @@
s[7:])
return s
+ def dup(self):
+ """dup() -> socket object
+
+ Return a new socket object connected to the same system resource.
+ """
+ fd = dup(self.fileno())
+ 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'.
@@ -148,8 +143,8 @@
rawmode += "r"
if writing:
rawmode += "w"
- raw = SocketIO(self, rawmode)
- self._io_refs += 1
+ sock = self.dup()
+ raw = SocketIO(sock, rawmode)
if buffering is None:
buffering = -1
if buffering < 0:
@@ -157,7 +152,7 @@
if buffering == 0:
if not binary:
raise ValueError("unbuffered streams must be binary")
- raw.name = self.fileno()
+ raw.name = sock.fileno()
raw.mode = mode
return raw
if reading and writing:
@@ -168,39 +163,25 @@
assert writing
buffer = io.BufferedWriter(raw, buffering)
if binary:
- buffer.name = self.fileno()
+ buffer.name = sock.fileno()
buffer.mode = mode
return buffer
text = io.TextIOWrapper(buffer, encoding, newline)
- text.name = self.fileno()
+ text.name = sock.fileno()
text.mode = mode
return text
- def _decref_socketios(self):
- if self._io_refs > 0:
- self._io_refs -= 1
- if self._closed:
- self.close()
- def close(self):
- self._closed = True
- if self._io_refs < 1:
- self._real_close()
+def fromfd(fd, family, type, proto=0):
+ """ fromfd(fd, family, type[, proto]) -> socket object
- # _real_close calls close on the _socket.socket base class.
+ Create a socket object from a duplicate of the given file
+ descriptor. The remaining arguments are the same as for socket().
+ """
+ nfd = dup(fd)
+ return Socket(family, type, proto, nfd)
- if not _can_dup_socket:
- def _real_close(self):
- _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):
"""Raw I/O implementation for stream sockets.
@@ -243,11 +224,9 @@
if self.closed:
return
io.RawIOBase.close(self)
+ self._sock = None
- def __del__(self):
- self._sock._decref_socketios()
-
def getfqdn(name=''):
"""Get fully qualified domain name from name.
@@ -289,7 +268,7 @@
af, socktype, proto, canonname, sa = res
sock = None
try:
- sock = socket(af, socktype, proto)
+ sock = Socket(af, socktype, proto)
if timeout is not None:
sock.settimeout(timeout)
sock.connect(sa)
Index: Lib/test/test_socket.py
===================================================================
--- Lib/test/test_socket.py (revision 58987)
+++ Lib/test/test_socket.py (working copy)
@@ -224,7 +224,7 @@
def test_repr(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.assert_(repr(s).startswith("