private void InternalReadCallback(IAsyncResult asyncResult)
{
InternalAsyncResult internalAsyncResult = (InternalAsyncResult)asyncResult.AsyncState;
bool haveDataToReturn = false;
try
{
int bytesRead = 0;
try
{
bytesRead = innerStream.EndRead(asyncResult);
}
catch (Exception ex)
{
// Set the exception into the internal async result
internalAsyncResult.SetComplete(ex);
}
if (bytesRead <= 0)
{
// Zero byte read most likely indicates connection closed (if it's a network stream)
internalAsyncResult.SetComplete(0);
return;
}
else
{
// Copy encrypted data into the SSL read_bio
read_bio.Write(read_buffer, bytesRead);
if (handShakeState == HandshakeState.InProcess ||
handShakeState == HandshakeState.RenegotiateInProcess)
{
// We are in the handshake, complete the async operation to fire the async
// handshake callback for processing
internalAsyncResult.SetComplete(bytesRead);
return;
}
uint nBytesPending = read_bio.BytesPending;
byte[] decrypted_buf = new byte[SSL3_RT_MAX_PACKET_SIZE];
while (nBytesPending > 0)
{
int decryptedBytesRead = ssl.Read(decrypted_buf, decrypted_buf.Length);
if (decryptedBytesRead <= 0)
{
SslError lastError = ssl.GetError(decryptedBytesRead);
if (lastError == SslError.SSL_ERROR_WANT_READ)
{
// if we have bytes pending in the write bio.
// the client has requested a renegotiation
if (write_bio.BytesPending > 0)
{
// Start the renegotiation by writing the write_bio data, and use the RenegotiationWriteCallback
// to handle the rest of the renegotiation
ArraySegment<byte> buf = write_bio.ReadBytes((int)write_bio.BytesPending);
innerStream.BeginWrite(buf.Array, 0, buf.Count, new AsyncCallback(RenegotiationWriteCallback), internalAsyncResult);
return;
}
// no data in the out bio, we just need more data to complete the record
//break;
}
else if (lastError == SslError.SSL_ERROR_WANT_WRITE)
{
// unexpected error!
//!!TODO debug log
}
else if (lastError == SslError.SSL_ERROR_ZERO_RETURN)
{
// Shutdown alert
SendShutdownAlert();
break;
}
else
{
throw new OpenSslException();
}
}
if (decryptedBytesRead > 0)
{
// Write decrypted data to memory stream
long pos = decrypted_data_stream.Position;
decrypted_data_stream.Seek(0, SeekOrigin.End);
decrypted_data_stream.Write(decrypted_buf, 0, decryptedBytesRead);
decrypted_data_stream.Seek(pos, SeekOrigin.Begin);
haveDataToReturn = true;
}
// See if we have more data to process
nBytesPending = read_bio.BytesPending;
}
// Check to see if we have data to return, if not, fire the async read again
if (!haveDataToReturn)
{
innerStream.BeginRead(read_buffer, 0, read_buffer.Length, new AsyncCallback(InternalReadCallback), internalAsyncResult);
}
else
{
int bytesReadIntoUserBuffer = 0;
// Read the data into the buffer provided by the user (now hosted in the InternalAsyncResult)
bytesReadIntoUserBuffer = decrypted_data_stream.Read(internalAsyncResult.Buffer, internalAsyncResult.Offset, internalAsyncResult.Count);
internalAsyncResult.SetComplete(bytesReadIntoUserBuffer);
}
}
}
catch (Exception ex)
{
internalAsyncResult.SetComplete(ex);
}
}