[Python-checkins] bpo-32454: socket closefd (#5048)

Christian Heimes webhook-mailer at python.org
Sat Jan 27 03:54:16 EST 2018


https://github.com/python/cpython/commit/d0e31b980f18101738d0ec518cb991a5fb73fe93
commit: d0e31b980f18101738d0ec518cb991a5fb73fe93
branch: master
author: Christian Heimes <christian at python.org>
committer: GitHub <noreply at github.com>
date: 2018-01-27T09:54:13+01:00
summary:

bpo-32454: socket closefd (#5048)

Add close(fd) function to the socket module

Signed-off-by: Christian Heimes <christian at python.org>

files:
A Misc/NEWS.d/next/Library/2017-12-30-10-38-05.bpo-32454.wsZnl-.rst
M Doc/library/socket.rst
M Lib/test/test_socket.py
M Modules/socketmodule.c

diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
index db032ca7f1f..7edd4ba3604 100644
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -578,6 +578,14 @@ Other functions
 The :mod:`socket` module also offers various network-related services:
 
 
+.. function:: close(fd)
+
+   Close a socket file descriptor. This is like :func:`os.close`, but for
+   sockets. On some platforms (most noticeable Windows) :func:`os.close`
+   does not work for socket file descriptors.
+
+   .. versionadded:: 3.7
+
 .. function:: getaddrinfo(host, port, family=0, type=0, proto=0, flags=0)
 
    Translate the *host*/*port* argument into a sequence of 5-tuples that contain
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 22d142c8f80..275384c28fb 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1519,6 +1519,22 @@ def test_unusable_closed_socketio(self):
             self.assertRaises(ValueError, fp.writable)
             self.assertRaises(ValueError, fp.seekable)
 
+    def test_socket_close(self):
+        sock = socket.socket()
+        try:
+            sock.bind((HOST, 0))
+            socket.close(sock.fileno())
+            with self.assertRaises(OSError):
+                sock.listen(1)
+        finally:
+            with self.assertRaises(OSError):
+                # sock.close() fails with EBADF
+                sock.close()
+        with self.assertRaises(TypeError):
+            socket.close(None)
+        with self.assertRaises(OSError):
+            socket.close(-1)
+
     def test_makefile_mode(self):
         for mode in 'r', 'rb', 'rw', 'w', 'wb':
             with self.subTest(mode=mode):
diff --git a/Misc/NEWS.d/next/Library/2017-12-30-10-38-05.bpo-32454.wsZnl-.rst b/Misc/NEWS.d/next/Library/2017-12-30-10-38-05.bpo-32454.wsZnl-.rst
new file mode 100644
index 00000000000..b8eaa859fa5
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-12-30-10-38-05.bpo-32454.wsZnl-.rst
@@ -0,0 +1 @@
+Add close(fd) function to the socket module.
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index d75a51af9a6..5fe2431bee8 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -2836,7 +2836,7 @@ sock_close(PySocketSockObject *s)
     Py_RETURN_NONE;
 }
 
-PyDoc_STRVAR(close_doc,
+PyDoc_STRVAR(sock_close_doc,
 "close()\n\
 \n\
 Close the socket.  It cannot be used after this call.");
@@ -4558,7 +4558,7 @@ static PyMethodDef sock_methods[] = {
     {"bind",              (PyCFunction)sock_bind, METH_O,
                       bind_doc},
     {"close",             (PyCFunction)sock_close, METH_NOARGS,
-                      close_doc},
+                      sock_close_doc},
     {"connect",           (PyCFunction)sock_connect, METH_O,
                       connect_doc},
     {"connect_ex",        (PyCFunction)sock_connect_ex, METH_O,
@@ -5456,6 +5456,31 @@ PyDoc_STRVAR(getprotobyname_doc,
 \n\
 Return the protocol number for the named protocol.  (Rarely used.)");
 
+static PyObject *
+socket_close(PyObject *self, PyObject *fdobj)
+{
+    SOCKET_T fd;
+    int res;
+
+    fd = PyLong_AsSocket_t(fdobj);
+    if (fd == (SOCKET_T)(-1) && PyErr_Occurred())
+        return NULL;
+    Py_BEGIN_ALLOW_THREADS
+    res = SOCKETCLOSE(fd);
+    Py_END_ALLOW_THREADS
+    /* bpo-30319: The peer can already have closed the connection.
+       Python ignores ECONNRESET on close(). */
+    if (res < 0 && !CHECK_ERRNO(ECONNRESET)) {
+        return set_error();
+    }
+    Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(close_doc,
+"close(integer) -> None\n\
+\n\
+Close an integer socket file descriptor.  This is like os.close(), but for\n\
+sockets; on some platforms os.close() won't work for socket file descriptors.");
 
 #ifndef NO_DUP
 /* dup() function for socket fds */
@@ -6397,6 +6422,8 @@ static PyMethodDef socket_methods[] = {
      METH_VARARGS, getservbyport_doc},
     {"getprotobyname",          socket_getprotobyname,
      METH_VARARGS, getprotobyname_doc},
+    {"close",                   socket_close,
+     METH_O, close_doc},
 #ifndef NO_DUP
     {"dup",                     socket_dup,
      METH_O, dup_doc},



More information about the Python-checkins mailing list