long hb_ssl_socketRead( PHB_SSLSTREAM pStream, HB_SOCKET sd, void * buffer, long len, HB_MAXINT timeout ) { HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); long lRead = -1; int iToRead = -1; /* sd = SSL_get_rfd( pStream->ssl ); */ #if LONG_MAX > INT_MAX if( len > INT_MAX ) len = INT_MAX; #endif #if 0 while( ERR_get_error() != 0 ) { /* eat pending errors */ } #endif if( pStream->blocking ? timeout >= 0 : timeout < 0 ) { if( hb_socketSetBlockingIO( sd, timeout < 0 ) >= 0 ) pStream->blocking = ! pStream->blocking; } if( len > 0 ) { iToRead = SSL_pending( pStream->ssl ); if( iToRead <= 0 ) { iToRead = timeout < 0 ? 1 : hb_socketSelectRead( sd, timeout ); if( iToRead > 0 ) iToRead = ( int ) len; else if( iToRead == 0 ) hb_socketSetError( HB_SOCKET_ERR_TIMEOUT ); } else if( iToRead > len ) iToRead = ( int ) len; } while( iToRead > 0 ) { lRead = SSL_read( pStream->ssl, buffer, iToRead ); if( lRead > 0 ) hb_socketSetError( 0 ); else { int iError = SSL_get_error( pStream->ssl, ( int ) lRead ); switch( iError ) { case SSL_ERROR_ZERO_RETURN: hb_socketSetError( HB_SOCKET_ERR_PIPE ); lRead = 0; break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: if( hb_vmRequestQuery() == 0 ) { if( timeout > 0 ) { HB_MAXUINT timecurr = hb_dateMilliSeconds(); if( timecurr > timer ) timeout -= timecurr - timer; if( timeout > 0 ) { timer = timecurr; if( iError == SSL_ERROR_WANT_READ ) iError = hb_socketSelectRead( sd, timeout ); else iError = hb_socketSelectWrite( sd, timeout ); if( iError > 0 ) continue; else if( iError < 0 ) break; } } hb_socketSetError( HB_SOCKET_ERR_TIMEOUT ); break; } default: hb_socketSetError( HB_SSL_SOCK_ERROR_BASE + iError ); } } break; } return lRead; }
long hb_ssl_socketWrite( PHB_SSLSTREAM pStream, HB_SOCKET sd, const void * buffer, long len, HB_MAXINT timeout, long * plast ) { HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); long lWritten = 0, lWr = 0; /* sd = SSL_get_wfd( pStream->ssl ); */ #if LONG_MAX > INT_MAX if( len > INT_MAX ) len = INT_MAX; #endif #if 0 while( ERR_get_error() != 0 ) { /* eat pending errors */ } #endif if( pStream->blocking ? timeout >= 0 : timeout < 0 ) { if( hb_socketSetBlockingIO( sd, timeout < 0 ) >= 0 ) pStream->blocking = ! pStream->blocking; } while( len > 0 ) { lWr = SSL_write( pStream->ssl, buffer, ( int ) len ); if( plast ) *plast = lWr; if( lWr > 0 ) { lWritten += lWr; len -= lWr; buffer = ( const char * ) buffer + lWr; hb_socketSetError( 0 ); } else { int iError = SSL_get_error( pStream->ssl, ( int ) lWr ); switch( iError ) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: if( hb_vmRequestQuery() == 0 ) { if( timeout > 0 ) { HB_MAXUINT timecurr = hb_dateMilliSeconds(); if( timecurr > timer ) timeout -= timecurr - timer; if( timeout > 0 ) { timer = timecurr; if( iError == SSL_ERROR_WANT_READ ) iError = hb_socketSelectRead( sd, timeout ); else iError = hb_socketSelectWrite( sd, timeout ); if( iError > 0 ) continue; } else iError = 0; } else iError = 0; if( lWritten == 0 && iError == 0 ) hb_socketSetError( HB_SOCKET_ERR_TIMEOUT ); break; } default: hb_socketSetError( HB_SSL_SOCK_ERROR_BASE + iError ); } break; } } return lWritten != 0 ? lWritten : lWr; }
PHB_SSLSTREAM hb_ssl_socketNew( HB_SOCKET sd, SSL * ssl, HB_BOOL fServer, HB_MAXINT timeout, PHB_ITEM pSSL, int * piResult ) { int iResult; PHB_SSLSTREAM pStream; HB_MAXUINT timer; pStream = ( HB_SSLSTREAM * ) hb_xgrabz( sizeof( HB_SSLSTREAM ) ); timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); pStream->ssl = ssl; pStream->pSSL = pSSL ? hb_itemNew( pSSL ) : NULL; pStream->blocking = timeout < 0; if( hb_socketSetBlockingIO( sd, pStream->blocking ) < 0 ) pStream->blocking = ! pStream->blocking; SSL_set_mode( ssl, HB_SSL_MODE_AUTO_RETRY ); iResult = SSL_set_fd( ssl, sd ); /* Truncates `sd` on win64. OpenSSL bug: https://rt.openssl.org/Ticket/Display.html?id=1928&user=guest&pass=guest */ while( iResult == 1 ) { if( fServer ) iResult = SSL_accept( ssl ); else iResult = SSL_connect( ssl ); if( iResult != 1 && hb_vmRequestQuery() == 0 ) { int iError = SSL_get_error( ssl, iResult ); if( iError == SSL_ERROR_WANT_READ || iError == SSL_ERROR_WANT_WRITE ) { if( timeout < 0 ) { iResult = 1; continue; } else if( timeout > 0 ) { HB_MAXUINT timecurr = hb_dateMilliSeconds(); if( timecurr > timer ) { timeout -= timecurr - timer; if( timeout < 0 ) timeout = 0; timer = timecurr; } if( timeout > 0 ) { if( iError == SSL_ERROR_WANT_READ ) iError = hb_socketSelectRead( sd, timeout ); else iError = hb_socketSelectWrite( sd, timeout ); if( iError > 0 ) { iResult = 1; continue; } } } hb_socketSetError( HB_SOCKET_ERR_TIMEOUT ); } } break; } if( iResult != 1 ) { hb_ssl_socketClose( pStream ); pStream = NULL; } else pStream->blocking = hb_socketSetBlockingIO( sd, HB_FALSE ) < 0; if( piResult ) *piResult = iResult; return pStream; }
PHB_SSLSTREAM hb_ssl_socketNew( HB_SOCKET sd, SSL * ssl, HB_BOOL fServer, HB_MAXINT timeout, int * piResult ) { int iResult; PHB_SSLSTREAM pStream; HB_MAXUINT timer; pStream = ( HB_SSLSTREAM * ) hb_xgrabz( sizeof( HB_SSLSTREAM ) ); timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); pStream->ssl = ssl; pStream->pSSL = hb_itemNew( hb_param( 2, HB_IT_POINTER ) ); pStream->blocking = timeout < 0; if( hb_socketSetBlockingIO( sd, pStream->blocking ) < 0 ) pStream->blocking = ! pStream->blocking; SSL_set_mode( ssl, HB_SSL_MODE_AUTO_RETRY ); iResult = SSL_set_fd( ssl, sd ); while( iResult == 1 ) { if( fServer ) iResult = SSL_accept( ssl ); else iResult = SSL_connect( ssl ); if( iResult != 1 && hb_vmRequestQuery() == 0 ) { int iError = SSL_get_error( ssl, iResult ); if( iError == SSL_ERROR_WANT_READ || iError == SSL_ERROR_WANT_WRITE ) { if( timeout < 0 ) { iResult = 1; continue; } else if( timeout > 0 ) { HB_MAXUINT timecurr = hb_dateMilliSeconds(); if( timecurr > timer ) { timeout -= timecurr - timer; timer = timecurr; } if( timeout > 0 ) { if( iError == SSL_ERROR_WANT_READ ) iError = hb_socketSelectRead( sd, timeout ); else iError = hb_socketSelectWrite( sd, timeout ); if( iError > 0 ) { iResult = 1; continue; } } } hb_socketSetError( HB_SOCKET_ERR_TIMEOUT ); } } break; } if( iResult != 1 ) { hb_ssl_socketClose( pStream ); pStream = NULL; } else pStream->blocking = hb_socketSetBlockingIO( sd, HB_FALSE ) < 0; if( piResult ) *piResult = iResult; return pStream; }