public CustomerSession Authenticate(string username, string password, string ipAddress) { try { if (username.IsNullOrBlank() || password.IsNullOrBlank()) { logger.Debug("Login failed, either username or password was not specified."); return(null); } else { logger.Debug("CustomerSessionManager authenticate requested for username " + username + " from " + ipAddress + "."); // Don't do the password check via the database as different ones have different string case matching. Customer customer = m_customerPersistor.Get(c => c.CustomerUsername == username); if (customer != null && PasswordHash.Hash(password, customer.Salt) == customer.CustomerPassword) { if (!customer.EmailAddressConfirmed) { throw new ApplicationException("Your email address has not yet been confirmed."); } else if (customer.Suspended) { throw new ApplicationException("Your account is suspended."); } else { logger.Debug("Login successful for " + username + "."); string sessionId = Crypto.GetRandomByteString(SESSION_ID_STRING_LENGTH / 2); CustomerSession customerSession = new CustomerSession(Guid.NewGuid(), sessionId, customer.CustomerUsername, ipAddress); m_customerSessionPersistor.Add(customerSession); return(customerSession); } } else { logger.Debug("Login failed for " + username + "."); return(null); } } } catch (Exception excp) { logger.Error("Exception Authenticate CustomerSessionManager. " + excp.Message); throw; } }
public SIPProvider AddSIPProvider(SIPProvider sipProvider) { Customer customer = AuthoriseRequest(); if (!customer.ServiceLevel.IsNullOrBlank() && customer.ServiceLevel.ToLower() == "free") { // Check the number of SIP Provider is within limits. if (GetSIPProvidersCount(null) >= 1) { throw new ApplicationException("The SIP Provider cannot be added as your existing SIP Provider count has reached the allowed limit for your service level."); } } sipProvider.Owner = customer.CustomerUsername; string validationError = SIPProvider.ValidateAndClean(sipProvider); if (validationError != null) { logger.Warn("Validation error in AddSIPProvider for customer " + customer.CustomerUsername + ". " + validationError); throw new ApplicationException(validationError); } else { return(SIPProviderPersistor.Add(sipProvider)); } }
public void SIPProviderAdded(SIPProvider sipProvider) { try { logger.Debug("SIPProviderBindingSynchroniser SIPProviderAdded for " + sipProvider.Owner + " and " + sipProvider.ProviderName + "."); if (sipProvider.RegisterEnabled) { SIPProviderBinding binding = new SIPProviderBinding(sipProvider); m_bindingPersistor.Add(binding); } } catch (Exception excp) { logger.Error("Exception SIPProviderBindingSynchroniser SIPProviderAdded. " + excp.Message); } }
public SIPProvider AddSIPProvider(SIPProvider sipProvider) { Customer customer = AuthoriseRequest(); sipProvider.Owner = customer.CustomerUsername; string validationError = SIPProvider.ValidateAndClean(sipProvider); if (validationError != null) { logger.Warn("Validation error in AddSIPProvider for customer " + customer.CustomerUsername + ". " + validationError); throw new ApplicationException(validationError); } else { return(SIPProviderPersistor.Add(sipProvider)); } }
/// <summary> /// Establishes a new call with the client end tied to the proxy. Since the proxy will not be sending any audio the idea is that once /// the call is up it should be re-INVITED off somewhere else pronto to avoid the callee sitting their listening to dead air. /// </summary> /// <param name="dest1">The dial string of the first call to place.</param> /// <param name="dest2">The dial string of the second call to place.</param> /// <param name="delaySeconds">Delay in seconds before placing the first call. Gives the user a chance to hangup their phone if they are calling themselves back.</param> /// <param name="ringTimeoutLeg1">The ring timeout for the first call leg, If 0 the max timeout will be used.</param> /// <param name="ringTimeoutLeg1">The ring timeout for the second call leg, If 0 the max timeout will be used.</param> /// <param name="customHeadersCallLeg1">A | delimited string that contains a list of custom SIP headers to add to the INVITE request sent for the first call leg.</param> /// /// <param name="customHeadersCallLeg2">A | delimited string that contains a list of custom SIP headers to add to the INVITE request sent for the second call leg.</param> /// <returns>The result of the call.</returns> public void Callback(string dest1, string dest2, int delaySeconds, int ringTimeoutLeg1, int ringTimeoutLeg2, string customHeadersCallLeg1, string customHeadersCallLeg2) { var ts = new CancellationTokenSource(); CancellationToken ct = ts.Token; try { if (delaySeconds > 0) { delaySeconds = (delaySeconds > MAXCALLBACK_DELAY_SECONDS) ? MAXCALLBACK_DELAY_SECONDS : delaySeconds; Log("Callback app delaying by " + delaySeconds + "s."); Thread.Sleep(delaySeconds * 1000); } Log("Callback app commencing first leg to " + dest1 + "."); SIPEndPoint defaultUDPEP = m_sipTransport.GetDefaultSIPEndPoint(SIPProtocolsEnum.udp); SIPRequest firstLegDummyInviteRequest = GetCallbackInviteRequest(defaultUDPEP.GetIPEndPoint(), null); ForkCall firstLegCall = new ForkCall(m_sipTransport, Log_External, m_callManager.QueueNewCall, null, m_username, m_adminMemberId, m_outboundProxy, m_callManager, null); m_firstLegDialogue = Dial(firstLegCall, dest1, ringTimeoutLeg1, 0, firstLegDummyInviteRequest, SIPCallDescriptor.ParseCustomHeaders(customHeadersCallLeg1)); if (m_firstLegDialogue == null) { Log("The first call leg to " + dest1 + " was unsuccessful."); return; } // Persist the dialogue to the database so any hangup can be detected. m_sipDialoguePersistor.Add(new SIPDialogueAsset(m_firstLegDialogue)); SDP firstLegSDP = SDP.ParseSDPDescription(m_firstLegDialogue.RemoteSDP); string call1SDPIPAddress = firstLegSDP.Connection.ConnectionAddress; int call1SDPPort = firstLegSDP.Media[0].Port; Log("The first call leg to " + dest1 + " was successful, audio socket=" + call1SDPIPAddress + ":" + call1SDPPort + "."); Log("Callback app commencing second leg to " + dest2 + "."); SIPRequest secondLegDummyInviteRequest = GetCallbackInviteRequest(defaultUDPEP.GetIPEndPoint(), m_firstLegDialogue.RemoteSDP); ForkCall secondLegCall = new ForkCall(m_sipTransport, Log_External, m_callManager.QueueNewCall, null, m_username, m_adminMemberId, m_outboundProxy, m_callManager, null); Task.Factory.StartNew(() => { while (true) { Thread.Sleep(CHECK_FIRST_LEG_FOR_HANGUP_PERIOD); Console.WriteLine("Checking if first call leg is still up..."); if (ct.IsCancellationRequested) { Console.WriteLine("Checking first call leg task was cancelled."); break; } else { // Check that the first call leg hasn't been hung up. var dialog = m_sipDialoguePersistor.Get(m_firstLegDialogue.Id); if (dialog == null) { Console.WriteLine("First call leg has been hungup."); // The first call leg has been hungup while waiting for the second call. Log("The first call leg was hungup while the second call leg was waiting for an answer."); secondLegCall.CancelNotRequiredCallLegs(CallCancelCause.ClientCancelled); break; } } } Console.WriteLine("Checking first call leg task finished..."); }, ct); SIPDialogue secondLegDialogue = Dial(secondLegCall, dest2, ringTimeoutLeg2, 0, secondLegDummyInviteRequest, SIPCallDescriptor.ParseCustomHeaders(customHeadersCallLeg2)); ts.Cancel(); if (secondLegDialogue == null) { Log("The second call leg to " + dest2 + " was unsuccessful."); m_firstLegDialogue.Hangup(m_sipTransport, m_outboundProxy); return; } // Check that the first call leg hasn't been hung up. var firstLegDialog = m_sipDialoguePersistor.Get(m_firstLegDialogue.Id); if (firstLegDialog == null) { // The first call leg has been hungup while waiting for the second call. Log("The first call leg was hungup while waiting for the second call leg."); secondLegDialogue.Hangup(m_sipTransport, m_outboundProxy); return; } SDP secondLegSDP = SDP.ParseSDPDescription(secondLegDialogue.RemoteSDP); string call2SDPIPAddress = secondLegSDP.Connection.ConnectionAddress; int call2SDPPort = secondLegSDP.Media[0].Port; Log("The second call leg to " + dest2 + " was successful, audio socket=" + call2SDPIPAddress + ":" + call2SDPPort + "."); // Persist the second leg dialogue and update the bridge ID on the first call leg. Guid bridgeId = Guid.NewGuid(); secondLegDialogue.BridgeId = bridgeId; m_sipDialoguePersistor.Add(new SIPDialogueAsset(secondLegDialogue)); m_sipDialoguePersistor.UpdateProperty(firstLegDialog.Id, "BridgeID", bridgeId.ToString()); //m_callManager.CreateDialogueBridge(m_firstLegDialogue, secondLegDialogue, m_username); Log("Re-inviting Callback dialogues to each other."); m_callManager.ReInvite(m_firstLegDialogue, secondLegDialogue); //m_callManager.ReInvite(secondLegDialogue, m_firstLegDialogue.RemoteSDP); SendRTPPacket(call2SDPIPAddress + ":" + call2SDPPort, call1SDPIPAddress + ":" + call1SDPPort); SendRTPPacket(call1SDPIPAddress + ":" + call1SDPPort, call2SDPIPAddress + ":" + call2SDPPort); } catch (Exception excp) { logger.Error("Exception CallbackApp. " + excp); Log("Exception in Callback. " + excp); } finally { if (!ts.IsCancellationRequested) { ts.Cancel(); } } }
/// <summary> /// Updates the bindings list for a registrar's address-of-records. /// </summary> /// <param name="proxyEndPoint">If the request arrived at this registrar via a proxy then this will contain the end point of the proxy.</param> /// <param name="uacRecvdEndPoint">The public end point the UAC REGISTER request was deemded to have originated from.</param> /// <param name="registrarEndPoint">The registrar end point the registration request was received on.</param> /// <param name="maxAllowedExpiry">The maximum allowed expiry that can be granted to this binding request.</param> /// <returns>If the binding update was successful the expiry time for it is returned otherwise 0.</returns> 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); } }
public void CreateCustomer(Customer customer) { try { if (m_inviteCodeRequired && customer.InviteCode == null) { throw new ApplicationException("Sorry new account creations currently require an invite code, please see http://sipsorcery.wordpress.com/new-accounts/."); } else if (m_newCustomersAllowedLimit != 0 && CRMCustomerPersistor.Count(null) >= m_newCustomersAllowedLimit) { // Check whether the number of customers is within the allowed limit. throw new ApplicationException("Sorry new account creations are currently disabled, please see http://sipsorcery.wordpress.com/new-accounts/."); } else { // Check whether the username is already taken. customer.CustomerUsername = customer.CustomerUsername.ToLower(); Customer existingCustomer = CRMCustomerPersistor.Get(c => c.CustomerUsername == customer.CustomerUsername); if (existingCustomer != null) { throw new ApplicationException("The requested username is already in use please try a different one."); } // Check whether the email address is already taken. customer.EmailAddress = customer.EmailAddress.ToLower(); existingCustomer = CRMCustomerPersistor.Get(c => c.EmailAddress == customer.EmailAddress); if (existingCustomer != null) { throw new ApplicationException("The email address is already associated with an account."); } string validationError = Customer.ValidateAndClean(customer); if (validationError != null) { throw new ApplicationException(validationError); } customer.MaxExecutionCount = Customer.DEFAULT_MAXIMUM_EXECUTION_COUNT; customer.APIKey = Crypto.GetRandomByteString(Customer.API_KEY_LENGTH / 2); CRMCustomerPersistor.Add(customer); logger.Debug("New customer record added for " + customer.CustomerUsername + "."); // Create a default dialplan. SIPDialPlan defaultDialPlan = new SIPDialPlan(customer.CustomerUsername, "default", null, "sys.Log(\"hello world\")\n", SIPDialPlanScriptTypesEnum.Ruby); DialPlanPersistor.Add(defaultDialPlan); logger.Debug("Default dialplan added for " + customer.CustomerUsername + "."); // Get default domain name. string defaultDomain = SIPDomainManager.GetDomain("local", true); // Create SIP account. if (SIPAccountPersistor.Get(s => s.SIPUsername == customer.CustomerUsername && s.SIPDomain == defaultDomain) == null) { SIPAccount sipAccount = new SIPAccount(customer.CustomerUsername, defaultDomain, customer.CustomerUsername, customer.CustomerPassword, "default"); SIPAccountPersistor.Add(sipAccount); logger.Debug("SIP account " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + " added for " + sipAccount.Owner + "."); } else { int attempts = 0; while (attempts < 10) { string testUsername = customer.CustomerUsername + Crypto.GetRandomString(4); if (SIPAccountPersistor.Get(s => s.SIPUsername == testUsername && s.SIPDomain == defaultDomain) == null) { SIPAccount sipAccount = new SIPAccount(customer.CustomerUsername, defaultDomain, testUsername, customer.CustomerPassword, "default"); SIPAccountPersistor.Add(sipAccount); logger.Debug("SIP account " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + " added for " + sipAccount.Owner + "."); break; } else { attempts++; } } } if (!m_customerConfirmLink.IsNullOrBlank()) { logger.Debug("Sending new account confirmation email to " + customer.EmailAddress + "."); SIPSorcerySMTP.SendEmail(customer.EmailAddress, NEW_ACCOUNT_EMAIL_FROM_ADDRESS, NEW_ACCOUNT_EMAIL_SUBJECT, String.Format(NEW_ACCOUNT_EMAIL_BODY, customer.FirstName, m_customerConfirmLink, customer.Id)); } else { logger.Debug("Customer confirmation email was not sent as no confirmation link has been set."); } } } catch (Exception excp) { logger.Error("Exception CreateNewCustomer. " + excp.Message); throw; } }