Index: _ssl.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/_ssl.c,v retrieving revision 1.16 diff -c -w -b -B -c -r1.16 _ssl.c *** _ssl.c 23 Mar 2004 23:16:54 -0000 1.16 --- _ssl.c 11 May 2004 07:05:47 -0000 *************** *** 64,73 **** static PyTypeObject PySSL_Type; static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args); static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args); ! static int wait_for_timeout(PySocketSockObject *s, int writing); #define PySSLObject_Check(v) ((v)->ob_type == &PySSL_Type) /* XXX It might be helpful to augment the error message generated below with the name of the SSL function that generated the error. I expect it's obvious most of the time. --- 64,81 ---- static PyTypeObject PySSL_Type; static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args); static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args); ! static int check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing); #define PySSLObject_Check(v) ((v)->ob_type == &PySSL_Type) + typedef enum { + SOCKET_IS_NONBLOCKING, + SOCKET_IS_BLOCKING, + SOCKET_HAS_TIMED_OUT, + SOCKET_HAS_BEEN_CLOSED, + SOCKET_OPERATION_OK + } timeout_state; + /* XXX It might be helpful to augment the error message generated below with the name of the SSL function that generated the error. I expect it's obvious most of the time. *************** *** 170,176 **** char *errstr = NULL; int ret; int err; ! int timedout; self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ if (self == NULL){ --- 178,184 ---- char *errstr = NULL; int ret; int err; ! int sockstate; self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ if (self == NULL){ *************** *** 239,245 **** /* Actually negotiate SSL connection */ /* XXX If SSL_connect() returns 0, it's also a failure. */ ! timedout = 0; do { Py_BEGIN_ALLOW_THREADS ret = SSL_connect(self->ssl); --- 247,253 ---- /* Actually negotiate SSL connection */ /* XXX If SSL_connect() returns 0, it's also a failure. */ ! sockstate = 0; do { Py_BEGIN_ALLOW_THREADS ret = SSL_connect(self->ssl); *************** *** 249,261 **** goto fail; } if (err == SSL_ERROR_WANT_READ) { ! timedout = wait_for_timeout(Sock, 0); } else if (err == SSL_ERROR_WANT_WRITE) { ! timedout = wait_for_timeout(Sock, 1); ! } ! if (timedout) { ! errstr = "The connect operation timed out"; goto fail; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (ret <= 0) { --- 257,275 ---- goto fail; } if (err == SSL_ERROR_WANT_READ) { ! sockstate = check_socket_and_wait_for_timeout(Sock, 0); } else if (err == SSL_ERROR_WANT_WRITE) { ! sockstate = check_socket_and_wait_for_timeout(Sock, 1); ! } else ! sockstate = SOCKET_OPERATION_OK; ! if (sockstate == SOCKET_HAS_TIMED_OUT) { ! PyErr_SetString(PySSLErrorObject, "The connect operation timed out"); ! goto fail; ! } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { ! PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); goto fail; + } else if (sockstate == SOCKET_IS_NONBLOCKING) { + break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (ret <= 0) { *************** *** 334,355 **** /* If the socket has a timeout, do a select() on the socket. The argument writing indicates the direction. ! Return non-zero if the socket timed out, zero otherwise. */ static int ! wait_for_timeout(PySocketSockObject *s, int writing) { fd_set fds; struct timeval tv; int rc; /* Nothing to do unless we're in timeout mode (not non-blocking) */ ! if (s->sock_timeout <= 0.0) ! return 0; /* Guard against closed socket */ if (s->sock_fd < 0) ! return 0; /* Construct the arguments to select */ tv.tv_sec = (int)s->sock_timeout; --- 348,372 ---- /* If the socket has a timeout, do a select() on the socket. The argument writing indicates the direction. ! Returns one of the possibilities in the timeout_state enum (above). */ + static int ! check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing) { fd_set fds; struct timeval tv; int rc; /* Nothing to do unless we're in timeout mode (not non-blocking) */ ! if (s->sock_timeout < 0.0) ! return SOCKET_IS_BLOCKING; ! else if (s->sock_timeout == 0.0) ! return SOCKET_IS_NONBLOCKING; /* Guard against closed socket */ if (s->sock_fd < 0) ! return SOCKET_HAS_BEEN_CLOSED; /* Construct the arguments to select */ tv.tv_sec = (int)s->sock_timeout; *************** *** 365,372 **** rc = select(s->sock_fd+1, &fds, NULL, NULL, &tv); Py_END_ALLOW_THREADS ! /* Return 1 on timeout, 0 otherwise */ ! return rc == 0; } static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) --- 382,390 ---- rc = select(s->sock_fd+1, &fds, NULL, NULL, &tv); Py_END_ALLOW_THREADS ! /* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise ! (when we are able to write or when there's something to read) */ ! return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK; } static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) *************** *** 374,389 **** char *data; int len; int count; ! int timedout; int err; if (!PyArg_ParseTuple(args, "s#:write", &data, &count)) return NULL; ! timedout = wait_for_timeout(self->Socket, 1); ! if (timedout) { PyErr_SetString(PySSLErrorObject, "The write operation timed out"); return NULL; } do { err = 0; --- 392,410 ---- char *data; int len; int count; ! int sockstate; int err; if (!PyArg_ParseTuple(args, "s#:write", &data, &count)) return NULL; ! sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); ! if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The write operation timed out"); return NULL; + } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { + PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); + return NULL; } do { err = 0; *************** *** 395,407 **** return NULL; } if (err == SSL_ERROR_WANT_READ) { ! timedout = wait_for_timeout(self->Socket, 0); } else if (err == SSL_ERROR_WANT_WRITE) { ! timedout = wait_for_timeout(self->Socket, 1); ! } ! if (timedout) { PyErr_SetString(PySSLErrorObject, "The write operation timed out"); return NULL; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (len > 0) --- 416,434 ---- return NULL; } if (err == SSL_ERROR_WANT_READ) { ! sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); } else if (err == SSL_ERROR_WANT_WRITE) { ! sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); ! } else ! sockstate = SOCKET_OPERATION_OK; ! if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The write operation timed out"); return NULL; + } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { + PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); + return NULL; + } else if (sockstate == SOCKET_IS_NONBLOCKING) { + break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (len > 0) *************** *** 421,427 **** PyObject *buf; int count = 0; int len = 1024; ! int timedout; int err; if (!PyArg_ParseTuple(args, "|i:read", &len)) --- 448,454 ---- PyObject *buf; int count = 0; int len = 1024; ! int sockstate; int err; if (!PyArg_ParseTuple(args, "|i:read", &len)) *************** *** 430,437 **** if (!(buf = PyString_FromStringAndSize((char *) 0, len))) return NULL; ! timedout = wait_for_timeout(self->Socket, 0); ! if (timedout) { PyErr_SetString(PySSLErrorObject, "The read operation timed out"); Py_DECREF(buf); return NULL; --- 457,464 ---- if (!(buf = PyString_FromStringAndSize((char *) 0, len))) return NULL; ! sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); ! if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The read operation timed out"); Py_DECREF(buf); return NULL; *************** *** 447,460 **** return NULL; } if (err == SSL_ERROR_WANT_READ) { ! timedout = wait_for_timeout(self->Socket, 0); } else if (err == SSL_ERROR_WANT_WRITE) { ! timedout = wait_for_timeout(self->Socket, 1); ! } ! if (timedout) { PyErr_SetString(PySSLErrorObject, "The read operation timed out"); Py_DECREF(buf); return NULL; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (count <= 0) { --- 474,490 ---- return NULL; } if (err == SSL_ERROR_WANT_READ) { ! sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); } else if (err == SSL_ERROR_WANT_WRITE) { ! sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); ! } else ! sockstate = SOCKET_OPERATION_OK; ! if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The read operation timed out"); Py_DECREF(buf); return NULL; + } else if (sockstate == SOCKET_IS_NONBLOCKING) { + break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (count <= 0) {