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.
This commit is contained in:
Victor Stinner 2015-04-06 23:16:34 +02:00
parent 9001d8089c
commit 8912d1418e
3 changed files with 49 additions and 16 deletions

View File

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

View File

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

View File

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