@@ -302,6 +302,11 @@ typedef struct {
302302 enum py_ssl_server_or_client socket_type ;
303303 PyObject * owner ; /* Python level "owner" passed to servername callback */
304304 PyObject * server_hostname ;
305+ int ssl_errno ; /* last seen error from SSL */
306+ int c_errno ; /* last seen error from libc */
307+ #ifdef MS_WINDOWS
308+ int ws_errno ; /* last seen error from winsock */
309+ #endif
305310} PySSLSocket ;
306311
307312typedef struct {
@@ -321,6 +326,20 @@ static PyTypeObject PySSLSocket_Type;
321326static PyTypeObject PySSLMemoryBIO_Type ;
322327static PyTypeObject PySSLSession_Type ;
323328
329+ #ifdef MS_WINDOWS
330+ #define _PySSL_UPDATE_ERRNO_IF (cond , sock , retcode ) if (cond) { \
331+ (sock)->ws_errno = WSAGetLastError(); \
332+ (sock)->c_errno = errno; \
333+ (sock)->ssl_errno = SSL_get_error((sock->ssl), (retcode)); \
334+ } else { sock->ws_errno = 0; sock->c_errno = 0; sock->ssl_errno = 0; }
335+ #else
336+ #define _PySSL_UPDATE_ERRNO_IF (cond , sock , retcode ) if (cond) { \
337+ (sock)->c_errno = errno; \
338+ (sock)->ssl_errno = SSL_get_error((sock->ssl), (retcode)); \
339+ } else { (sock)->c_errno = 0; (sock)->ssl_errno = 0; }
340+ #endif
341+ #define _PySSL_UPDATE_ERRNO (sock , retcode ) _PySSL_UPDATE_ERRNO_IF(1, (sock), (retcode))
342+
324343/*[clinic input]
325344module _ssl
326345class _ssl._SSLContext "PySSLContext *" "&PySSLContext_Type"
@@ -494,7 +513,7 @@ PySSL_SetError(PySSLSocket *obj, int ret, const char *filename, int lineno)
494513 e = ERR_peek_last_error ();
495514
496515 if (obj -> ssl != NULL ) {
497- err = SSL_get_error ( obj -> ssl , ret ) ;
516+ err = obj -> ssl_errno ;
498517
499518 switch (err ) {
500519 case SSL_ERROR_ZERO_RETURN :
@@ -530,8 +549,16 @@ PySSL_SetError(PySSLSocket *obj, int ret, const char *filename, int lineno)
530549 errstr = "EOF occurred in violation of protocol" ;
531550 } else if (s && ret == -1 ) {
532551 /* underlying BIO reported an I/O error */
533- Py_INCREF (s );
534552 ERR_clear_error ();
553+ #ifdef MS_WINDOWS
554+ if (obj -> ws_errno )
555+ return PyErr_SetFromWindowsErr (obj -> ws_errno );
556+ #endif
557+ if (obj -> c_errno ) {
558+ errno = obj -> c_errno ;
559+ return PyErr_SetFromErrno (PyExc_OSError );
560+ }
561+ Py_INCREF (s );
535562 s -> errorhandler ();
536563 Py_DECREF (s );
537564 return NULL ;
@@ -609,6 +636,11 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
609636 }
610637 self -> server_hostname = hostname ;
611638 }
639+ self -> ssl_errno = 0 ;
640+ self -> c_errno = 0 ;
641+ #ifdef MS_WINDOWS
642+ self -> ws_errno = 0 ;
643+ #endif
612644
613645 /* Make sure the SSL error state is initialized */
614646 (void ) ERR_get_state ();
@@ -706,8 +738,9 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
706738 do {
707739 PySSL_BEGIN_ALLOW_THREADS
708740 ret = SSL_do_handshake (self -> ssl );
709- err = SSL_get_error ( self -> ssl , ret );
741+ _PySSL_UPDATE_ERRNO_IF ( ret < 1 , self , ret );
710742 PySSL_END_ALLOW_THREADS
743+ err = self -> ssl_errno ;
711744
712745 if (PyErr_CheckSignals ())
713746 goto error ;
@@ -2003,8 +2036,9 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
20032036 do {
20042037 PySSL_BEGIN_ALLOW_THREADS
20052038 len = SSL_write (self -> ssl , b -> buf , (int )b -> len );
2006- err = SSL_get_error ( self -> ssl , len );
2039+ _PySSL_UPDATE_ERRNO_IF ( len <= 0 , self , len );
20072040 PySSL_END_ALLOW_THREADS
2041+ err = self -> ssl_errno ;
20082042
20092043 if (PyErr_CheckSignals ())
20102044 goto error ;
@@ -2058,6 +2092,7 @@ _ssl__SSLSocket_pending_impl(PySSLSocket *self)
20582092
20592093 PySSL_BEGIN_ALLOW_THREADS
20602094 count = SSL_pending (self -> ssl );
2095+ _PySSL_UPDATE_ERRNO_IF (count < 0 , self , count );
20612096 PySSL_END_ALLOW_THREADS
20622097 if (count < 0 )
20632098 return PySSL_SetError (self , count , __FILE__ , __LINE__ );
@@ -2146,7 +2181,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
21462181 do {
21472182 PySSL_BEGIN_ALLOW_THREADS
21482183 count = SSL_read (self -> ssl , mem , len );
2149- err = SSL_get_error ( self -> ssl , count );
2184+ _PySSL_UPDATE_ERRNO_IF ( count <= 0 , self , count );
21502185 PySSL_END_ALLOW_THREADS
21512186
21522187 if (PyErr_CheckSignals ())
@@ -2155,6 +2190,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
21552190 if (has_timeout )
21562191 timeout = deadline - _PyTime_GetMonotonicClock ();
21572192
2193+ err = self -> ssl_errno ;
21582194 if (err == SSL_ERROR_WANT_READ ) {
21592195 sockstate = PySSL_select (sock , 0 , timeout );
21602196 } else if (err == SSL_ERROR_WANT_WRITE ) {
@@ -2211,7 +2247,7 @@ static PyObject *
22112247_ssl__SSLSocket_shutdown_impl (PySSLSocket * self )
22122248/*[clinic end generated code: output=ca1aa7ed9d25ca42 input=ede2cc1a2ddf0ee4]*/
22132249{
2214- int err , ssl_err , sockstate , nonblocking ;
2250+ int err , sockstate , nonblocking ;
22152251 int zeros = 0 ;
22162252 PySocketSockObject * sock = GET_SOCKET (self );
22172253 _PyTime_t timeout , deadline = 0 ;
@@ -2250,6 +2286,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
22502286 if (self -> shutdown_seen_zero )
22512287 SSL_set_read_ahead (self - > ssl , 0 );
22522288 err = SSL_shutdown (self -> ssl );
2289+ _PySSL_UPDATE_ERRNO_IF (err < 0 , self , err );
22532290 PySSL_END_ALLOW_THREADS
22542291
22552292 /* If err == 1, a secure shutdown with SSL_shutdown() is complete */
@@ -2270,16 +2307,16 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
22702307 timeout = deadline - _PyTime_GetMonotonicClock ();
22712308
22722309 /* Possibly retry shutdown until timeout or failure */
2273- ssl_err = SSL_get_error (self -> ssl , err );
2274- if (ssl_err == SSL_ERROR_WANT_READ )
2310+ _PySSL_UPDATE_ERRNO (self , err );
2311+ if (self -> ssl_errno == SSL_ERROR_WANT_READ )
22752312 sockstate = PySSL_select (sock , 0 , timeout );
2276- else if (ssl_err == SSL_ERROR_WANT_WRITE )
2313+ else if (self -> ssl_errno == SSL_ERROR_WANT_WRITE )
22772314 sockstate = PySSL_select (sock , 1 , timeout );
22782315 else
22792316 break ;
22802317
22812318 if (sockstate == SOCKET_HAS_TIMED_OUT ) {
2282- if (ssl_err == SSL_ERROR_WANT_READ )
2319+ if (self -> ssl_errno == SSL_ERROR_WANT_READ )
22832320 PyErr_SetString (PySocketModule .timeout_error ,
22842321 "The read operation timed out" );
22852322 else
0 commit comments