public List<SIPRegistrarBinding> UpdateBindings(
SIPAccount sipAccount,
SIPEndPoint proxySIPEndPoint,
SIPEndPoint remoteSIPEndPoint,
SIPEndPoint registrarSIPEndPoint,
List<SIPContactHeader> contactHeaders,
string callId,
int cseq,
//int contactHeaderExpiresValue,
int expiresHeaderValue,
string userAgent,
out SIPResponseStatusCodesEnum responseStatus,
out string responseMessage)
{
//logger.Debug("UpdateBinding " + bindingURI.ToString() + ".");
int maxAllowedExpiry = (m_userAgentConfigs != null) ? m_userAgentConfigs.GetMaxAllowedExpiry(userAgent) : SIPUserAgentConfiguration.DEFAULT_MAX_EXPIRY_SECONDS;
responseMessage = null;
string sipAccountAOR = sipAccount.SIPUsername + "@" + sipAccount.SIPDomain;
responseStatus = SIPResponseStatusCodesEnum.Ok;
try
{
userAgent = (userAgent != null && userAgent.Length > MAX_USERAGENT_LENGTH) ? userAgent.Substring(0, MAX_USERAGENT_LENGTH) : userAgent;
List<SIPRegistrarBinding> bindings = m_bindingsPersistor.Get(b => b.SIPAccountId == sipAccount.Id, null, 0, Int32.MaxValue);
foreach (SIPContactHeader contactHeader in contactHeaders)
{
SIPURI bindingURI = contactHeader.ContactURI.CopyOf();
int contactHeaderExpiresValue = contactHeader.Expires;
int bindingExpiry = 0;
if (bindingURI.Host == m_sipRegisterRemoveAll)
{
if (contactHeaders.Count > 1)
{
// If a register request specifies remove all it cannot contain any other binding requests.
FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.BindingRemoval, "Remove all bindings requested for " + sipAccountAOR + " but mutliple bindings specified, rejecting as a bad request.", sipAccount.SIPUsername));
responseStatus = SIPResponseStatusCodesEnum.BadRequest;
break;
}
#region Process remove all bindings.
if (expiresHeaderValue == 0)
{
// Removing all bindings for user.
FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.BindingRemoval, "Remove all bindings requested for " + sipAccountAOR + ".", sipAccount.SIPUsername));
// Mark all the current bindings as expired.
if (bindings != null && bindings.Count > 0)
{
for (int index = 0; index < bindings.Count; index++)
{
bindings[index].RemovalReason = SIPBindingRemovalReason.ClientExpiredAll;
bindings[index].Expiry = 0;
m_bindingsPersistor.Update(bindings[index]);
// Remove the NAT keep-alive job if present.
if (m_natKeepAliveJobs.ContainsKey(bindings[index].RemoteSIPSocket))
{
m_natKeepAliveJobs[bindings[index].RemoteSIPSocket].CancelJob();
}
}
}
FireSIPMonitorLogEvent(new SIPMonitorMachineEvent(SIPMonitorMachineEventTypesEnum.SIPRegistrarBindingRemoval, sipAccount.Owner, sipAccount.Id.ToString(), SIPURI.ParseSIPURIRelaxed(sipAccountAOR)));
responseStatus = SIPResponseStatusCodesEnum.Ok;
}
else
{
// Remove all header cannot be present with other headers and must have an Expiry equal to 0.
responseStatus = SIPResponseStatusCodesEnum.BadRequest;
}
#endregion
}
else
{
int requestedExpiry = (contactHeaderExpiresValue != -1) ? contactHeaderExpiresValue : expiresHeaderValue;
requestedExpiry = (requestedExpiry == -1) ? maxAllowedExpiry : requestedExpiry; // This will happen if the Expires header and the Expiry on the Contact are both missing.
bindingExpiry = (requestedExpiry > maxAllowedExpiry) ? maxAllowedExpiry : requestedExpiry;
bindingExpiry = (bindingExpiry < MINIMUM_EXPIRY_SECONDS) ? MINIMUM_EXPIRY_SECONDS : bindingExpiry;
bindingURI.Parameters.Remove(m_sipExpiresParameterKey);
SIPRegistrarBinding binding = GetBindingForContactURI(bindings, bindingURI.ToString());
if (binding != null)
{
if (requestedExpiry <= 0)
{
FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.BindingExpired, "Binding expired by client for " + sipAccountAOR + " from " + remoteSIPEndPoint.ToString() + ".", sipAccount.SIPUsername));
bindings.Remove(binding);
m_bindingsPersistor.Delete(binding);
bindingExpiry = 0;
FireSIPMonitorLogEvent(new SIPMonitorMachineEvent(SIPMonitorMachineEventTypesEnum.SIPRegistrarBindingRemoval, sipAccount.Owner, sipAccount.Id.ToString(), SIPURI.ParseSIPURIRelaxed(sipAccountAOR)));
// Remove the NAT keep-alive job if present.
if (m_natKeepAliveJobs.ContainsKey(binding.RemoteSIPSocket))
{
m_natKeepAliveJobs[binding.RemoteSIPSocket].CancelJob();
}
}
else
{
FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Registrar, "Binding update request for " + sipAccountAOR + " from " + remoteSIPEndPoint.ToString() + ", expiry requested " + requestedExpiry + "s granted " + bindingExpiry + "s.", sipAccount.Owner));
binding.RefreshBinding(bindingExpiry, remoteSIPEndPoint, proxySIPEndPoint, registrarSIPEndPoint, sipAccount.DontMangleEnabled);
DateTime startTime = DateTime.Now;
m_bindingsPersistor.Update(binding);
TimeSpan duration = DateTime.Now.Subtract(startTime);
//FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegistrarTiming, "Binding database update time for " + sipAccountAOR + " took " + duration.TotalMilliseconds + "ms.", null));
FireSIPMonitorLogEvent(new SIPMonitorMachineEvent(SIPMonitorMachineEventTypesEnum.SIPRegistrarBindingUpdate, sipAccount.Owner, sipAccount.Id.ToString(), SIPURI.ParseSIPURIRelaxed(sipAccountAOR)));
// Add a NAT keep-alive job if required.
if (sipAccount.SendNATKeepAlives && proxySIPEndPoint != null)
{
AddNATKeepAliveJob(sipAccount, remoteSIPEndPoint, proxySIPEndPoint, binding, bindingExpiry);
}
}
}
else
{
if (requestedExpiry > 0)
{
FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.BindingInProgress, "New binding request for " + sipAccountAOR + " from " + remoteSIPEndPoint.ToString() + ", expiry requested " + requestedExpiry + "s granted " + bindingExpiry + "s.", sipAccount.Owner));
if (bindings.Count >= m_maxBindingsPerAccount)
{
// Need to remove the oldest binding to stay within limit.
//SIPRegistrarBinding oldestBinding = m_bindingsPersistor.Get(b => b.SIPAccountId == sipAccount.Id, null, 0, Int32.MaxValue).OrderBy(x => x.LastUpdateUTC).Last();
SIPRegistrarBinding oldestBinding = bindings.OrderBy(x => x.LastUpdate).Last();
FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.BindingInProgress, "Binding limit exceeded for " + sipAccountAOR + " from " + remoteSIPEndPoint.ToString() + " removing oldest binding to stay within limit of " + m_maxBindingsPerAccount + ".", sipAccount.Owner));
m_bindingsPersistor.Delete(oldestBinding);
if (m_natKeepAliveJobs.ContainsKey(binding.RemoteSIPSocket))
{
m_natKeepAliveJobs[binding.RemoteSIPSocket].CancelJob();
}
}
SIPRegistrarBinding newBinding = new SIPRegistrarBinding(sipAccount, bindingURI, callId, cseq, userAgent, remoteSIPEndPoint, proxySIPEndPoint, registrarSIPEndPoint, bindingExpiry);
DateTime startTime = DateTime.Now;
bindings.Add(newBinding);
m_bindingsPersistor.Add(newBinding);
TimeSpan duration = DateTime.Now.Subtract(startTime);
//FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegistrarTiming, "Binding database add time for " + sipAccountAOR + " took " + duration.TotalMilliseconds + "ms.", null));
// Add a NAT keep-alive job if required.
if (sipAccount.SendNATKeepAlives && proxySIPEndPoint != null)
{
AddNATKeepAliveJob(sipAccount, remoteSIPEndPoint, proxySIPEndPoint, newBinding, bindingExpiry);
}
FireSIPMonitorLogEvent(new SIPMonitorMachineEvent(SIPMonitorMachineEventTypesEnum.SIPRegistrarBindingUpdate, sipAccount.Owner, sipAccount.Id.ToString(), SIPURI.ParseSIPURIRelaxed(sipAccountAOR)));
}
else
{
FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.BindingFailed, "New binding received for " + sipAccountAOR + " with expired contact," + bindingURI.ToString() + " no update.", sipAccount.Owner));
bindingExpiry = 0;
}
}
responseStatus = SIPResponseStatusCodesEnum.Ok;
}
}
return bindings;
}
catch (Exception excp)
{
logger.Error("Exception UpdateBinding. " + excp.Message);
FireSIPMonitorLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Error, "Registrar error updating binding: " + excp.Message + " Binding not updated.", sipAccount.SIPUsername));
responseStatus = SIPResponseStatusCodesEnum.InternalServerError;
return null;
}
}