private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
{
if (asyncRequest != null)
{
asyncRequest.SetNextRequest(buffer, offset, count, s_resumeAsyncWriteCallback);
}
// We loop to this method from the callback.
// If the last chunk was just completed from async callback (count < 0), we complete user request.
if (count >= 0 )
{
byte[] outBuffer = null;
if (_pinnableOutputBufferInUse == null)
{
if (_pinnableOutputBuffer == null)
{
_pinnableOutputBuffer = s_PinnableWriteBufferCache.AllocateBuffer();
}
_pinnableOutputBufferInUse = buffer;
outBuffer = _pinnableOutputBuffer;
if (PinnableBufferCacheEventSource.Log.IsEnabled())
{
PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Trying Pinnable", this.GetHashCode(), count, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer));
}
}
else
{
if (PinnableBufferCacheEventSource.Log.IsEnabled())
{
PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.StartWriting BufferInUse", this.GetHashCode(), count);
}
}
do
{
if (count == 0 && !SslStreamPal.CanEncryptEmptyMessage)
{
// If it's an empty message and the PAL doesn't support that,
// we're done.
break;
}
// Request a write IO slot.
if (_sslState.CheckEnqueueWrite(asyncRequest))
{
// Operation is async and has been queued, return.
return;
}
int chunkBytes = Math.Min(count, _sslState.MaxDataSize);
int encryptedBytes;
SecurityStatusPal status = _sslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes);
if (status.ErrorCode != SecurityStatusPalErrorCode.OK)
{
// Re-handshake status is not supported.
ProtocolToken message = new ProtocolToken(null, status);
throw new IOException(SR.net_io_encrypt, message.GetException());
}
if (PinnableBufferCacheEventSource.Log.IsEnabled())
{
PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Got Encrypted Buffer",
this.GetHashCode(), encryptedBytes, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer));
}
if (asyncRequest != null)
{
// Prepare for the next request.
asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, s_resumeAsyncWriteCallback);
IAsyncResult ar = _sslState.InnerStream.BeginWrite(outBuffer, 0, encryptedBytes, s_writeCallback, asyncRequest);
if (!ar.CompletedSynchronously)
{
return;
}
_sslState.InnerStream.EndWrite(ar);
}
else
{
_sslState.InnerStream.Write(outBuffer, 0, encryptedBytes);
}
offset += chunkBytes;
count -= chunkBytes;
// Release write IO slot.
_sslState.FinishWrite();
} while (count != 0);
}
if (asyncRequest != null)
{
asyncRequest.CompleteUser();
}
if (buffer == _pinnableOutputBufferInUse)
{
_pinnableOutputBufferInUse = null;
if (PinnableBufferCacheEventSource.Log.IsEnabled())
{
PinnableBufferCacheEventSource.Log.DebugMessage1("In System.Net._SslStream.StartWriting Freeing buffer.", this.GetHashCode());
}
}
}