From e43f9d0ed69addbc34bac4af1b3ad7f1bdd3b149 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 8 Aug 2010 23:24:50 +0000 Subject: 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. --- Doc/library/socket.rst | 8 ++++++++ Doc/whatsnew/3.2.rst | 6 ++++++ Lib/ssl.py | 5 ++--- Lib/test/test_socket.py | 13 +++++++++++++ Misc/NEWS | 4 ++++ Modules/socketmodule.c | 17 +++++++++++++++++ 6 files changed, 50 insertions(+), 3 deletions(-) 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 @@ correspond to Unix system calls applicable to sockets. 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 @@ New, Improved, and Deprecated Modules (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 _ssl import ( 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 @@ class SSLSocket(socket): 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 @@ class SSLSocket(socket): 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 @@ class BasicTCPTest(SocketConnectedTest): 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 @@ Core and Builtins 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 @@ PyDoc_STRVAR(close_doc, \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 @@ static PyMethodDef sock_methods[] = { 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}, -- cgit v0.12