private RegisterResultEnum Register(SIPTransaction registerTransaction)
{
try
{
SIPRequest sipRequest = registerTransaction.TransactionRequest;
SIPURI registerURI = sipRequest.URI;
SIPToHeader toHeader = sipRequest.Header.To;
string toUser = toHeader.ToURI.User;
string canonicalDomain = (m_strictRealmHandling) ? GetCanonicalDomain_External(toHeader.ToURI.Host, true) : toHeader.ToURI.Host;
int requestedExpiry = GetRequestedExpiry(sipRequest);
if (canonicalDomain == null)
{
FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Warn, "Register request for " + toHeader.ToURI.Host + " rejected as no matching domain found.", null));
SIPResponse noDomainResponse = GetErrorResponse(sipRequest, SIPResponseStatusCodesEnum.Forbidden, "Domain not serviced");
registerTransaction.SendFinalResponse(noDomainResponse);
return RegisterResultEnum.DomainNotServiced;
}
SIPAccount sipAccount = GetSIPAccount_External(s => s.SIPUsername == toUser && s.SIPDomain == canonicalDomain);
SIPRequestAuthenticationResult authenticationResult = SIPRequestAuthenticator_External(registerTransaction.LocalSIPEndPoint, registerTransaction.RemoteEndPoint, sipRequest, sipAccount, FireProxyLogEvent);
if (!authenticationResult.Authenticated)
{
// 401 Response with a fresh nonce needs to be sent.
SIPResponse authReqdResponse = SIPTransport.GetResponse(sipRequest, authenticationResult.ErrorResponse, null);
authReqdResponse.Header.AuthenticationHeader = authenticationResult.AuthenticationRequiredHeader;
registerTransaction.SendFinalResponse(authReqdResponse);
if (authenticationResult.ErrorResponse == SIPResponseStatusCodesEnum.Forbidden)
{
FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Warn, "Forbidden " + toUser + "@" + canonicalDomain + " does not exist, " + sipRequest.Header.ProxyReceivedFrom.ToString() + ", " + sipRequest.Header.UserAgent + ".", null));
return RegisterResultEnum.Forbidden;
}
else
{
FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Registrar, "Authentication required for " + toUser + "@" + canonicalDomain + " from " + sipRequest.Header.ProxyReceivedFrom.ToString() + ".", toUser));
return RegisterResultEnum.AuthenticationRequired;
}
}
else
{
// Authenticated.
if (sipRequest.Header.Contact == null || sipRequest.Header.Contact.Count == 0)
{
// No contacts header to update bindings with, return a list of the current bindings.
List<SIPRegistrarBinding> bindings = m_registrarBindingsManager.GetBindings(sipAccount.Id);
//List<SIPContactHeader> contactsList = m_registrarBindingsManager.GetContactHeader(); // registration.GetContactHeader(true, null);
if (bindings != null)
{
sipRequest.Header.Contact = GetContactHeader(bindings);
}
SIPResponse okResponse = GetOkResponse(sipRequest);
registerTransaction.SendFinalResponse(okResponse);
FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegisterSuccess, "Empty registration request successful for " + toUser + "@" + canonicalDomain + " from " + sipRequest.Header.ProxyReceivedFrom.ToString() + ".", toUser));
}
else
{
SIPEndPoint uacRemoteEndPoint = (!sipRequest.Header.ProxyReceivedFrom.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxyReceivedFrom) : registerTransaction.RemoteEndPoint;
SIPEndPoint proxySIPEndPoint = (!sipRequest.Header.ProxyReceivedOn.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxyReceivedOn) : null;
SIPEndPoint registrarEndPoint = registerTransaction.LocalSIPEndPoint;
SIPResponseStatusCodesEnum updateResult = SIPResponseStatusCodesEnum.Ok;
string updateMessage = null;
DateTime startTime = DateTime.Now;
List<SIPRegistrarBinding> bindingsList = m_registrarBindingsManager.UpdateBindings(
sipAccount,
proxySIPEndPoint,
uacRemoteEndPoint,
registrarEndPoint,
//sipRequest.Header.Contact[0].ContactURI.CopyOf(),
sipRequest.Header.Contact,
sipRequest.Header.CallId,
sipRequest.Header.CSeq,
//sipRequest.Header.Contact[0].Expires,
sipRequest.Header.Expires,
sipRequest.Header.UserAgent,
out updateResult,
out updateMessage);
//int bindingExpiry = GetBindingExpiry(bindingsList, sipRequest.Header.Contact[0].ContactURI.ToString());
TimeSpan duration = DateTime.Now.Subtract(startTime);
FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegistrarTiming, "Binding update time for " + toUser + "@" + canonicalDomain + " took " + duration.TotalMilliseconds + "ms.", null));
if (updateResult == SIPResponseStatusCodesEnum.Ok)
{
string proxySocketStr = (proxySIPEndPoint != null) ? " (proxy=" + proxySIPEndPoint.ToString() + ")" : null;
int bindingCount = 1;
foreach (SIPRegistrarBinding binding in bindingsList)
{
string bindingIndex = (bindingsList.Count == 1) ? String.Empty : " (" + bindingCount + ")";
//FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegisterSuccess, "Registration successful for " + toUser + "@" + canonicalDomain + " from " + uacRemoteEndPoint + proxySocketStr + ", binding " + binding.ContactSIPURI.ToParameterlessString() + ";expiry=" + binding.Expiry + bindingIndex + ".", toUser));
FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegisterSuccess, "Registration successful for " + toUser + "@" + canonicalDomain + " from " + uacRemoteEndPoint + ", binding " + binding.ContactSIPURI.ToParameterlessString() + ";expiry=" + binding.Expiry + bindingIndex + ".", toUser));
//FireProxyLogEvent(new SIPMonitorMachineEvent(SIPMonitorMachineEventTypesEnum.SIPRegistrarBindingUpdate, toUser, uacRemoteEndPoint, sipAccount.Id.ToString()));
bindingCount++;
}
// The standard states that the Ok response should contain the list of current bindings but that breaks some UAs. As a
// compromise the list is returned with the Contact that UAC sent as the first one in the list.
bool contactListSupported = m_userAgentConfigs.GetUserAgentContactListSupport(sipRequest.Header.UserAgent);
if (contactListSupported)
{
sipRequest.Header.Contact = GetContactHeader(bindingsList);
}
else
{
// Some user agents can't match the contact header if the expiry is added to it.
sipRequest.Header.Contact[0].Expires = GetBindingExpiry(bindingsList, sipRequest.Header.Contact[0].ContactURI.ToString()); ;
}
SIPResponse okResponse = GetOkResponse(sipRequest);
// If a request was made for a switchboard token and a certificate is available to sign the tokens then generate it.
if (sipRequest.Header.SwitchboardTokenRequest > 0 && m_switchbboardRSAProvider != null)
{
SwitchboardToken token = new SwitchboardToken(sipRequest.Header.SwitchboardTokenRequest, sipAccount.Owner, uacRemoteEndPoint.Address.ToString());
lock (m_switchbboardRSAProvider)
{
token.SignedHash = Convert.ToBase64String(m_switchbboardRSAProvider.SignHash(Crypto.GetSHAHash(token.GetHashString()), null));
}
string tokenXML = token.ToXML(true);
logger.Debug("Switchboard token set for " + sipAccount.Owner + " with expiry of " + token.Expiry + "s.");
okResponse.Header.SwitchboardToken = Crypto.SymmetricEncrypt(sipAccount.SIPPassword, sipRequest.Header.AuthenticationHeader.SIPDigest.Nonce, tokenXML);
}
registerTransaction.SendFinalResponse(okResponse);
}
else
{
// The binding update failed even though the REGISTER request was authorised. This is probably due to a
// temporary problem connecting to the bindings data store. Send Ok but set the binding expiry to the minimum so
// that the UA will try again as soon as possible.
FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Error, "Registration request successful but binding update failed for " + toUser + "@" + canonicalDomain + " from " + registerTransaction.RemoteEndPoint + ".", toUser));
sipRequest.Header.Contact[0].Expires = m_minimumBindingExpiry;
SIPResponse okResponse = GetOkResponse(sipRequest);
registerTransaction.SendFinalResponse(okResponse);
}
}
return RegisterResultEnum.Authenticated;
}
}
catch (Exception excp)
{
string regErrorMessage = "Exception registrarcore registering. " + excp.Message + "\r\n" + registerTransaction.TransactionRequest.ToString();
logger.Error(regErrorMessage);
FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Error, regErrorMessage, null));
try
{
SIPResponse errorResponse = GetErrorResponse(registerTransaction.TransactionRequest, SIPResponseStatusCodesEnum.InternalServerError, null);
registerTransaction.SendFinalResponse(errorResponse);
}
catch { }
return RegisterResultEnum.Error;
}
}