Issue #8524: Add a forget() method to socket objects, so as to put the
socket into the closed state without closing the underlying file
descriptor.
diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
index 75d86b7..2b43266 100644
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -548,6 +548,14 @@
this limitation.
+.. method:: socket.forget()
+
+ Put the socket object into closed state without actually closing the
+ underlying file descriptor. This allows the latter to be reused.
+
+ .. versionadded:: 3.2
+
+
.. method:: socket.getpeername()
Return the remote address to which the socket is connected. This is useful to
diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst
index f4802a0..487298f 100644
--- a/Doc/whatsnew/3.2.rst
+++ b/Doc/whatsnew/3.2.rst
@@ -136,6 +136,12 @@
(Contributed by Tarek Ziadé.)
+* Socket objects now have a :meth:`~socket.socket.forget()` method which
+ puts the socket into closed state without actually closing the underlying
+ file descriptor. The latter can then be reused for other purposes.
+
+ (Added by Antoine Pitrou; :issue:`8524`.)
+
* The *sqlite3* module has some new features:
* XXX *enable_load_extension*
diff --git a/Lib/ssl.py b/Lib/ssl.py
index 585105d..7bcc67e 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -79,7 +79,6 @@
from socket import getnameinfo as _getnameinfo
from socket import error as socket_error
-from socket import dup as _dup
from socket import socket, AF_INET, SOCK_STREAM
import base64 # for DER-to-PEM translation
import traceback
@@ -148,7 +147,7 @@
family=sock.family,
type=sock.type,
proto=sock.proto,
- fileno=_dup(sock.fileno()))
+ fileno=sock.fileno())
self.settimeout(sock.gettimeout())
# see if it's connected
try:
@@ -158,7 +157,7 @@
raise
else:
connected = True
- sock.close()
+ sock.forget()
elif fileno is not None:
socket.__init__(self, fileno=fileno)
else:
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 25025dd..ae34c11 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -655,6 +655,19 @@
self.serv_conn.send(MSG)
self.serv_conn.shutdown(2)
+ def testForget(self):
+ # Testing forget()
+ f = self.cli_conn.fileno()
+ self.cli_conn.forget()
+ self.assertRaises(socket.error, self.cli_conn.recv, 1024)
+ self.cli_conn.close()
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, fileno=f)
+ msg = sock.recv(1024)
+ self.assertEqual(msg, MSG)
+
+ def _testForget(self):
+ self.serv_conn.send(MSG)
+
@unittest.skipUnless(thread, 'Threading required for this test.')
class BasicUDPTest(ThreadedUDPSocketTest):
diff --git a/Misc/NEWS b/Misc/NEWS
index 46ddfef..00188d4 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -30,6 +30,10 @@
Extensions
----------
+- Issue #8524: Add a forget() method to socket objects, so as to put the
+ socket into the closed state without closing the underlying file
+ descriptor.
+
- Issue #477863: Print a warning at shutdown if gc.garbage is not empty.
- Issue #6869: Fix a refcount problem in the _ctypes extension.
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 563bdea..fc671e0 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1869,6 +1869,21 @@
\n\
Close the socket. It cannot be used after this call.");
+static PyObject *
+sock_forget(PySocketSockObject *s)
+{
+ s->sock_fd = -1;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(forget_doc,
+"forget()\n\
+\n\
+Close the socket object without closing the underlying file descriptor.\
+The object cannot be used after this call, but the file descriptor\
+can be reused for other purposes.");
+
static int
internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
int *timeoutp)
@@ -2759,6 +2774,8 @@
connect_ex_doc},
{"fileno", (PyCFunction)sock_fileno, METH_NOARGS,
fileno_doc},
+ {"forget", (PyCFunction)sock_forget, METH_NOARGS,
+ forget_doc},
#ifdef HAVE_GETPEERNAME
{"getpeername", (PyCFunction)sock_getpeername,
METH_NOARGS, getpeername_doc},