mirror of
				https://github.com/python/cpython.git
				synced 2025-10-29 20:51:26 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									ba8a98600e
								
							
						
					
					
						commit
						e43f9d0ed6
					
				
					 6 changed files with 50 additions and 3 deletions
				
			
		|  | @ -548,6 +548,14 @@ correspond to Unix system calls applicable to sockets. | ||||||
|    this limitation. |    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() | .. method:: socket.getpeername() | ||||||
| 
 | 
 | ||||||
|    Return the remote address to which the socket is connected.  This is useful to |    Return the remote address to which the socket is connected.  This is useful to | ||||||
|  |  | ||||||
|  | @ -136,6 +136,12 @@ New, Improved, and Deprecated Modules | ||||||
| 
 | 
 | ||||||
|   (Contributed by Tarek Ziadé.) |   (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: | * The *sqlite3* module has some new features: | ||||||
| 
 | 
 | ||||||
|   * XXX *enable_load_extension* |   * XXX *enable_load_extension* | ||||||
|  |  | ||||||
|  | @ -79,7 +79,6 @@ | ||||||
| 
 | 
 | ||||||
| from socket import getnameinfo as _getnameinfo | from socket import getnameinfo as _getnameinfo | ||||||
| from socket import error as socket_error | from socket import error as socket_error | ||||||
| from socket import dup as _dup |  | ||||||
| from socket import socket, AF_INET, SOCK_STREAM | from socket import socket, AF_INET, SOCK_STREAM | ||||||
| import base64        # for DER-to-PEM translation | import base64        # for DER-to-PEM translation | ||||||
| import traceback | import traceback | ||||||
|  | @ -148,7 +147,7 @@ def __init__(self, sock=None, keyfile=None, certfile=None, | ||||||
|                             family=sock.family, |                             family=sock.family, | ||||||
|                             type=sock.type, |                             type=sock.type, | ||||||
|                             proto=sock.proto, |                             proto=sock.proto, | ||||||
|                             fileno=_dup(sock.fileno())) |                             fileno=sock.fileno()) | ||||||
|             self.settimeout(sock.gettimeout()) |             self.settimeout(sock.gettimeout()) | ||||||
|             # see if it's connected |             # see if it's connected | ||||||
|             try: |             try: | ||||||
|  | @ -158,7 +157,7 @@ def __init__(self, sock=None, keyfile=None, certfile=None, | ||||||
|                     raise |                     raise | ||||||
|             else: |             else: | ||||||
|                 connected = True |                 connected = True | ||||||
|             sock.close() |             sock.forget() | ||||||
|         elif fileno is not None: |         elif fileno is not None: | ||||||
|             socket.__init__(self, fileno=fileno) |             socket.__init__(self, fileno=fileno) | ||||||
|         else: |         else: | ||||||
|  |  | ||||||
|  | @ -655,6 +655,19 @@ def _testShutdown(self): | ||||||
|         self.serv_conn.send(MSG) |         self.serv_conn.send(MSG) | ||||||
|         self.serv_conn.shutdown(2) |         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.') | @unittest.skipUnless(thread, 'Threading required for this test.') | ||||||
| class BasicUDPTest(ThreadedUDPSocketTest): | class BasicUDPTest(ThreadedUDPSocketTest): | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -30,6 +30,10 @@ Core and Builtins | ||||||
| Extensions | 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 #477863: Print a warning at shutdown if gc.garbage is not empty. | ||||||
| 
 | 
 | ||||||
| - Issue #6869: Fix a refcount problem in the _ctypes extension. | - Issue #6869: Fix a refcount problem in the _ctypes extension. | ||||||
|  |  | ||||||
|  | @ -1869,6 +1869,21 @@ PyDoc_STRVAR(close_doc, | ||||||
| \n\ | \n\ | ||||||
| Close the socket.  It cannot be used after this call."); | 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 | static int | ||||||
| internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, | internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, | ||||||
|                  int *timeoutp) |                  int *timeoutp) | ||||||
|  | @ -2759,6 +2774,8 @@ static PyMethodDef sock_methods[] = { | ||||||
|                       connect_ex_doc}, |                       connect_ex_doc}, | ||||||
|     {"fileno",            (PyCFunction)sock_fileno, METH_NOARGS, |     {"fileno",            (PyCFunction)sock_fileno, METH_NOARGS, | ||||||
|                       fileno_doc}, |                       fileno_doc}, | ||||||
|  |     {"forget",            (PyCFunction)sock_forget, METH_NOARGS, | ||||||
|  |                       forget_doc}, | ||||||
| #ifdef HAVE_GETPEERNAME | #ifdef HAVE_GETPEERNAME | ||||||
|     {"getpeername",       (PyCFunction)sock_getpeername, |     {"getpeername",       (PyCFunction)sock_getpeername, | ||||||
|                       METH_NOARGS, getpeername_doc}, |                       METH_NOARGS, getpeername_doc}, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Antoine Pitrou
						Antoine Pitrou