a socket operation on a socket with a timeout, the exception will be caught correctly. Previously, the exception was not caught.
This commit is contained in:
parent
3ee5941f68
commit
9b0ca79213
|
@ -11,6 +11,7 @@ import Queue
|
||||||
import sys
|
import sys
|
||||||
import array
|
import array
|
||||||
from weakref import proxy
|
from weakref import proxy
|
||||||
|
import signal
|
||||||
|
|
||||||
PORT = 50007
|
PORT = 50007
|
||||||
HOST = 'localhost'
|
HOST = 'localhost'
|
||||||
|
@ -817,6 +818,37 @@ class TCPTimeoutTest(SocketTCPTest):
|
||||||
if not ok:
|
if not ok:
|
||||||
self.fail("accept() returned success when we did not expect it")
|
self.fail("accept() returned success when we did not expect it")
|
||||||
|
|
||||||
|
def testInterruptedTimeout(self):
|
||||||
|
# XXX I don't know how to do this test on MSWindows or any other
|
||||||
|
# plaform that doesn't support signal.alarm() or os.kill(), though
|
||||||
|
# the bug should have existed on all platforms.
|
||||||
|
if not hasattr(signal, "alarm"):
|
||||||
|
return # can only test on *nix
|
||||||
|
self.serv.settimeout(5.0) # must be longer than alarm
|
||||||
|
class Alarm(Exception):
|
||||||
|
pass
|
||||||
|
def alarm_handler(signal, frame):
|
||||||
|
raise Alarm
|
||||||
|
old_alarm = signal.signal(signal.SIGALRM, alarm_handler)
|
||||||
|
try:
|
||||||
|
signal.alarm(2) # POSIX allows alarm to be up to 1 second early
|
||||||
|
try:
|
||||||
|
foo = self.serv.accept()
|
||||||
|
except socket.timeout:
|
||||||
|
self.fail("caught timeout instead of Alarm")
|
||||||
|
except Alarm:
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
self.fail("caught other exception instead of Alarm")
|
||||||
|
else:
|
||||||
|
self.fail("nothing caught")
|
||||||
|
signal.alarm(0) # shut off alarm
|
||||||
|
except Alarm:
|
||||||
|
self.fail("got Alarm in wrong place")
|
||||||
|
finally:
|
||||||
|
# no alarm can be pending. Safe to restore old handler.
|
||||||
|
signal.signal(signal.SIGALRM, old_alarm)
|
||||||
|
|
||||||
class UDPTimeoutTest(SocketTCPTest):
|
class UDPTimeoutTest(SocketTCPTest):
|
||||||
|
|
||||||
def testUDPTimeout(self):
|
def testUDPTimeout(self):
|
||||||
|
|
|
@ -435,6 +435,7 @@ Michael Muller
|
||||||
Takahiro Nakayama
|
Takahiro Nakayama
|
||||||
Travers Naran
|
Travers Naran
|
||||||
Fredrik Nehr
|
Fredrik Nehr
|
||||||
|
Tony Nelson
|
||||||
Chad Netzer
|
Chad Netzer
|
||||||
Max Neunhöffer
|
Max Neunhöffer
|
||||||
George Neville-Neil
|
George Neville-Neil
|
||||||
|
|
|
@ -140,6 +140,10 @@ Library
|
||||||
Extension Modules
|
Extension Modules
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Patch #1519025 and bug #926423: If a KeyboardInterrupt occurs during
|
||||||
|
a socket operation on a socket with a timeout, the exception will be
|
||||||
|
caught correctly. Previously, the exception was not caught.
|
||||||
|
|
||||||
- Patch #1529514: The _ctypes extension is now compiled on more
|
- Patch #1529514: The _ctypes extension is now compiled on more
|
||||||
openbsd target platforms.
|
openbsd target platforms.
|
||||||
|
|
||||||
|
|
|
@ -708,7 +708,7 @@ internal_setblocking(PySocketSockObject *s, int block)
|
||||||
The argument writing indicates the direction.
|
The argument writing indicates the direction.
|
||||||
This does not raise an exception; we'll let our caller do that
|
This does not raise an exception; we'll let our caller do that
|
||||||
after they've reacquired the interpreter lock.
|
after they've reacquired the interpreter lock.
|
||||||
Returns 1 on timeout, 0 otherwise. */
|
Returns 1 on timeout, -1 on error, 0 otherwise. */
|
||||||
static int
|
static int
|
||||||
internal_select(PySocketSockObject *s, int writing)
|
internal_select(PySocketSockObject *s, int writing)
|
||||||
{
|
{
|
||||||
|
@ -753,6 +753,9 @@ internal_select(PySocketSockObject *s, int writing)
|
||||||
n = select(s->sock_fd+1, &fds, NULL, NULL, &tv);
|
n = select(s->sock_fd+1, &fds, NULL, NULL, &tv);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
return -1;
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1552,7 +1555,7 @@ sock_accept(PySocketSockObject *s)
|
||||||
&addrlen);
|
&addrlen);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout == 1) {
|
||||||
PyErr_SetString(socket_timeout, "timed out");
|
PyErr_SetString(socket_timeout, "timed out");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1923,9 +1926,15 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
|
||||||
if (s->sock_timeout > 0.0) {
|
if (s->sock_timeout > 0.0) {
|
||||||
if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) {
|
if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) {
|
||||||
timeout = internal_select(s, 1);
|
timeout = internal_select(s, 1);
|
||||||
res = connect(s->sock_fd, addr, addrlen);
|
if (timeout == 0) {
|
||||||
if (res < 0 && errno == EISCONN)
|
res = connect(s->sock_fd, addr, addrlen);
|
||||||
res = 0;
|
if (res < 0 && errno == EISCONN)
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
else if (timeout == -1)
|
||||||
|
res = errno; /* had error */
|
||||||
|
else
|
||||||
|
res = EWOULDBLOCK; /* timed out */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1955,7 +1964,7 @@ sock_connect(PySocketSockObject *s, PyObject *addro)
|
||||||
res = internal_connect(s, addr, addrlen, &timeout);
|
res = internal_connect(s, addr, addrlen, &timeout);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout == 1) {
|
||||||
PyErr_SetString(socket_timeout, "timed out");
|
PyErr_SetString(socket_timeout, "timed out");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1989,6 +1998,13 @@ sock_connect_ex(PySocketSockObject *s, PyObject *addro)
|
||||||
res = internal_connect(s, addr, addrlen, &timeout);
|
res = internal_connect(s, addr, addrlen, &timeout);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
/* Signals are not errors (though they may raise exceptions). Adapted
|
||||||
|
from PyErr_SetFromErrnoWithFilenameObject(). */
|
||||||
|
#ifdef EINTR
|
||||||
|
if (res == EINTR && PyErr_CheckSignals())
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
return PyInt_FromLong((long) res);
|
return PyInt_FromLong((long) res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2209,10 +2225,10 @@ The mode and buffersize arguments are as for the built-in open() function.");
|
||||||
static ssize_t
|
static ssize_t
|
||||||
sock_recv_guts(PySocketSockObject *s, char* cbuf, int len, int flags)
|
sock_recv_guts(PySocketSockObject *s, char* cbuf, int len, int flags)
|
||||||
{
|
{
|
||||||
ssize_t outlen = 0;
|
ssize_t outlen = -1;
|
||||||
int timeout;
|
int timeout;
|
||||||
#ifdef __VMS
|
#ifdef __VMS
|
||||||
int remaining, nread;
|
int remaining;
|
||||||
char *read_buf;
|
char *read_buf;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2228,7 +2244,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, int len, int flags)
|
||||||
outlen = recv(s->sock_fd, cbuf, len, flags);
|
outlen = recv(s->sock_fd, cbuf, len, flags);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout == 1) {
|
||||||
PyErr_SetString(socket_timeout, "timed out");
|
PyErr_SetString(socket_timeout, "timed out");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -2243,6 +2259,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, int len, int flags)
|
||||||
remaining = len;
|
remaining = len;
|
||||||
while (remaining != 0) {
|
while (remaining != 0) {
|
||||||
unsigned int segment;
|
unsigned int segment;
|
||||||
|
int nread = -1;
|
||||||
|
|
||||||
segment = remaining /SEGMENT_SIZE;
|
segment = remaining /SEGMENT_SIZE;
|
||||||
if (segment != 0) {
|
if (segment != 0) {
|
||||||
|
@ -2258,7 +2275,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, int len, int flags)
|
||||||
nread = recv(s->sock_fd, read_buf, segment, flags);
|
nread = recv(s->sock_fd, read_buf, segment, flags);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout == 1) {
|
||||||
PyErr_SetString(socket_timeout, "timed out");
|
PyErr_SetString(socket_timeout, "timed out");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -2406,7 +2423,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, int len, int flags,
|
||||||
{
|
{
|
||||||
sock_addr_t addrbuf;
|
sock_addr_t addrbuf;
|
||||||
int timeout;
|
int timeout;
|
||||||
ssize_t n = 0;
|
ssize_t n = -1;
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
|
|
||||||
*addr = NULL;
|
*addr = NULL;
|
||||||
|
@ -2438,7 +2455,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, int len, int flags,
|
||||||
}
|
}
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout == 1) {
|
||||||
PyErr_SetString(socket_timeout, "timed out");
|
PyErr_SetString(socket_timeout, "timed out");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -2553,7 +2570,7 @@ static PyObject *
|
||||||
sock_send(PySocketSockObject *s, PyObject *args)
|
sock_send(PySocketSockObject *s, PyObject *args)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
int len, n = 0, flags = 0, timeout;
|
int len, n = -1, flags = 0, timeout;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags))
|
if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2571,7 +2588,7 @@ sock_send(PySocketSockObject *s, PyObject *args)
|
||||||
#endif
|
#endif
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout == 1) {
|
||||||
PyErr_SetString(socket_timeout, "timed out");
|
PyErr_SetString(socket_timeout, "timed out");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -2594,7 +2611,7 @@ static PyObject *
|
||||||
sock_sendall(PySocketSockObject *s, PyObject *args)
|
sock_sendall(PySocketSockObject *s, PyObject *args)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
int len, n = 0, flags = 0, timeout;
|
int len, n = -1, flags = 0, timeout;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags))
|
if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2605,6 +2622,7 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
do {
|
do {
|
||||||
timeout = internal_select(s, 1);
|
timeout = internal_select(s, 1);
|
||||||
|
n = -1;
|
||||||
if (timeout)
|
if (timeout)
|
||||||
break;
|
break;
|
||||||
#ifdef __VMS
|
#ifdef __VMS
|
||||||
|
@ -2619,7 +2637,7 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
|
||||||
} while (len > 0);
|
} while (len > 0);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout == 1) {
|
||||||
PyErr_SetString(socket_timeout, "timed out");
|
PyErr_SetString(socket_timeout, "timed out");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -2647,7 +2665,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
|
||||||
PyObject *addro;
|
PyObject *addro;
|
||||||
char *buf;
|
char *buf;
|
||||||
struct sockaddr *addr;
|
struct sockaddr *addr;
|
||||||
int addrlen, len, n = 0, flags, timeout;
|
int addrlen, len, n = -1, flags, timeout;
|
||||||
|
|
||||||
flags = 0;
|
flags = 0;
|
||||||
if (!PyArg_ParseTuple(args, "s#O:sendto", &buf, &len, &addro)) {
|
if (!PyArg_ParseTuple(args, "s#O:sendto", &buf, &len, &addro)) {
|
||||||
|
@ -2669,7 +2687,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
|
||||||
n = sendto(s->sock_fd, buf, len, flags, addr, addrlen);
|
n = sendto(s->sock_fd, buf, len, flags, addr, addrlen);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout == 1) {
|
||||||
PyErr_SetString(socket_timeout, "timed out");
|
PyErr_SetString(socket_timeout, "timed out");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue