protected void HandleControl(MemBlock b, ISender return_path) {
ISender low_level_sender = return_path;
if(low_level_sender is ReqrepManager.ReplyState) {
low_level_sender = ((ReqrepManager.ReplyState) low_level_sender).ReturnPath;
}
SecurityControlMessage scm = new SecurityControlMessage(b);
MemBlock calc_cookie = CalculateCookie(low_level_sender);
if(scm.Version != Version) {
ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
"Invalid version expected {0}, found {1}, from {2}, message: {3}",
Version, scm.Version, low_level_sender, scm));
return;
} else if(!SecurityPolicy.Supports(scm.SPI)) {
ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
"Unsupported SPI, from {0}, message: {1}", low_level_sender, scm));
return;
} else if((scm.Type != SecurityControlMessage.MessageType.Cookie &&
scm.Type != SecurityControlMessage.MessageType.NoSuchSA) &&
!scm.RemoteCookie.Equals(calc_cookie))
{
ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
"Invalid cookie, Expected {0}, Found {1}, From {2}, Message {3}",
calc_cookie, scm.RemoteCookie, low_level_sender, scm));
return;
}
SecurityControlMessage scm_reply = new SecurityControlMessage();
scm_reply.Version = Version;
scm_reply.SPI = scm.SPI;
PeerSecAssociation sa = null;
// This can be in a try statement since this is best effort anyway
try {
Dictionary<ISender, PeerSecAssociation> sender_to_sa = _spi[scm.SPI];
sa = sender_to_sa[low_level_sender];
} catch { }
if(sa != null) {
// Reset cases where no state has been set yet or state is attempting
// to be re-established, if other message types arrive, they will
// expect pre-set state and will fail. The mechanisms instilled thus
// far should prevent this, but this makes it explicit. Now only
// wayward messages will arrive to other states.
if(scm.Type == SecurityControlMessage.MessageType.NoSuchSA ||
scm.Type == SecurityControlMessage.MessageType.Cookie ||
scm.Type == SecurityControlMessage.MessageType.CookieResponse ||
scm.Type == SecurityControlMessage.MessageType.DHEWithCertificateAndCAs)
{
sa.TryReset();
}
if(sa.Closed) {
ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, GetHashCode() + " SA closed, clearing SA state! " + sa);
sa = null;
} else if(sa.State == SecurityAssociation.States.Active &&
// Two nodes can demand a confirm at the same time, if this
// message doesn't pass, then one side will close due to timeout
scm.Type != SecurityControlMessage.MessageType.Confirm)
{
ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
"{0}, {1}: {2}", GetHashCode(), "SA Active, received message",
scm.Type));
return;
}
}
try {
switch(scm.Type) {
case SecurityControlMessage.MessageType.NoSuchSA:
HandleControlNoSuchSA(sa);
break;
case SecurityControlMessage.MessageType.Cookie:
HandleControlCookie(sa, calc_cookie, scm, scm_reply, return_path, low_level_sender);
break;
case SecurityControlMessage.MessageType.CookieResponse:
HandleControlCookieResponse(sa, scm, scm_reply, return_path, low_level_sender);
break;
case SecurityControlMessage.MessageType.DHEWithCertificateAndCAs:
HandleControlDHEWithCertificateAndCAs(sa, scm, scm_reply, return_path, low_level_sender);
break;
case SecurityControlMessage.MessageType.DHEWithCertificate:
HandleControlDHEWithCertificate(sa, scm, scm_reply, return_path, low_level_sender);
break;
case SecurityControlMessage.MessageType.Confirm:
HandleControlConfirm(sa, scm, scm_reply, return_path, low_level_sender);
break;
default:
throw new Exception("Invalid message!");
}
} catch(Exception e) {
if(scm.Type == SecurityControlMessage.MessageType.DHEWithCertificateAndCAs ||
scm.Type == SecurityControlMessage.MessageType.DHEWithCertificate ||
scm.Type == SecurityControlMessage.MessageType.Confirm)
{
NoSuchSA(scm.SPI, return_path);
}
if(sa != null && sa.Closed) {
ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, GetHashCode() + " SA closed! " + sa);
return;
}
ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
"Error in {0}, unhandled exception from {1}, message: {2}, exception: {3}",
GetHashCode(), low_level_sender, scm, e));
}
}