]> granicus.if.org Git - python/commitdiff
Issue #23853: socket.socket.sendall() does no more reset the socket timeout
authorVictor Stinner <victor.stinner@gmail.com>
Mon, 6 Apr 2015 21:16:34 +0000 (23:16 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Mon, 6 Apr 2015 21:16:34 +0000 (23:16 +0200)
each time data is sent successfuly. The socket timeout is now the maximum total
duration to send all data.

Doc/library/socket.rst
Misc/NEWS
Modules/socketmodule.c

index 9a69ad41a272292aa393960e11de7ad1a4942271..530fbb055679b3946a0c460f9fbbf1b0d6eae9d9 100644 (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
index 8bacc1355babd1faab994b74c41475d4e10d12d4..7b64a89682e781089ed3711ca26cded6139a45a7 100644 (file)
--- 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.
index 604b9a82078fc4b214214522b7a1a726695944a3..f27e69729c9547f787b7245f4ac41d70b03a9d3b 100644 (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,