@@ -64,10 +64,19 @@ typedef struct {
6464static PyTypeObject PySSL_Type ;
6565static PyObject * PySSL_SSLwrite (PySSLObject * self , PyObject * args );
6666static PyObject * PySSL_SSLread (PySSLObject * self , PyObject * args );
67- static int wait_for_timeout (PySocketSockObject * s , int writing );
67+ static int check_socket_and_wait_for_timeout (PySocketSockObject * s ,
68+ int writing );
6869
6970#define PySSLObject_Check (v ) ((v)->ob_type == &PySSL_Type)
7071
72+ typedef enum {
73+ SOCKET_IS_NONBLOCKING ,
74+ SOCKET_IS_BLOCKING ,
75+ SOCKET_HAS_TIMED_OUT ,
76+ SOCKET_HAS_BEEN_CLOSED ,
77+ SOCKET_OPERATION_OK
78+ } timeout_state ;
79+
7180/* XXX It might be helpful to augment the error message generated
7281 below with the name of the SSL function that generated the error.
7382 I expect it's obvious most of the time.
@@ -170,7 +179,7 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file)
170179 char * errstr = NULL ;
171180 int ret ;
172181 int err ;
173- int timedout ;
182+ int sockstate ;
174183
175184 self = PyObject_New (PySSLObject , & PySSL_Type ); /* Create new object */
176185 if (self == NULL ){
@@ -239,7 +248,7 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file)
239248
240249 /* Actually negotiate SSL connection */
241250 /* XXX If SSL_connect() returns 0, it's also a failure. */
242- timedout = 0 ;
251+ sockstate = 0 ;
243252 do {
244253 Py_BEGIN_ALLOW_THREADS
245254 ret = SSL_connect (self -> ssl );
@@ -249,13 +258,20 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file)
249258 goto fail ;
250259 }
251260 if (err == SSL_ERROR_WANT_READ ) {
252- timedout = wait_for_timeout (Sock , 0 );
261+ sockstate = check_socket_and_wait_for_timeout (Sock , 0 );
253262 } else if (err == SSL_ERROR_WANT_WRITE ) {
254- timedout = wait_for_timeout (Sock , 1 );
263+ sockstate = check_socket_and_wait_for_timeout (Sock , 1 );
264+ } else {
265+ sockstate = SOCKET_OPERATION_OK ;
255266 }
256- if (timedout ) {
257- errstr = "The connect operation timed out" ;
267+ if (sockstate == SOCKET_HAS_TIMED_OUT ) {
268+ PyErr_SetString ( PySSLErrorObject , "The connect operation timed out" ) ;
258269 goto fail ;
270+ } else if (sockstate == SOCKET_HAS_BEEN_CLOSED ) {
271+ PyErr_SetString (PySSLErrorObject , "Underlying socket has been closed." );
272+ goto fail ;
273+ } else if (sockstate == SOCKET_IS_NONBLOCKING ) {
274+ break ;
259275 }
260276 } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE );
261277 if (ret <= 0 ) {
@@ -334,22 +350,25 @@ static void PySSL_dealloc(PySSLObject *self)
334350
335351/* If the socket has a timeout, do a select() on the socket.
336352 The argument writing indicates the direction.
337- Return non-zero if the socket timed out, zero otherwise .
353+ Returns one of the possibilities in the timeout_state enum (above) .
338354 */
355+
339356static int
340- wait_for_timeout (PySocketSockObject * s , int writing )
357+ check_socket_and_wait_for_timeout (PySocketSockObject * s , int writing )
341358{
342359 fd_set fds ;
343360 struct timeval tv ;
344361 int rc ;
345362
346363 /* Nothing to do unless we're in timeout mode (not non-blocking) */
347- if (s -> sock_timeout <= 0.0 )
348- return 0 ;
364+ if (s -> sock_timeout < 0.0 )
365+ return SOCKET_IS_BLOCKING ;
366+ else if (s -> sock_timeout == 0.0 )
367+ return SOCKET_IS_NONBLOCKING ;
349368
350369 /* Guard against closed socket */
351370 if (s -> sock_fd < 0 )
352- return 0 ;
371+ return SOCKET_HAS_BEEN_CLOSED ;
353372
354373 /* Construct the arguments to select */
355374 tv .tv_sec = (int )s -> sock_timeout ;
@@ -365,25 +384,29 @@ wait_for_timeout(PySocketSockObject *s, int writing)
365384 rc = select (s -> sock_fd + 1 , & fds , NULL , NULL , & tv );
366385 Py_END_ALLOW_THREADS
367386
368- /* Return 1 on timeout, 0 otherwise */
369- return rc == 0 ;
387+ /* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise
388+ (when we are able to write or when there's something to read) */
389+ return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK ;
370390}
371391
372392static PyObject * PySSL_SSLwrite (PySSLObject * self , PyObject * args )
373393{
374394 char * data ;
375395 int len ;
376396 int count ;
377- int timedout ;
397+ int sockstate ;
378398 int err ;
379399
380400 if (!PyArg_ParseTuple (args , "s#:write" , & data , & count ))
381401 return NULL ;
382402
383- timedout = wait_for_timeout (self -> Socket , 1 );
384- if (timedout ) {
403+ sockstate = check_socket_and_wait_for_timeout (self -> Socket , 1 );
404+ if (sockstate == SOCKET_HAS_TIMED_OUT ) {
385405 PyErr_SetString (PySSLErrorObject , "The write operation timed out" );
386406 return NULL ;
407+ } else if (sockstate == SOCKET_HAS_BEEN_CLOSED ) {
408+ PyErr_SetString (PySSLErrorObject , "Underlying socket has been closed." );
409+ return NULL ;
387410 }
388411 do {
389412 err = 0 ;
@@ -395,13 +418,20 @@ static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args)
395418 return NULL ;
396419 }
397420 if (err == SSL_ERROR_WANT_READ ) {
398- timedout = wait_for_timeout (self -> Socket , 0 );
421+ sockstate = check_socket_and_wait_for_timeout (self -> Socket , 0 );
399422 } else if (err == SSL_ERROR_WANT_WRITE ) {
400- timedout = wait_for_timeout (self -> Socket , 1 );
423+ sockstate = check_socket_and_wait_for_timeout (self -> Socket , 1 );
424+ } else {
425+ sockstate = SOCKET_OPERATION_OK ;
401426 }
402- if (timedout ) {
427+ if (sockstate == SOCKET_HAS_TIMED_OUT ) {
403428 PyErr_SetString (PySSLErrorObject , "The write operation timed out" );
404429 return NULL ;
430+ } else if (sockstate == SOCKET_HAS_BEEN_CLOSED ) {
431+ PyErr_SetString (PySSLErrorObject , "Underlying socket has been closed." );
432+ return NULL ;
433+ } else if (sockstate == SOCKET_IS_NONBLOCKING ) {
434+ break ;
405435 }
406436 } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE );
407437 if (len > 0 )
@@ -421,7 +451,7 @@ static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args)
421451 PyObject * buf ;
422452 int count = 0 ;
423453 int len = 1024 ;
424- int timedout ;
454+ int sockstate ;
425455 int err ;
426456
427457 if (!PyArg_ParseTuple (args , "|i:read" , & len ))
@@ -430,8 +460,8 @@ static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args)
430460 if (!(buf = PyString_FromStringAndSize ((char * ) 0 , len )))
431461 return NULL ;
432462
433- timedout = wait_for_timeout (self -> Socket , 0 );
434- if (timedout ) {
463+ sockstate = check_socket_and_wait_for_timeout (self -> Socket , 0 );
464+ if (sockstate == SOCKET_HAS_TIMED_OUT ) {
435465 PyErr_SetString (PySSLErrorObject , "The read operation timed out" );
436466 Py_DECREF (buf );
437467 return NULL ;
@@ -447,14 +477,18 @@ static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args)
447477 return NULL ;
448478 }
449479 if (err == SSL_ERROR_WANT_READ ) {
450- timedout = wait_for_timeout (self -> Socket , 0 );
480+ sockstate = check_socket_and_wait_for_timeout (self -> Socket , 0 );
451481 } else if (err == SSL_ERROR_WANT_WRITE ) {
452- timedout = wait_for_timeout (self -> Socket , 1 );
482+ sockstate = check_socket_and_wait_for_timeout (self -> Socket , 1 );
483+ } else {
484+ sockstate = SOCKET_OPERATION_OK ;
453485 }
454- if (timedout ) {
486+ if (sockstate == SOCKET_HAS_TIMED_OUT ) {
455487 PyErr_SetString (PySSLErrorObject , "The read operation timed out" );
456488 Py_DECREF (buf );
457489 return NULL ;
490+ } else if (sockstate == SOCKET_IS_NONBLOCKING ) {
491+ break ;
458492 }
459493 } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE );
460494 if (count <= 0 ) {
0 commit comments