private void ReceiveHandshakeCallback(IAsyncResult asyncResult)
{
AsyncHandshakeResult asyncHandshakeResult = (AsyncHandshakeResult)asyncResult.AsyncState;
try {
Record[] records = _recordStream.EndReceive(asyncResult);
for (int i=0; i<records.Length; i++) {
Record record = records[i];
if (!_recordHandler.ProcessInputRecord(record)) {
// Ignore records from invalid epoch
continue;
}
lock (_handshakeLock) {
if (!_isAuthenticated && record.Type == RecordType.Data) {
// Refuse data packets before authentication
throw new AlertException(AlertDescription.UnexpectedMessage,
"Data packet received before handshake");
}
if (!_isHandshaking && (record.Type == RecordType.ChangeCipherSpec || record.Type == RecordType.Handshake)) {
// Refuse ChangeCipherSpec and Handshake packets if not handshaking
// TODO: Should handle HelloRequest if renegotiation is supported
throw new AlertException(AlertDescription.UnexpectedMessage,
"Handshake packet received outside handshake");
}
if (_isHandshaking && record.Type == RecordType.Data) {
// Queue data packets during new handshake to avoid sync problems
// TODO: Should handle the data correctly if renegotiation is supported
throw new AlertException(AlertDescription.UnexpectedMessage,
"Received a data packet during handshake");
}
}
switch (record.Type) {
case RecordType.ChangeCipherSpec:
ProcessChangeCipherSpecRecord(record, asyncHandshakeResult);
break;
case RecordType.Alert:
ProcessAlertRecord(record, asyncHandshakeResult);
break;
case RecordType.Handshake:
ProcessHandshakeRecord(record, asyncHandshakeResult);
break;
case RecordType.Data:
// TODO: Implement this properly if renegotiation is supported
break;
default:
ProcessUnknownRecord(record, asyncHandshakeResult);
break;
}
}
} catch (AlertException ae) {
ProcessSendFatalAlert(new Alert(ae.AlertDescription, _handshakeSession.NegotiatedVersion));
asyncHandshakeResult.SetComplete(new Exception("Connection closed because of local alert", ae));
} catch (IOException) {
asyncHandshakeResult.SetComplete(new EndOfStreamException("Connection closed unexpectedly"));
} catch (Exception e) {
ProcessSendFatalAlert(new Alert(AlertDescription.InternalError, _handshakeSession.NegotiatedVersion));
asyncHandshakeResult.SetComplete(new Exception("Connection closed because of local error", e));
}
}