Index: Lib/socket.py =================================================================== --- Lib/socket.py (revision 85491) +++ Lib/socket.py (working copy) @@ -132,6 +132,17 @@ fd, addr = self._accept() return socket(self.family, self.type, self.proto, fileno=fd), addr + if hasattr(_socket.socket, "_accept4"): + def accept4(self, flags): + """accept4() -> (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._accept4(flags) + return socket(self.family, self.type, self.proto, fileno=fd), addr + def makefile(self, mode="r", buffering=None, *, encoding=None, errors=None, newline=None): """makefile(...) -> an I/O stream connected to the socket Index: Modules/socketmodule.c =================================================================== --- Modules/socketmodule.c (revision 85491) +++ Modules/socketmodule.c (working copy) @@ -1657,9 +1657,7 @@ PyObject *addr = NULL; PyObject *res = NULL; int timeout; -#ifdef HAVE_ACCEPT4 - int flags = 0; -#endif + if (!getsockaddrlen(s, &addrlen)) return NULL; memset(&addrbuf, 0, addrlen); @@ -1670,15 +1668,8 @@ BEGIN_SELECT_LOOP(s) Py_BEGIN_ALLOW_THREADS timeout = internal_select_ex(s, 0, interval); - if (!timeout) { -#ifdef HAVE_ACCEPT4 - /* inherit socket flags and use accept4 call */ - flags = s->sock_type & (SOCK_CLOEXEC | SOCK_NONBLOCK); - newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen, flags); -#else + if (!timeout) newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); -#endif /* HAVE_ACCEPT4 */ - } Py_END_ALLOW_THREADS if (timeout == 1) { @@ -1716,6 +1707,82 @@ representing the connection, and the address of the client.\n\ For IP sockets, the address info is a pair (hostaddr, port)."); + +#ifdef HAVE_ACCEPT4 +/* s._accept4(flags) -> (fd, address) */ + +static PyObject * +sock_accept4(PySocketSockObject *s, PyObject *arg) +{ + sock_addr_t addrbuf; + SOCKET_T newfd = INVALID_SOCKET; + socklen_t addrlen; + PyObject *sock = NULL; + PyObject *addr = NULL; + PyObject *res = NULL; + int timeout, flags; + + /* Get flags value */ + flags = PyLong_AsLong(arg); + if (flags == -1 && PyErr_Occurred()) + return NULL; + /* Check flags value */ + if(flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) { + PyErr_SetString(PyExc_ValueError, + "Wrong flag value"); + return NULL; + } + if (!getsockaddrlen(s, &addrlen)) + return NULL; + memset(&addrbuf, 0, addrlen); + + if (!IS_SELECTABLE(s)) + return select_error(); + + BEGIN_SELECT_LOOP(s) + Py_BEGIN_ALLOW_THREADS + timeout = internal_select_ex(s, 0, interval); + if (!timeout) + newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen, flags); + Py_END_ALLOW_THREADS + + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + return NULL; + } + END_SELECT_LOOP(s) + + if (newfd == INVALID_SOCKET) + return s->errorhandler(); + + sock = PyLong_FromSocket_t(newfd); + if (sock == NULL) { + SOCKETCLOSE(newfd); + goto finally; + } + + addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), + addrlen, s->sock_proto); + if (addr == NULL) + goto finally; + + res = PyTuple_Pack(2, sock, addr); + +finally: + Py_XDECREF(sock); + Py_XDECREF(addr); + return res; +} + +PyDoc_STRVAR(accept4_doc, +"_accept4(flags) -> (integer, address info)\n\ +\n\ +Wait for an incoming connection. Return a new socket file descriptor\n\ +representing the connection, and the address of the client.\n\ +For IP sockets, the address info is a pair (hostaddr, port)."); +#endif /* HAVE_ACCEPT4 */ + + /* s.setblocking(flag) method. Argument: False -- non-blocking mode; same as settimeout(0) True -- blocking mode; same as settimeout(None) @@ -2863,6 +2930,10 @@ static PyMethodDef sock_methods[] = { {"_accept", (PyCFunction)sock_accept, METH_NOARGS, accept_doc}, +#ifdef HAVE_ACCEPT4 + {"_accept4", (PyCFunction)sock_accept4, METH_O, + accept4_doc}, +#endif {"bind", (PyCFunction)sock_bind, METH_O, bind_doc}, {"close", (PyCFunction)sock_close, METH_NOARGS, @@ -3001,6 +3072,10 @@ PyErr_SetString(PyExc_ValueError, "can't use invalid socket value"); return -1; +#ifdef HAVE_ACCEPT4 + /* These flags are not inherited after accept */ + type &= ~(SOCK_NONBLOCK & SOCK_CLOEXEC); +#endif /* HAVE_ACCEPT4 */ } } else {