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.
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
......
......@@ -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.
......
......@@ -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,
......
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