Mercurial > cpython-lru_cache-weakref
comparison Modules/socketmodule.c @ 64959:aed04b3f0fe3
Issue #9950: Fix socket.sendall() crash or misbehaviour when a signal is
received. Now sendall() properly calls signal handlers if necessary,
and retries sending if these returned successfully, including on sockets
with a timeout.
| author | Antoine Pitrou <solipsis@pitrou.net> |
|---|---|
| date | Mon, 27 Sep 2010 17:52:25 +0000 |
| parents | 7d1752d62050 |
| children | 0f8c2eb89f46 |
comparison
equal
deleted
inserted
replaced
| 64958:ff5d3e5c4bb5 | 64959:aed04b3f0fe3 |
|---|---|
| 2566 static PyObject * | 2566 static PyObject * |
| 2567 sock_sendall(PySocketSockObject *s, PyObject *args) | 2567 sock_sendall(PySocketSockObject *s, PyObject *args) |
| 2568 { | 2568 { |
| 2569 char *buf; | 2569 char *buf; |
| 2570 Py_ssize_t len, n = -1; | 2570 Py_ssize_t len, n = -1; |
| 2571 int flags = 0, timeout; | 2571 int flags = 0, timeout, saved_errno; |
| 2572 Py_buffer pbuf; | 2572 Py_buffer pbuf; |
| 2573 | 2573 |
| 2574 if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags)) | 2574 if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags)) |
| 2575 return NULL; | 2575 return NULL; |
| 2576 buf = pbuf.buf; | 2576 buf = pbuf.buf; |
| 2579 if (!IS_SELECTABLE(s)) { | 2579 if (!IS_SELECTABLE(s)) { |
| 2580 PyBuffer_Release(&pbuf); | 2580 PyBuffer_Release(&pbuf); |
| 2581 return select_error(); | 2581 return select_error(); |
| 2582 } | 2582 } |
| 2583 | 2583 |
| 2584 Py_BEGIN_ALLOW_THREADS | |
| 2585 do { | 2584 do { |
| 2585 Py_BEGIN_ALLOW_THREADS | |
| 2586 timeout = internal_select(s, 1); | 2586 timeout = internal_select(s, 1); |
| 2587 n = -1; | 2587 n = -1; |
| 2588 if (timeout) | 2588 if (!timeout) { |
| 2589 break; | |
| 2590 #ifdef __VMS | 2589 #ifdef __VMS |
| 2591 n = sendsegmented(s->sock_fd, buf, len, flags); | 2590 n = sendsegmented(s->sock_fd, buf, len, flags); |
| 2592 #else | 2591 #else |
| 2593 n = send(s->sock_fd, buf, len, flags); | 2592 n = send(s->sock_fd, buf, len, flags); |
| 2594 #endif | 2593 #endif |
| 2594 } | |
| 2595 Py_END_ALLOW_THREADS | |
| 2596 if (timeout == 1) { | |
| 2597 PyBuffer_Release(&pbuf); | |
| 2598 PyErr_SetString(socket_timeout, "timed out"); | |
| 2599 return NULL; | |
| 2600 } | |
| 2601 /* PyErr_CheckSignals() might change errno */ | |
| 2602 saved_errno = errno; | |
| 2603 /* We must run our signal handlers before looping again. | |
| 2604 send() can return a successful partial write when it is | |
| 2605 interrupted, so we can't restrict ourselves to EINTR. */ | |
| 2606 if (PyErr_CheckSignals()) { | |
| 2607 PyBuffer_Release(&pbuf); | |
| 2608 return NULL; | |
| 2609 } | |
| 2595 if (n < 0) { | 2610 if (n < 0) { |
| 2596 #ifdef EINTR | 2611 /* If interrupted, try again */ |
| 2597 /* We must handle EINTR here as there is no way for | 2612 if (saved_errno == EINTR) |
| 2598 * the caller to know how much was sent otherwise. */ | |
| 2599 if (errno == EINTR) { | |
| 2600 /* Run signal handlers. If an exception was | |
| 2601 * raised, abort and leave this socket in | |
| 2602 * an unknown state. */ | |
| 2603 if (PyErr_CheckSignals()) | |
| 2604 return NULL; | |
| 2605 continue; | 2613 continue; |
| 2606 } | 2614 else |
| 2607 #endif | 2615 break; |
| 2608 break; | |
| 2609 } | 2616 } |
| 2610 buf += n; | 2617 buf += n; |
| 2611 len -= n; | 2618 len -= n; |
| 2612 } while (len > 0); | 2619 } while (len > 0); |
| 2613 Py_END_ALLOW_THREADS | |
| 2614 PyBuffer_Release(&pbuf); | 2620 PyBuffer_Release(&pbuf); |
| 2615 | 2621 |
| 2616 if (timeout == 1) { | |
| 2617 PyErr_SetString(socket_timeout, "timed out"); | |
| 2618 return NULL; | |
| 2619 } | |
| 2620 if (n < 0) | 2622 if (n < 0) |
| 2621 return s->errorhandler(); | 2623 return s->errorhandler(); |
| 2622 | 2624 |
| 2623 Py_INCREF(Py_None); | 2625 Py_INCREF(Py_None); |
| 2624 return Py_None; | 2626 return Py_None; |
