diff -r 7ed567ad8b4c -r f753a3b727b4 Modules/socketmodule.c --- a/Modules/socketmodule.c Tue Mar 31 22:03:59 2015 +0200 +++ b/Modules/socketmodule.c Wed Apr 01 00:41:54 2015 +0200 @@ -683,45 +683,90 @@ internal_connect_select(PySocketSockObje return internal_select_impl(s, 1, s->sock_timeout, 1); } -/* - Two macros for automatic retry of select() in case of false positives - (for example, select() could indicate a socket is ready for reading - but the data then discarded by the OS because of a wrong checksum). - Here is an example of use: - - BEGIN_SELECT_LOOP(s) - - timeout = internal_select(s, 0, interval); - - if (!timeout) { - Py_BEGIN_ALLOW_THREADS - outlen = recv(s->sock_fd, cbuf, len, flags); - Py_END_ALLOW_THREADS - } - if (timeout == 1) { - PyErr_SetString(socket_timeout, "timed out"); +/* Call a socket function. + + If the socket has a timeout, wait until the socket is ready before calling + the function: wait until the socket is writable if writing is nonzero, wait + until the socket received data otherwise. + + If the function is interrupted by a signal (failed with EINTR): retry the + function, except if the signal handler raised an exception (PEP 475). + + When the function is retried, recompute the timeout using a monotonic clock. + + Raise an exception and return -1 on error, return 0 on success. */ + +static int +sock_call(PySocketSockObject *s, + int writing, + int (*func) (PySocketSockObject *s, void *data), + void *data) +{ + int has_timeout = (s->sock_timeout > 0); + _PyTime_t deadline = 0; + int deadline_initialized = 0; + + while (1) { + int timeout; + + if (has_timeout) { + _PyTime_t interval; + + if (deadline_initialized) { + interval = deadline - _PyTime_GetMonotonicClock(); + } + else { + deadline = _PyTime_GetMonotonicClock() + s->sock_timeout; + interval = s->sock_timeout; + } + timeout = internal_select(s, writing, interval); + + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + return -1; + } + } + else { + timeout = 0; + } + + if (!timeout) { + int res = func(s, data); + if (res) + break; + /* func() failed */ + } + + if (CHECK_ERRNO(EINTR)) { + /* select() or func() was interrupted by a signal */ + if (PyErr_CheckSignals()) + return -1; + + /* retry select() or func() */ + continue; + } + + if (s->sock_timeout > 0 + && (CHECK_ERRNO(EWOULDBLOCK) || CHECK_ERRNO(EAGAIN))) { + /* False positive: select() or func() failed with EWOULDBLOCK or + EAGAIN (and the socket has a timeout). + + For example, select() could indicate a socket is ready for + reading, but the data then discarded by the OS because of a + wrong checksum. + + Retry the function. */ + continue; + } + + s->errorhandler(); return -1; } - END_SELECT_LOOP(s) -*/ - -#define BEGIN_SELECT_LOOP(s) \ - { \ - _PyTime_t deadline = 0; \ - _PyTime_t interval = s->sock_timeout; \ - int has_timeout = (s->sock_timeout > 0); \ - if (has_timeout) \ - deadline = _PyTime_GetMonotonicClock() + interval; \ - while (1) { \ - errno = 0; \ - -#define END_SELECT_LOOP(s) \ - if (!has_timeout || \ - (!CHECK_ERRNO(EWOULDBLOCK) && !CHECK_ERRNO(EAGAIN))) \ - break; \ - interval = deadline - _PyTime_GetMonotonicClock(); \ - } \ - } \ + + /* func() succeeded */ + return 0; +} + /* Initialize a new socket object. */ @@ -2061,62 +2106,62 @@ get_cmsg_data_len(struct msghdr *msg, st #endif /* CMSG_LEN */ +struct sock_accept { + socklen_t addrlen; + sock_addr_t addrbuf; + SOCKET_T newfd; +}; + +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) +/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */ +static int accept4_works = -1; +#endif + +static int +sock_accept_impl(PySocketSockObject *s, void *data) +{ + struct sock_accept *ctx = data; + + Py_BEGIN_ALLOW_THREADS +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) + if (accept4_works != 0) { + ctx->newfd = accept4(s->sock_fd, SAS2SA(&ctx->addrbuf), &ctx->addrlen, + SOCK_CLOEXEC); + if (ctx->newfd == INVALID_SOCKET && accept4_works == -1) { + /* On Linux older than 2.6.28, accept4() fails with ENOSYS */ + accept4_works = (errno != ENOSYS); + } + } + if (accept4_works == 0) + ctx->newfd = accept(s->sock_fd, SAS2SA(&ctx->addrbuf), &ctx->addrlen); +#else + ctx->newfd = accept(s->sock_fd, SAS2SA(&ctx->addrbuf), &ctx->addrlen); +#endif + Py_END_ALLOW_THREADS + + return (ctx->newfd >= 0); +} + /* s._accept() -> (fd, address) */ static PyObject * sock_accept(PySocketSockObject *s) { - sock_addr_t addrbuf; - SOCKET_T newfd = INVALID_SOCKET; - socklen_t addrlen; PyObject *sock = NULL; PyObject *addr = NULL; PyObject *res = NULL; - int timeout; - int async_err = 0; -#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) - /* accept4() is available on Linux 2.6.28+ and glibc 2.10 */ - static int accept4_works = -1; -#endif - - if (!getsockaddrlen(s, &addrlen)) + struct sock_accept ctx; + + if (!getsockaddrlen(s, &ctx.addrlen)) return NULL; - memset(&addrbuf, 0, addrlen); + memset(&ctx.addrbuf, 0, ctx.addrlen); + ctx.newfd = INVALID_SOCKET; if (!IS_SELECTABLE(s)) return select_error(); - BEGIN_SELECT_LOOP(s) - do { - timeout = internal_select(s, 0, interval); - - if (!timeout) { - Py_BEGIN_ALLOW_THREADS -#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) - if (accept4_works != 0) { - newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen, - SOCK_CLOEXEC); - if (newfd == INVALID_SOCKET && accept4_works == -1) { - /* On Linux older than 2.6.28, accept4() fails with ENOSYS */ - accept4_works = (errno != ENOSYS); - } - } - if (accept4_works == 0) - newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); -#else - newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); -#endif - Py_END_ALLOW_THREADS - } - } while (newfd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); - if (timeout == 1) { - PyErr_SetString(socket_timeout, "timed out"); + if (sock_call(s, 0, sock_accept_impl, &ctx) < 0) return NULL; - } - END_SELECT_LOOP(s) - - if (newfd == INVALID_SOCKET) - return (!async_err) ? s->errorhandler() : NULL; #ifdef MS_WINDOWS if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) { @@ -2130,21 +2175,21 @@ sock_accept(PySocketSockObject *s) if (!accept4_works) #endif { - if (_Py_set_inheritable(newfd, 0, NULL) < 0) { - SOCKETCLOSE(newfd); + if (_Py_set_inheritable(ctx.newfd, 0, NULL) < 0) { + SOCKETCLOSE(ctx.newfd); goto finally; } } #endif - sock = PyLong_FromSocket_t(newfd); + sock = PyLong_FromSocket_t(ctx.newfd); if (sock == NULL) { - SOCKETCLOSE(newfd); + SOCKETCLOSE(ctx.newfd); goto finally; } - addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), - addrlen, s->sock_proto); + addr = makesockaddr(s->sock_fd, SAS2SA(&ctx.addrbuf), + ctx.addrlen, s->sock_proto); if (addr == NULL) goto finally; @@ -2690,6 +2735,31 @@ at least 0 (if it is lower, it is set to unaccepted connections that the system will allow before refusing new\n\ connections. If not specified, a default reasonable value is chosen."); +struct sock_recv { + char *cbuf; + Py_ssize_t len; + Py_ssize_t outlen; + int flags; +}; + +static int +sock_recv_impl(PySocketSockObject *s, void *data) +{ + struct sock_recv *ctx = data; + + Py_BEGIN_ALLOW_THREADS +#ifdef MS_WINDOWS + if (ctx->len > INT_MAX) + ctx->len = INT_MAX; + ctx->outlen = recv(s->sock_fd, ctx->cbuf, (int)ctx->len, ctx->flags); +#else + ctx->outlen = recv(s->sock_fd, ctx->cbuf, ctx->len, ctx->flags); +#endif + Py_END_ALLOW_THREADS + + return (ctx->outlen >= 0); +} + /* * This is the guts of the recv() and recv_into() methods, which reads into a @@ -2703,9 +2773,7 @@ connections. If not specified, a default static Py_ssize_t sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags) { - Py_ssize_t outlen = -1; - int timeout; - int async_err = 0; + struct sock_recv ctx; if (!IS_SELECTABLE(s)) { select_error(); @@ -2716,36 +2784,14 @@ sock_recv_guts(PySocketSockObject *s, ch return 0; } - BEGIN_SELECT_LOOP(s) - do { - timeout = internal_select(s, 0, interval); - - if (!timeout) { - Py_BEGIN_ALLOW_THREADS -#ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - outlen = recv(s->sock_fd, cbuf, (int)len, flags); -#else - outlen = recv(s->sock_fd, cbuf, len, flags); -#endif - Py_END_ALLOW_THREADS - } - } while (outlen < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); - - if (timeout == 1) { - PyErr_SetString(socket_timeout, "timed out"); + ctx.cbuf = cbuf; + ctx.len = len; + ctx.flags = flags; + ctx.outlen = -1; + if (sock_call(s, 0, sock_recv_impl, &ctx) < 0) return -1; - } - END_SELECT_LOOP(s) - if (outlen < 0) { - /* Note: the call to errorhandler() ALWAYS indirectly returned - NULL, so ignore its return value */ - if (!async_err) - s->errorhandler(); - return -1; - } - return outlen; + + return ctx.outlen; } @@ -2859,6 +2905,37 @@ is not specified (or 0), receive up to t \n\ See recv() for documentation about the flags."); +struct sock_recvfrom { + char* cbuf; + Py_ssize_t len; + int flags; + socklen_t addrlen; + sock_addr_t addrbuf; + Py_ssize_t n; +}; + +static int +sock_recvfrom_impl(PySocketSockObject *s, void *data) +{ + struct sock_recvfrom *ctx = data; + + memset(&ctx->addrbuf, 0, ctx->addrlen); + + Py_BEGIN_ALLOW_THREADS +#ifdef MS_WINDOWS + if (ctx->len > INT_MAX) + ctx->len = INT_MAX; + ctx->n = recvfrom(s->sock_fd, ctx->cbuf, (int)ctx->len, ctx->flags, + (void *) &ctx->addrbuf, &ctx->addrlen); +#else + ctx->n = recvfrom(s->sock_fd, ctx->cbuf, ctx->len, ctx->flags, + SAS2SA(&ctx->addrbuf), &ctx->addrlen); +#endif + Py_END_ALLOW_THREADS + + return (ctx->n >= 0); +} + /* * This is the guts of the recvfrom() and recvfrom_into() methods, which reads @@ -2875,15 +2952,11 @@ static Py_ssize_t sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags, PyObject** addr) { - sock_addr_t addrbuf; - int timeout; - Py_ssize_t n = -1; - socklen_t addrlen; - int async_err = 0; + struct sock_recvfrom ctx; *addr = NULL; - if (!getsockaddrlen(s, &addrlen)) + if (!getsockaddrlen(s, &ctx.addrlen)) return -1; if (!IS_SELECTABLE(s)) { @@ -2891,42 +2964,19 @@ sock_recvfrom_guts(PySocketSockObject *s return -1; } - BEGIN_SELECT_LOOP(s) - do { - memset(&addrbuf, 0, addrlen); - timeout = internal_select(s, 0, interval); - - if (!timeout) { - Py_BEGIN_ALLOW_THREADS -#ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - n = recvfrom(s->sock_fd, cbuf, (int)len, flags, - (void *) &addrbuf, &addrlen); -#else - n = recvfrom(s->sock_fd, cbuf, len, flags, - SAS2SA(&addrbuf), &addrlen); -#endif - Py_END_ALLOW_THREADS - } - } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); - - if (timeout == 1) { - PyErr_SetString(socket_timeout, "timed out"); + ctx.cbuf = cbuf; + ctx.len = len; + ctx.flags = flags; + ctx.n = -1; + if (sock_call(s, 0, sock_recvfrom_impl, &ctx) < 0) return -1; - } - END_SELECT_LOOP(s) - if (n < 0) { - if (!async_err) - s->errorhandler(); + + *addr = makesockaddr(s->sock_fd, SAS2SA(&ctx.addrbuf), ctx.addrlen, + s->sock_proto); + if (*addr == NULL) return -1; - } - - if (!(*addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), - addrlen, s->sock_proto))) - return -1; - - return n; + + return ctx.n; } /* s.recvfrom(nbytes [,flags]) method */ @@ -3037,6 +3087,24 @@ PyDoc_STRVAR(recvfrom_into_doc, \n\ Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info."); +struct sock_recvmsg { + struct msghdr *msg; + int flags; + ssize_t bytes_received; +}; + +static int +sock_recvmsg_impl(PySocketSockObject *s, void *data) +{ + struct sock_recvmsg *ctx = data; + + Py_BEGIN_ALLOW_THREADS; + ctx->bytes_received = recvmsg(s->sock_fd, ctx->msg, ctx->flags); + Py_END_ALLOW_THREADS; + + return (ctx->bytes_received >= 0); +} + /* The sendmsg() and recvmsg[_into]() methods require a working CMSG_LEN(). See the comment near get_CMSG_LEN(). */ @@ -3056,9 +3124,6 @@ sock_recvmsg_guts(PySocketSockObject *s, int flags, Py_ssize_t controllen, PyObject *(*makeval)(ssize_t, void *), void *makeval_data) { - ssize_t bytes_received = -1; - int timeout; - int async_err = 0; sock_addr_t addrbuf; socklen_t addrbuflen; struct msghdr msg = {0}; @@ -3067,6 +3132,7 @@ sock_recvmsg_guts(PySocketSockObject *s, struct cmsghdr *cmsgh; size_t cmsgdatalen = 0; int cmsg_status; + struct sock_recvmsg ctx; /* XXX: POSIX says that msg_name and msg_namelen "shall be ignored" when the socket is connected (Linux fills them in @@ -3093,35 +3159,19 @@ sock_recvmsg_guts(PySocketSockObject *s, goto finally; } - BEGIN_SELECT_LOOP(s) - do { - msg.msg_name = SAS2SA(&addrbuf); - msg.msg_namelen = addrbuflen; - msg.msg_iov = iov; - msg.msg_iovlen = iovlen; - msg.msg_control = controlbuf; - msg.msg_controllen = controllen; - timeout = internal_select(s, 0, interval); - - if (timeout == 1) { - PyErr_SetString(socket_timeout, "timed out"); - goto finally; - } - - if (!timeout) { - Py_BEGIN_ALLOW_THREADS; - bytes_received = recvmsg(s->sock_fd, &msg, flags); - Py_END_ALLOW_THREADS; - } - } while (bytes_received < 0 && errno == EINTR && - !(async_err = PyErr_CheckSignals())); - END_SELECT_LOOP(s) - - if (bytes_received < 0) { - if (!async_err) - s->errorhandler(); + msg.msg_name = SAS2SA(&addrbuf); + msg.msg_namelen = addrbuflen; + msg.msg_iov = iov; + msg.msg_iovlen = iovlen; + msg.msg_control = controlbuf; + msg.msg_controllen = controllen; + + ctx.msg = &msg; + ctx.flags = flags; + ctx.bytes_received = -1; + + if (sock_call(s, 0, sock_recvmsg_impl, &ctx) < 0) goto finally; - } /* Make list of (level, type, data) tuples from control messages. */ if ((cmsg_list = PyList_New(0)) == NULL) @@ -3163,7 +3213,7 @@ sock_recvmsg_guts(PySocketSockObject *s, } retval = Py_BuildValue("NOiN", - (*makeval)(bytes_received, makeval_data), + (*makeval)(ctx.bytes_received, makeval_data), cmsg_list, (int)msg.msg_flags, makesockaddr(s->sock_fd, SAS2SA(&addrbuf), @@ -3371,54 +3421,59 @@ SCM_RIGHTS mechanism."); #endif /* CMSG_LEN */ +struct sock_send { + char *buf; + Py_ssize_t len; + int flags; + Py_ssize_t n; +}; + +static int +sock_send_impl(PySocketSockObject *s, void *data) +{ + struct sock_send *ctx = data; + + Py_BEGIN_ALLOW_THREADS +#ifdef MS_WINDOWS + if (ctx->len > INT_MAX) + ctx->len = INT_MAX; + ctx->n = send(s->sock_fd, ctx->buf, (int)ctx->len, ctx->flags); +#else + ctx->n = send(s->sock_fd, ctx->buf, ctx->len, ctx->flags); +#endif + Py_END_ALLOW_THREADS + + return (ctx->n >= 0); +} + /* s.send(data [,flags]) method */ static PyObject * sock_send(PySocketSockObject *s, PyObject *args) { - char *buf; - Py_ssize_t len, n = -1; - int async_err = 0; - int flags = 0, timeout; Py_buffer pbuf; - - if (!PyArg_ParseTuple(args, "y*|i:send", &pbuf, &flags)) + struct sock_send ctx; + + ctx.flags = 0; + + if (!PyArg_ParseTuple(args, "y*|i:send", &pbuf, &ctx.flags)) return NULL; if (!IS_SELECTABLE(s)) { PyBuffer_Release(&pbuf); return select_error(); } - buf = pbuf.buf; - len = pbuf.len; - - BEGIN_SELECT_LOOP(s) - do { - timeout = internal_select(s, 1, interval); - - if (!timeout) { - Py_BEGIN_ALLOW_THREADS -#ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - n = send(s->sock_fd, buf, (int)len, flags); -#else - n = send(s->sock_fd, buf, len, flags); -#endif - Py_END_ALLOW_THREADS - } - } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); - if (timeout == 1) { + ctx.buf = pbuf.buf; + ctx.len = pbuf.len; + ctx.n = -1; + + if (sock_call(s, 1, sock_send_impl, &ctx) < 0) { PyBuffer_Release(&pbuf); - PyErr_SetString(socket_timeout, "timed out"); return NULL; } - END_SELECT_LOOP(s) - PyBuffer_Release(&pbuf); - if (n < 0) - return (!async_err) ? s->errorhandler() : NULL; - return PyLong_FromSsize_t(n); + + return PyLong_FromSsize_t(ctx.n); } PyDoc_STRVAR(send_doc, @@ -3494,6 +3549,35 @@ until all data is sent. If an error occ to tell how much data has been sent."); +struct sock_sendto { + char *buf; + Py_ssize_t len; + int addrlen; + sock_addr_t addrbuf; + int flags; + Py_ssize_t n; +}; + +static int +sock_sendto_impl(PySocketSockObject *s, void *data) +{ + struct sock_sendto *ctx = data; + + Py_BEGIN_ALLOW_THREADS +#ifdef MS_WINDOWS + if (ctx->len > INT_MAX) + ctx->len = INT_MAX; + ctx->n = sendto(s->sock_fd, ctx->buf, (int)ctx->len, ctx->flags, + SAS2SA(&ctx->addrbuf), ctx->addrlen); +#else + ctx->n = sendto(s->sock_fd, ctx->buf, ctx->len, ctx->flags, + SAS2SA(&ctx->addrbuf), ctx->addrlen); +#endif + Py_END_ALLOW_THREADS + + return (ctx->n >= 0); +} + /* s.sendto(data, [flags,] sockaddr) method */ static PyObject * @@ -3501,13 +3585,10 @@ sock_sendto(PySocketSockObject *s, PyObj { Py_buffer pbuf; PyObject *addro; - char *buf; - Py_ssize_t len, arglen; - sock_addr_t addrbuf; - int addrlen, n = -1, flags, timeout; - int async_err = 0; - - flags = 0; + Py_ssize_t arglen; + struct sock_sendto ctx; + + ctx.flags = 0; arglen = PyTuple_Size(args); switch (arglen) { case 2: @@ -3515,7 +3596,7 @@ sock_sendto(PySocketSockObject *s, PyObj break; case 3: PyArg_ParseTuple(args, "y*iO:sendto", - &pbuf, &flags, &addro); + &pbuf, &ctx.flags, &addro); break; default: PyErr_Format(PyExc_TypeError, @@ -3526,48 +3607,27 @@ sock_sendto(PySocketSockObject *s, PyObj if (PyErr_Occurred()) return NULL; - buf = pbuf.buf; - len = pbuf.len; - if (!IS_SELECTABLE(s)) { PyBuffer_Release(&pbuf); return select_error(); } - if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen)) { + if (!getsockaddrarg(s, addro, SAS2SA(&ctx.addrbuf), &ctx.addrlen)) { PyBuffer_Release(&pbuf); return NULL; } - BEGIN_SELECT_LOOP(s) - do { - timeout = internal_select(s, 1, interval); - - if (!timeout) { - Py_BEGIN_ALLOW_THREADS -#ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - n = sendto(s->sock_fd, buf, (int)len, flags, - SAS2SA(&addrbuf), addrlen); -#else - n = sendto(s->sock_fd, buf, len, flags, - SAS2SA(&addrbuf), addrlen); -#endif - Py_END_ALLOW_THREADS - } - } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); - - if (timeout == 1) { + ctx.buf = pbuf.buf; + ctx.len = pbuf.len; + ctx.n = -1; + + if (sock_call(s, 1, sock_sendto_impl, &ctx) < 0) { PyBuffer_Release(&pbuf); - PyErr_SetString(socket_timeout, "timed out"); return NULL; } - END_SELECT_LOOP(s) PyBuffer_Release(&pbuf); - if (n < 0) - return (!async_err) ? s->errorhandler() : NULL; - return PyLong_FromSsize_t(n); + + return PyLong_FromSsize_t(ctx.n); } PyDoc_STRVAR(sendto_doc, @@ -3577,6 +3637,24 @@ Like send(data, flags) but allows specif For IP sockets, the address is a pair (hostaddr, port)."); +struct sock_sendmsg { + struct msghdr *msg; + int flags; + ssize_t bytes_sent; +}; + +static int +sock_sendmsg_impl(PySocketSockObject *s, void *data) +{ + struct sock_sendmsg *ctx = data; + + Py_BEGIN_ALLOW_THREADS; + ctx->bytes_sent = sendmsg(s->sock_fd, ctx->msg, ctx->flags); + Py_END_ALLOW_THREADS; + + return (ctx->bytes_sent >= 0); +} + /* The sendmsg() and recvmsg[_into]() methods require a working CMSG_LEN(). See the comment near get_CMSG_LEN(). */ #ifdef CMSG_LEN @@ -3597,11 +3675,10 @@ sock_sendmsg(PySocketSockObject *s, PyOb } *cmsgs = NULL; void *controlbuf = NULL; size_t controllen, controllen_last; - ssize_t bytes_sent = -1; - int async_err = 0; - int addrlen, timeout, flags = 0; + int addrlen, flags = 0; PyObject *data_arg, *cmsg_arg = NULL, *addr_arg = NULL, *data_fast = NULL, *cmsg_fast = NULL, *retval = NULL; + struct sock_sendmsg ctx; if (!PyArg_ParseTuple(args, "O|OiO:sendmsg", &data_arg, &cmsg_arg, &flags, &addr_arg)) @@ -3755,30 +3832,13 @@ sock_sendmsg(PySocketSockObject *s, PyOb goto finally; } - BEGIN_SELECT_LOOP(s) - do { - timeout = internal_select(s, 1, interval); - - if (!timeout) { - Py_BEGIN_ALLOW_THREADS; - bytes_sent = sendmsg(s->sock_fd, &msg, flags); - Py_END_ALLOW_THREADS; - } - - if (timeout == 1) { - PyErr_SetString(socket_timeout, "timed out"); - goto finally; - } - } while (bytes_sent < 0 && errno == EINTR && - !(async_err = PyErr_CheckSignals())); - END_SELECT_LOOP(s) - - if (bytes_sent < 0) { - if (!async_err) - s->errorhandler(); + ctx.flags = flags; + ctx.msg = &msg; + ctx.bytes_sent = -1; + if (sock_call(s, 1, sock_sendmsg_impl, &ctx) < 0) goto finally; - } - retval = PyLong_FromSsize_t(bytes_sent); + + retval = PyLong_FromSsize_t(ctx.bytes_sent); finally: PyMem_Free(controlbuf);