2424#include " jliball.hpp"
2525#include " string.h"
2626#include < atomic>
27+ #include < limits>
2728#include < mutex>
2829
2930#ifdef _WIN32
@@ -364,7 +365,8 @@ class CAsyncTLSWriteHandler : public CAsyncTLSHandlerBase
364365 {
365366 case TLSWriteState::WantRead:
366367 // Renegotiation data arrived, feed to BIO and retry write
367- BIO_write (network_bio, encryptedBuffer.bytes (), result);
368+ if (BIO_write (network_bio, encryptedBuffer.bytes (), result) != result)
369+ return handleError (-1 );
368370 complete = safeTryOperation ();
369371 break ;
370372
@@ -598,6 +600,8 @@ class CSecureSocket : implements ISecureSocket, public CInterface
598600private:
599601 StringBuffer& get_cn (X509* cert, StringBuffer& cn);
600602 void handleError (int ssl_err, bool writing, bool wait, unsigned timeoutMs, const char *opStr);
603+ bool flushPendingEncryptedOutput (CCycleTimer &timer, unsigned timeoutMs, const char *opStr);
604+ size32_t readAndQueueEncryptedSocketInput (CCycleTimer &timer, unsigned timeoutMs, const char *opStr);
601605
602606 // Make verify_cert and network_bio accessible to async handlers
603607 friend class CAsyncTLSAcceptHandler ;
@@ -1693,7 +1697,8 @@ bool CAsyncTLSReadHandler::onAsyncComplete(int result)
16931697 if (state == TLSReadState::WantRead && result > 0 )
16941698 {
16951699 // Feed received encrypted bytes to SSL's network BIO
1696- BIO_write (network_bio, encryptedBuffer.bytes (), result);
1700+ if (BIO_write (network_bio, encryptedBuffer.bytes (), result) != result)
1701+ return handleError (-1 );
16971702 state = TLSReadState::Reading;
16981703 }
16991704 else if (state == TLSReadState::WantWrite)
@@ -1735,8 +1740,9 @@ bool CAsyncTLSReadHandler::tryRead()
17351740 while (totalRead < minSize && totalRead < maxSize)
17361741 {
17371742 size32_t bytesToRead = maxSize - totalRead;
1738-
1739- int ret = SSL_read (ssl, (char *)appBuffer + totalRead, bytesToRead);
1743+ size32_t readChunk = std::min (bytesToRead, (size32_t )std::numeric_limits<int >::max ());
1744+
1745+ int ret = SSL_read (ssl, (char *)appBuffer + totalRead, (int )readChunk);
17401746
17411747 if (ret > 0 )
17421748 {
@@ -1974,6 +1980,39 @@ void CSecureSocket::handleError(int ssl_err, bool writing, bool wait, unsigned t
19741980 }
19751981}
19761982
1983+ bool CSecureSocket::flushPendingEncryptedOutput (CCycleTimer &timer, unsigned timeoutMs, const char *opStr)
1984+ {
1985+ byte encryptedWriteBuffer[16384 ];
1986+
1987+ bool flushed = false ;
1988+ while (true )
1989+ {
1990+ int pending = BIO_pending (network_bio);
1991+ if (pending <= 0 )
1992+ return flushed;
1993+
1994+ size32_t chunk = std::min ((size32_t )pending, (size32_t )sizeof (encryptedWriteBuffer));
1995+ int bytesRead = BIO_read (network_bio, encryptedWriteBuffer, chunk);
1996+ if (bytesRead <= 0 )
1997+ THROWJSOCKEXCEPTION_MSG (-1 , VStringBuffer (" %s: failed to drain encrypted TLS output" , opStr).str ());
1998+
1999+ unsigned remainingMs = timer.remainingMs (timeoutMs);
2000+ m_socket->writetms (encryptedWriteBuffer, bytesRead, bytesRead, remainingMs);
2001+ flushed = true ;
2002+ }
2003+ }
2004+
2005+ size32_t CSecureSocket::readAndQueueEncryptedSocketInput (CCycleTimer &timer, unsigned timeoutMs, const char *opStr)
2006+ {
2007+ byte encryptedReadBuffer[16384 ];
2008+ size32_t encryptedRead = 0 ;
2009+ unsigned remainingMs = timer.remainingMs (timeoutMs);
2010+ m_socket->readtms (encryptedReadBuffer, 1 , sizeof (encryptedReadBuffer), encryptedRead, remainingMs);
2011+ if (encryptedRead > 0 && BIO_write (network_bio, encryptedReadBuffer, encryptedRead) != encryptedRead)
2012+ THROWJSOCKEXCEPTION_MSG (-1 , VStringBuffer (" %s: failed to queue encrypted socket input" , opStr).str ());
2013+ return encryptedRead;
2014+ }
2015+
19772016int CSecureSocket::secure_connect (int logLevel)
19782017{
19792018 if (m_fqdn.length () > 0 )
@@ -2052,10 +2091,85 @@ void CSecureSocket::readtms(void* buf, size32_t min_size, size32_t max_size, siz
20522091 // because we may not get another poll notification because SSL internally has read everything.
20532092 sizeRead = 0 ;
20542093 CCycleTimer timer;
2094+
2095+ if (network_bio)
2096+ {
2097+
2098+ while (true )
2099+ {
2100+ ERR_clear_error ();
2101+ size32_t bytesToRead = max_size - sizeRead;
2102+ size32_t readChunk = std::min (bytesToRead, (size32_t )std::numeric_limits<int >::max ());
2103+ int rc = SSL_read (m_ssl, (char *)buf + sizeRead, (int )readChunk);
2104+ unsigned remainingMs = timer.remainingMs (timeoutMs);
2105+ if (rc > 0 )
2106+ {
2107+ sizeRead += rc;
2108+ if (sizeRead == max_size)
2109+ break ;
2110+ if (0 == remainingMs)
2111+ {
2112+ if (sizeRead >= min_size)
2113+ break ;
2114+ THROWJSOCKEXCEPTION_MSG (JSOCKERR_timeout_expired, " timeout expired" );
2115+ }
2116+ continue ;
2117+ }
2118+
2119+ if (0 == rc)
2120+ {
2121+ m_socket->shutdownNoThrow ();
2122+ if (suppresGCIfMinSize && (sizeRead >= min_size))
2123+ break ;
2124+ THROWJSOCKEXCEPTION (JSOCKERR_graceful_close);
2125+ }
2126+
2127+ int ssl_err = SSL_get_error (m_ssl, rc);
2128+ if (ssl_err == SSL_ERROR_WANT_READ)
2129+ {
2130+ if (sizeRead >= min_size)
2131+ break ;
2132+
2133+ flushPendingEncryptedOutput (timer, timeoutMs, " SSL_read" );
2134+
2135+ size32_t encryptedRead = readAndQueueEncryptedSocketInput (timer, timeoutMs, " SSL_read" );
2136+ if (encryptedRead == 0 )
2137+ {
2138+ m_socket->shutdownNoThrow ();
2139+ if (suppresGCIfMinSize && (sizeRead >= min_size))
2140+ break ;
2141+ THROWJSOCKEXCEPTION (JSOCKERR_graceful_close);
2142+ }
2143+ continue ;
2144+ }
2145+
2146+ if (ssl_err == SSL_ERROR_WANT_WRITE)
2147+ {
2148+ if (sizeRead >= min_size)
2149+ break ;
2150+
2151+ if (flushPendingEncryptedOutput (timer, timeoutMs, " SSL_read" ))
2152+ continue ;
2153+
2154+ // No TLS output to flush; use wait/write-error handling instead of spinning.
2155+ handleError (ssl_err, false , true , remainingMs, " SSL_read" );
2156+ continue ;
2157+ }
2158+
2159+ bool wait = sizeRead < min_size; // if >= min_size, then handleError will validate errors only
2160+ handleError (ssl_err, false , wait, remainingMs, " SSL_read" );
2161+ if (sizeRead >= min_size)
2162+ break ;
2163+ }
2164+ }
2165+ else
2166+ {
20552167 while (true )
20562168 {
20572169 ERR_clear_error ();
2058- int rc = SSL_read (m_ssl, (char *)buf + sizeRead, max_size - sizeRead);
2170+ size32_t bytesToRead = max_size - sizeRead;
2171+ size32_t readChunk = std::min (bytesToRead, (size32_t )std::numeric_limits<int >::max ());
2172+ int rc = SSL_read (m_ssl, (char *)buf + sizeRead, (int )readChunk);
20592173 unsigned remainingMs = timer.remainingMs (timeoutMs);
20602174 if (rc > 0 )
20612175 {
@@ -2087,6 +2201,7 @@ void CSecureSocket::readtms(void* buf, size32_t min_size, size32_t max_size, siz
20872201 break ;
20882202 }
20892203 }
2204+ }
20902205
20912206 cycle_t elapsedCycles = timer.elapsedCycles ();
20922207 if (!SSTATS)
@@ -2116,6 +2231,52 @@ size32_t CSecureSocket::writetms(void const* buf, size32_t minSize, size32_t siz
21162231 size32_t bytesWritten = 0 ;
21172232 size32_t bytesRemaining = size;
21182233 char *cbuf = (char *)buf;
2234+
2235+ if (network_bio)
2236+ {
2237+
2238+ ERR_clear_error ();
2239+ while (bytesRemaining)
2240+ {
2241+ size32_t bytesChunk = MIN (bytesRemaining, 0x4000 );
2242+ int rc = SSL_write (m_ssl, &cbuf[bytesWritten], bytesChunk);
2243+ if (rc > 0 )
2244+ {
2245+ dbgassertex (bytesChunk == rc);
2246+ bytesRemaining -= rc;
2247+ bytesWritten += rc;
2248+ flushPendingEncryptedOutput (timer, timeoutMs, " SSL_write" );
2249+ continue ;
2250+ }
2251+
2252+ int ssl_err = SSL_get_error (m_ssl, rc);
2253+ unsigned remainingMs = timer.remainingMs (timeoutMs);
2254+ if (ssl_err == SSL_ERROR_WANT_READ)
2255+ {
2256+ flushPendingEncryptedOutput (timer, timeoutMs, " SSL_write" );
2257+
2258+ size32_t encryptedRead = readAndQueueEncryptedSocketInput (timer, timeoutMs, " SSL_write" );
2259+ if (encryptedRead == 0 )
2260+ {
2261+ m_socket->shutdownNoThrow ();
2262+ THROWJSOCKEXCEPTION (JSOCKERR_graceful_close);
2263+ }
2264+ continue ;
2265+ }
2266+
2267+ if (ssl_err == SSL_ERROR_WANT_WRITE)
2268+ {
2269+ if (flushPendingEncryptedOutput (timer, timeoutMs, " SSL_write" ))
2270+ continue ;
2271+ }
2272+
2273+ handleError (ssl_err, true , true , remainingMs, " SSL_write" );
2274+ }
2275+
2276+ flushPendingEncryptedOutput (timer, timeoutMs, " SSL_write" );
2277+ }
2278+ else
2279+ {
21192280 ERR_clear_error ();
21202281 while (bytesRemaining)
21212282 {
@@ -2135,6 +2296,7 @@ size32_t CSecureSocket::writetms(void const* buf, size32_t minSize, size32_t siz
21352296 handleError (ssl_err, true , true , remainingMs, " SSL_write" );
21362297 }
21372298 }
2299+ }
21382300
21392301 cycle_t elapsedCycles = timer.elapsedCycles ();
21402302 if (!SSTATS)
0 commit comments