Commit 8912d141 authored by Victor Stinner's avatar Victor Stinner

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.
parent 9001d808
...@@ -1155,6 +1155,10 @@ to sockets. ...@@ -1155,6 +1155,10 @@ to sockets.
success. On error, an exception is raised, and there is no way to determine how success. On error, an exception is raised, and there is no way to determine how
much data, if any, was successfully sent. 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 .. versionchanged:: 3.5
If the system call is interrupted and the signal handler does not raise 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 exception, the method now retries the system call instead of raising
......
...@@ -19,6 +19,10 @@ Core and Builtins ...@@ -19,6 +19,10 @@ Core and Builtins
Library 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 - 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 orderable and non-orderable elements no longer depends on iteration order of
set or dict. set or dict.
......
...@@ -706,9 +706,10 @@ sock_call_ex(PySocketSockObject *s, ...@@ -706,9 +706,10 @@ sock_call_ex(PySocketSockObject *s,
int (*sock_func) (PySocketSockObject *s, void *data), int (*sock_func) (PySocketSockObject *s, void *data),
void *data, void *data,
int connect, 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; _PyTime_t deadline = 0;
int deadline_initialized = 0; int deadline_initialized = 0;
int res; int res;
...@@ -731,8 +732,8 @@ sock_call_ex(PySocketSockObject *s, ...@@ -731,8 +732,8 @@ sock_call_ex(PySocketSockObject *s,
} }
else { else {
deadline_initialized = 1; deadline_initialized = 1;
deadline = _PyTime_GetMonotonicClock() + s->sock_timeout; deadline = _PyTime_GetMonotonicClock() + timeout;
interval = s->sock_timeout; interval = timeout;
} }
if (interval >= 0) if (interval >= 0)
...@@ -832,7 +833,7 @@ sock_call(PySocketSockObject *s, ...@@ -832,7 +833,7 @@ sock_call(PySocketSockObject *s,
int (*func) (PySocketSockObject *s, void *data), int (*func) (PySocketSockObject *s, void *data),
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, ...@@ -2636,12 +2637,14 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
if (raise) { if (raise) {
/* socket.connect() raises an exception on error */ /* 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; return -1;
} }
else { else {
/* socket.connect_ex() returns the error code on error */ /* 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 err;
} }
return 0; return 0;
...@@ -3550,6 +3553,11 @@ sock_sendall(PySocketSockObject *s, PyObject *args) ...@@ -3550,6 +3553,11 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
int flags = 0; int flags = 0;
Py_buffer pbuf; Py_buffer pbuf;
struct sock_send ctx; 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)) if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags))
return NULL; return NULL;
...@@ -3562,13 +3570,27 @@ sock_sendall(PySocketSockObject *s, PyObject *args) ...@@ -3562,13 +3570,27 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
} }
do { 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.buf = buf;
ctx.len = len; ctx.len = len;
ctx.flags = flags; ctx.flags = flags;
if (sock_call(s, 1, sock_send_impl, &ctx) < 0) { if (sock_call_ex(s, 1, sock_send_impl, &ctx, 0, NULL, interval) < 0)
PyBuffer_Release(&pbuf); goto done;
return NULL;
}
n = ctx.result; n = ctx.result;
assert(n >= 0); assert(n >= 0);
...@@ -3578,14 +3600,17 @@ sock_sendall(PySocketSockObject *s, PyObject *args) ...@@ -3578,14 +3600,17 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
/* We must run our signal handlers before looping again. /* We must run our signal handlers before looping again.
send() can return a successful partial write when it is send() can return a successful partial write when it is
interrupted, so we can't restrict ourselves to EINTR. */ interrupted, so we can't restrict ourselves to EINTR. */
if (PyErr_CheckSignals()) { if (PyErr_CheckSignals())
PyBuffer_Release(&pbuf); goto done;
return NULL;
}
} while (len > 0); } while (len > 0);
PyBuffer_Release(&pbuf); PyBuffer_Release(&pbuf);
Py_RETURN_NONE; Py_INCREF(Py_None);
res = Py_None;
done:
PyBuffer_Release(&pbuf);
return res;
} }
PyDoc_STRVAR(sendall_doc, PyDoc_STRVAR(sendall_doc,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment