From 8912d1418e6b336c21bbe21c0dd123332bbe5ab5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 6 Apr 2015 23:16:34 +0200 Subject: [PATCH] Issue #23853: socket.socket.sendall() does no more reset the socket timeout each time data is sent successfuly. The socket timeout is now the maximum total duration to send all data. --- Doc/library/socket.rst | 4 +++ Misc/NEWS | 4 +++ Modules/socketmodule.c | 57 ++++++++++++++++++++++++++++++------------ 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 9a69ad41a2..530fbb0556 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1155,6 +1155,10 @@ to sockets. success. On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent. + .. versionchanged:: 3.5 + The socket timeout is no more reset each time data is sent successfuly. + The socket timeout is now the maximum total duration to send all data. + .. versionchanged:: 3.5 If the system call is interrupted and the signal handler does not raise an exception, the method now retries the system call instead of raising diff --git a/Misc/NEWS b/Misc/NEWS index 8bacc1355b..7b64a89682 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -19,6 +19,10 @@ Core and Builtins Library ------- +- Issue #23853: :meth:`socket.socket.sendall` does no more reset the socket + timeout each time data is sent successfuly. The socket timeout is now the + maximum total duration to send all data. + - Issue #22721: An order of multiline pprint output of set or dict containing orderable and non-orderable elements no longer depends on iteration order of set or dict. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 604b9a8207..f27e69729c 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -706,9 +706,10 @@ sock_call_ex(PySocketSockObject *s, int (*sock_func) (PySocketSockObject *s, void *data), void *data, int connect, - int *err) + int *err, + _PyTime_t timeout) { - int has_timeout = (s->sock_timeout > 0); + int has_timeout = (timeout > 0); _PyTime_t deadline = 0; int deadline_initialized = 0; int res; @@ -731,8 +732,8 @@ sock_call_ex(PySocketSockObject *s, } else { deadline_initialized = 1; - deadline = _PyTime_GetMonotonicClock() + s->sock_timeout; - interval = s->sock_timeout; + deadline = _PyTime_GetMonotonicClock() + timeout; + interval = timeout; } if (interval >= 0) @@ -832,7 +833,7 @@ sock_call(PySocketSockObject *s, int (*func) (PySocketSockObject *s, void *data), void *data) { - return sock_call_ex(s, writing, func, data, 0, NULL); + return sock_call_ex(s, writing, func, data, 0, NULL, s->sock_timeout); } @@ -2636,12 +2637,14 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, if (raise) { /* socket.connect() raises an exception on error */ - if (sock_call_ex(s, 1, sock_connect_impl, NULL, 1, NULL) < 0) + if (sock_call_ex(s, 1, sock_connect_impl, NULL, + 1, NULL, s->sock_timeout) < 0) return -1; } else { /* socket.connect_ex() returns the error code on error */ - if (sock_call_ex(s, 1, sock_connect_impl, NULL, 1, &err) < 0) + if (sock_call_ex(s, 1, sock_connect_impl, NULL, + 1, &err, s->sock_timeout) < 0) return err; } return 0; @@ -3550,6 +3553,11 @@ sock_sendall(PySocketSockObject *s, PyObject *args) int flags = 0; Py_buffer pbuf; struct sock_send ctx; + int has_timeout = (s->sock_timeout > 0); + _PyTime_t interval = s->sock_timeout; + _PyTime_t deadline = 0; + int deadline_initialized = 0; + PyObject *res = NULL; if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags)) return NULL; @@ -3562,13 +3570,27 @@ sock_sendall(PySocketSockObject *s, PyObject *args) } do { + if (has_timeout) { + if (deadline_initialized) { + /* recompute the timeout */ + interval = deadline - _PyTime_GetMonotonicClock(); + } + else { + deadline_initialized = 1; + deadline = _PyTime_GetMonotonicClock() + s->sock_timeout; + } + + if (interval <= 0) { + PyErr_SetString(socket_timeout, "timed out"); + goto done; + } + } + ctx.buf = buf; ctx.len = len; ctx.flags = flags; - if (sock_call(s, 1, sock_send_impl, &ctx) < 0) { - PyBuffer_Release(&pbuf); - return NULL; - } + if (sock_call_ex(s, 1, sock_send_impl, &ctx, 0, NULL, interval) < 0) + goto done; n = ctx.result; assert(n >= 0); @@ -3578,14 +3600,17 @@ sock_sendall(PySocketSockObject *s, PyObject *args) /* We must run our signal handlers before looping again. send() can return a successful partial write when it is interrupted, so we can't restrict ourselves to EINTR. */ - if (PyErr_CheckSignals()) { - PyBuffer_Release(&pbuf); - return NULL; - } + if (PyErr_CheckSignals()) + goto done; } while (len > 0); PyBuffer_Release(&pbuf); - Py_RETURN_NONE; + Py_INCREF(Py_None); + res = Py_None; + +done: + PyBuffer_Release(&pbuf); + return res; } PyDoc_STRVAR(sendall_doc, -- 2.40.0