changeset: 95459:cdc83da0b0f8 user: Victor Stinner date: Mon Apr 06 23:16:34 2015 +0200 files: Doc/library/socket.rst Misc/NEWS Modules/socketmodule.c description: 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. diff -r 7f54676348d3 -r cdc83da0b0f8 Doc/library/socket.rst --- a/Doc/library/socket.rst Mon Apr 06 23:06:01 2015 +0200 +++ b/Doc/library/socket.rst Mon Apr 06 23:16:34 2015 +0200 @@ -1156,6 +1156,10 @@ 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 an :exc:`InterruptedError` exception (see :pep:`475` for the rationale). diff -r 7f54676348d3 -r cdc83da0b0f8 Misc/NEWS --- a/Misc/NEWS Mon Apr 06 23:06:01 2015 +0200 +++ b/Misc/NEWS Mon Apr 06 23:16:34 2015 +0200 @@ -19,6 +19,10 @@ 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 -r 7f54676348d3 -r cdc83da0b0f8 Modules/socketmodule.c --- a/Modules/socketmodule.c Mon Apr 06 23:06:01 2015 +0200 +++ b/Modules/socketmodule.c Mon Apr 06 23:16:34 2015 +0200 @@ -706,9 +706,10 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ /* 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,