@@ -321,6 +321,11 @@ typedef struct {
321321 enum py_ssl_server_or_client socket_type ;
322322 PyObject * owner ; /* Python level "owner" passed to servername callback */
323323 PyObject * server_hostname ;
324+ int ssl_errno ; /* last seen error from SSL */
325+ int c_errno ; /* last seen error from libc */
326+ #ifdef MS_WINDOWS
327+ int ws_errno ; /* last seen error from winsock */
328+ #endif
324329} PySSLSocket ;
325330
326331typedef struct {
@@ -340,6 +345,21 @@ static PyTypeObject PySSLSocket_Type;
340345static PyTypeObject PySSLMemoryBIO_Type ;
341346static PyTypeObject PySSLSession_Type ;
342347
348+ #ifdef MS_WINDOWS
349+ #define _PySSL_UPDATE_ERRNO_IF (cond , sock , retcode ) if (cond) { \
350+ (sock)->ws_errno = WSAGetLastError(); \
351+ _PySSL_FIX_ERRNO; \
352+ (sock)->c_errno = errno; \
353+ (sock)->ssl_errno = SSL_get_error((sock->ssl), (retcode)); \
354+ } else { sock->ws_errno = 0; sock->c_errno = 0; sock->ssl_errno = 0; }
355+ #else
356+ #define _PySSL_UPDATE_ERRNO_IF (cond , sock , retcode ) if (cond) { \
357+ (sock)->c_errno = errno; \
358+ (sock)->ssl_errno = SSL_get_error((sock->ssl), (retcode)); \
359+ } else { (sock)->c_errno = 0; (sock)->ssl_errno = 0; }
360+ #endif
361+ #define _PySSL_UPDATE_ERRNO (sock , retcode ) _PySSL_UPDATE_ERRNO_IF(1, (sock), (retcode))
362+
343363/*[clinic input]
344364module _ssl
345365class _ssl._SSLContext "PySSLContext *" "&PySSLContext_Type"
@@ -580,7 +600,7 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno)
580600 e = ERR_peek_last_error ();
581601
582602 if (sslsock -> ssl != NULL ) {
583- err = SSL_get_error ( sslsock -> ssl , ret ) ;
603+ err = sslsock -> ssl_errno ;
584604
585605 switch (err ) {
586606 case SSL_ERROR_ZERO_RETURN :
@@ -616,8 +636,16 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno)
616636 errstr = "EOF occurred in violation of protocol" ;
617637 } else if (s && ret == -1 ) {
618638 /* underlying BIO reported an I/O error */
619- Py_INCREF (s );
620639 ERR_clear_error ();
640+ #ifdef MS_WINDOWS
641+ if (sslsock -> ws_errno )
642+ return PyErr_SetFromWindowsErr (sslsock -> ws_errno );
643+ #endif
644+ if (sslsock -> c_errno ) {
645+ errno = sslsock -> c_errno ;
646+ return PyErr_SetFromErrno (PyExc_OSError );
647+ }
648+ Py_INCREF (s );
621649 s -> errorhandler ();
622650 Py_DECREF (s );
623651 return NULL ;
@@ -696,6 +724,11 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
696724 }
697725 self -> server_hostname = hostname ;
698726 }
727+ self -> ssl_errno = 0 ;
728+ self -> c_errno = 0 ;
729+ #ifdef MS_WINDOWS
730+ self -> ws_errno = 0 ;
731+ #endif
699732
700733 /* Make sure the SSL error state is initialized */
701734 (void ) ERR_get_state ();
@@ -792,8 +825,9 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
792825 do {
793826 PySSL_BEGIN_ALLOW_THREADS
794827 ret = SSL_do_handshake (self -> ssl );
795- err = SSL_get_error ( self -> ssl , ret );
828+ _PySSL_UPDATE_ERRNO_IF ( ret < 1 , self , ret );
796829 PySSL_END_ALLOW_THREADS
830+ err = self -> ssl_errno ;
797831
798832 if (PyErr_CheckSignals ())
799833 goto error ;
@@ -2064,8 +2098,9 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
20642098 do {
20652099 PySSL_BEGIN_ALLOW_THREADS
20662100 len = SSL_write (self -> ssl , b -> buf , (int )b -> len );
2067- err = SSL_get_error ( self -> ssl , len );
2101+ _PySSL_UPDATE_ERRNO_IF ( len <= 0 , self , len );
20682102 PySSL_END_ALLOW_THREADS
2103+ err = self -> ssl_errno ;
20692104
20702105 if (PyErr_CheckSignals ())
20712106 goto error ;
@@ -2119,6 +2154,7 @@ _ssl__SSLSocket_pending_impl(PySSLSocket *self)
21192154
21202155 PySSL_BEGIN_ALLOW_THREADS
21212156 count = SSL_pending (self -> ssl );
2157+ _PySSL_UPDATE_ERRNO_IF (count < 0 , self , count );
21222158 PySSL_END_ALLOW_THREADS
21232159 if (count < 0 )
21242160 return PySSL_SetError (self , count , __FILE__ , __LINE__ );
@@ -2207,7 +2243,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
22072243 do {
22082244 PySSL_BEGIN_ALLOW_THREADS
22092245 count = SSL_read (self -> ssl , mem , len );
2210- err = SSL_get_error ( self -> ssl , count );
2246+ _PySSL_UPDATE_ERRNO_IF ( count <= 0 , self , count );
22112247 PySSL_END_ALLOW_THREADS
22122248
22132249 if (PyErr_CheckSignals ())
@@ -2216,6 +2252,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
22162252 if (has_timeout )
22172253 timeout = deadline - _PyTime_GetMonotonicClock ();
22182254
2255+ err = self -> ssl_errno ;
22192256 if (err == SSL_ERROR_WANT_READ ) {
22202257 sockstate = PySSL_select (sock , 0 , timeout );
22212258 } else if (err == SSL_ERROR_WANT_WRITE ) {
@@ -2272,7 +2309,7 @@ static PyObject *
22722309_ssl__SSLSocket_shutdown_impl (PySSLSocket * self )
22732310/*[clinic end generated code: output=ca1aa7ed9d25ca42 input=ede2cc1a2ddf0ee4]*/
22742311{
2275- int err , ssl_err , sockstate , nonblocking ;
2312+ int err , sockstate , nonblocking ;
22762313 int zeros = 0 ;
22772314 PySocketSockObject * sock = GET_SOCKET (self );
22782315 _PyTime_t timeout , deadline = 0 ;
@@ -2311,6 +2348,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
23112348 if (self -> shutdown_seen_zero )
23122349 SSL_set_read_ahead (self - > ssl , 0 );
23132350 err = SSL_shutdown (self -> ssl );
2351+ _PySSL_UPDATE_ERRNO_IF (err < 0 , self , err );
23142352 PySSL_END_ALLOW_THREADS
23152353
23162354 /* If err == 1, a secure shutdown with SSL_shutdown() is complete */
@@ -2331,16 +2369,16 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
23312369 timeout = deadline - _PyTime_GetMonotonicClock ();
23322370
23332371 /* Possibly retry shutdown until timeout or failure */
2334- ssl_err = SSL_get_error (self -> ssl , err );
2335- if (ssl_err == SSL_ERROR_WANT_READ )
2372+ _PySSL_UPDATE_ERRNO (self , err );
2373+ if (self -> ssl_errno == SSL_ERROR_WANT_READ )
23362374 sockstate = PySSL_select (sock , 0 , timeout );
2337- else if (ssl_err == SSL_ERROR_WANT_WRITE )
2375+ else if (self -> ssl_errno == SSL_ERROR_WANT_WRITE )
23382376 sockstate = PySSL_select (sock , 1 , timeout );
23392377 else
23402378 break ;
23412379
23422380 if (sockstate == SOCKET_HAS_TIMED_OUT ) {
2343- if (ssl_err == SSL_ERROR_WANT_READ )
2381+ if (self -> ssl_errno == SSL_ERROR_WANT_READ )
23442382 PyErr_SetString (PySocketModule .timeout_error ,
23452383 "The read operation timed out" );
23462384 else
0 commit comments