+
+ record_processing.Reset ();
+ byte[] recordTypeBuffer = new byte[1];
+
+ ReceiveRecordAsyncResult internalResult = new ReceiveRecordAsyncResult(callback, state, recordTypeBuffer, record);
+
+ record.BeginRead(internalResult.InitialBuffer, 0, internalResult.InitialBuffer.Length, new AsyncCallback(InternalReceiveRecordCallback), internalResult);
+
+ return internalResult;
+ }
+
+ private void InternalReceiveRecordCallback(IAsyncResult asyncResult)
+ {
+ ReceiveRecordAsyncResult internalResult = asyncResult.AsyncState as ReceiveRecordAsyncResult;
+ Stream record = internalResult.Record;
+
+ try
+ {
+
+ int bytesRead = internalResult.Record.EndRead(asyncResult);
+
+ //We're at the end of the stream. Time to bail.
+ if (bytesRead == 0)
+ {
+ internalResult.SetComplete((byte[])null);
+ return;
+ }
+
+ // Try to read the Record Content Type
+ int type = internalResult.InitialBuffer[0];
+
+ // Set last handshake message received to None
+ this.context.LastHandshakeMsg = HandshakeType.ClientHello;
+
+ ContentType contentType = (ContentType)type;
+ byte[] buffer = this.ReadRecordBuffer(type, record);
+ if (buffer == null)
+ {
+ // record incomplete (at the moment)
+ internalResult.SetComplete((byte[])null);
+ return;
+ }
+
+ // Decrypt message contents if needed
+ if (contentType == ContentType.Alert && buffer.Length == 2)
+ {
+ }
+ else if ((this.Context.Read != null) && (this.Context.Read.Cipher != null))
+ {
+ buffer = this.decryptRecordFragment (contentType, buffer);
+ DebugHelper.WriteLine ("Decrypted record data", buffer);
+ }
+
+ // Process record
+ switch (contentType)
+ {
+ case ContentType.Alert:
+ this.ProcessAlert((AlertLevel)buffer [0], (AlertDescription)buffer [1]);
+ if (record.CanSeek)
+ {
+ // don't reprocess that memory block
+ record.SetLength (0);
+ }
+ buffer = null;
+ break;
+
+ case ContentType.ChangeCipherSpec:
+ this.ProcessChangeCipherSpec();
+ break;
+
+ case ContentType.ApplicationData:
+ break;
+
+ case ContentType.Handshake:
+ TlsStream message = new TlsStream (buffer);
+ while (!message.EOF)
+ {
+ this.ProcessHandshakeMessage(message);
+ }
+ break;
+
+ case (ContentType)0x80:
+ this.context.HandshakeMessages.Write (buffer);
+ break;
+
+ default:
+ throw new TlsException(
+ AlertDescription.UnexpectedMessage,
+ "Unknown record received from server.");
+ }
+
+ internalResult.SetComplete(buffer);
+ }
+ catch (Exception ex)
+ {
+ internalResult.SetComplete(ex);
+ }
+
+ }
+
+ public byte[] EndReceiveRecord(IAsyncResult asyncResult)
+ {
+ ReceiveRecordAsyncResult internalResult = asyncResult as ReceiveRecordAsyncResult;
+
+ if (null == internalResult)
+ throw new ArgumentException("Either the provided async result is null or was not created by this RecordProtocol.");
+
+ if (!internalResult.IsCompleted)
+ internalResult.AsyncWaitHandle.WaitOne();
+
+ if (internalResult.CompletedWithError)
+ throw internalResult.AsyncException;
+
+ byte[] result = internalResult.ResultingBuffer;
+ record_processing.Set ();
+ return result;
+ }
+
+ public byte[] ReceiveRecord(Stream record)
+ {
+ if (this.context.ReceivedConnectionEnd)
+ {
+ throw new TlsException(
+ AlertDescription.InternalError,
+ "The session is finished and it's no longer valid.");
+ }
+
+ record_processing.Reset ();
+ byte[] recordTypeBuffer = new byte[1];
+
+ int bytesRead = record.Read(recordTypeBuffer, 0, recordTypeBuffer.Length);
+
+ //We're at the end of the stream. Time to bail.
+ if (bytesRead == 0)