PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/sipsorcery-core/SIPSorcery.Servers.Cores/SIPApplicationServer/SIPCallManager.cs

https://github.com/thecc4re/sipsorcery-mono
C# | 1043 lines | 768 code | 87 blank | 188 comment | 134 complexity | 0c13b757866027ebc9eb31dd4415f466 MD5 | raw file
Possible License(s): CC-BY-SA-3.0

Large files files are truncated, but you can click here to view the full file

  1. // ============================================================================
  2. // FileName: SIPCallManager.cs
  3. //
  4. // Description:
  5. // Processes new SIP calls.
  6. //
  7. // Author(s):
  8. // Aaron Clauson
  9. //
  10. // History:
  11. // 10 Feb 2008 Aaron Clauson Created.
  12. //
  13. // License:
  14. // This software is licensed under the BSD License http://www.opensource.org/licenses/bsd-license.php
  15. //
  16. // Copyright (c) 2008 Aaron Clauson (aaronc@blueface.ie), Blue Face Ltd, Dublin, Ireland (www.blueface.ie)
  17. // All rights reserved.
  18. //
  19. // Redistribution and use in source and binary forms, with or without modification, are permitted provided that
  20. // the following conditions are met:
  21. //
  22. // Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  23. // Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
  24. // disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Blue Face Ltd.
  25. // nor the names of its contributors may be used to endorse or promote products derived from this software without specific
  26. // prior written permission.
  27. //
  28. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
  29. // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  30. // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  31. // OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  32. // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  33. // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  34. // POSSIBILITY OF SUCH DAMAGE.
  35. // ============================================================================
  36. using System;
  37. using System.Collections.Generic;
  38. using System.Configuration;
  39. using System.Data;
  40. using System.Data.SqlClient;
  41. using System.Diagnostics;
  42. using System.Linq;
  43. using System.Net;
  44. using System.ServiceModel;
  45. using System.ServiceModel.Configuration;
  46. using System.Text;
  47. using System.Threading;
  48. using System.Transactions;
  49. using SIPSorcery.AppServer.DialPlan;
  50. using SIPSorcery.CRM;
  51. using SIPSorcery.Persistence;
  52. using SIPSorcery.SIP;
  53. using SIPSorcery.SIP.App;
  54. using SIPSorcery.Sys;
  55. using SIPSorcery.Web.Services;
  56. using log4net;
  57. namespace SIPSorcery.Servers
  58. {
  59. public class SIPCallManager : ISIPCallManager
  60. {
  61. private const int MAX_FORWARD_BINDINGS = 5;
  62. private const string MONITOR_CALLLIMITS_THREAD_NAME = "sipcallmanager-monitorcalls";
  63. private const string PROCESS_CALLS_THREAD_NAME_PREFIX = "sipcallmanager-processcalls";
  64. private const int MAX_QUEUEWAIT_PERIOD = 4000; // Maximum time to wait to check the new calls queue if no events are received.
  65. private const int MAX_NEWCALL_QUEUE = 10; // Maximum number of new calls that will be queued for processing.
  66. public const string DISPATCHER_SIPACCOUNT_NAME = "dispatcher";
  67. private const int MAX_CALLBACK_WAIT_SECONDS = 30;
  68. private const int EXPIRECALL_HANGUP_FAILURE_RETRY = 60; // When a call is hungup due to time limit being reached a new hangup time will be set in case this server agent crashes.
  69. private const string DISPATCHER_CONTRACT_NAME = "SIPSorcery.Web.Services.ICallDispatcherService";
  70. private const int RETRY_FAILED_PROXY = 20000;
  71. private static ILog logger = AppState.logger;
  72. private static ILog execCountlogger = AppState.GetLogger("executioncount");
  73. //private static readonly string m_sipDialPlanExecutionCountPropertyName = SIPDialPlan.PROPERTY_EXECUTIONCOUNT_NAME;
  74. private SIPTransport m_sipTransport;
  75. private SIPEndPoint m_outboundProxy;
  76. private SIPDialogueManager m_sipDialogueManager;
  77. private string m_traceDirectory;
  78. private bool m_monitorCalls; // If true this call manager instance will monitor the sip dialogues table and hangup any expired calls.
  79. private int m_dailyCallLimit; // If not -1 indicates a limit on the number of calls for each owner account is being enforced.
  80. private bool m_stop;
  81. private SIPAssetPersistor<SIPDialogueAsset> m_sipDialoguePersistor;
  82. private SIPAssetPersistor<SIPCDRAsset> m_sipCDRPersistor;
  83. private SIPAssetPersistor<Customer> m_customerPersistor;
  84. private SIPAssetPersistor<SIPDialPlan> m_dialPlanPersistor;
  85. private SIPMonitorLogDelegate Log_External;
  86. private SIPAssetGetListDelegate<SIPProvider> GetSIPProviders_External;
  87. private SIPAssetGetDelegate<SIPDialPlan> GetDialPlan_External; // Function to load user dial plans.
  88. private SIPAssetGetDelegate<SIPAccount> GetSIPAccount_External; // Function in authenticate user outgoing calls.
  89. private SIPAssetGetListDelegate<SIPRegistrarBinding> GetSIPAccountBindings_External; // Function to lookup bindings that have been registered for a SIP account.
  90. private GetCanonicalDomainDelegate GetCanonicalDomain_External;
  91. private Dictionary<string, string> m_inDialogueTransactions = new Dictionary<string, string>(); // <Forwarded transaction id, Origin transaction id>.
  92. private Queue<ISIPServerUserAgent> m_newCalls = new Queue<ISIPServerUserAgent>();
  93. private AutoResetEvent m_newCallReady = new AutoResetEvent(false);
  94. private DialPlanEngine m_dialPlanEngine;
  95. private int m_pid;
  96. private Dictionary<string, CallDispatcherProxy> m_dispatcherProxy = new Dictionary<string, CallDispatcherProxy>(); // [config name, proxy].
  97. private Dictionary<string, CallbackWaiter> m_waitingForCallbacks = new Dictionary<string, CallbackWaiter>();
  98. public SIPCallManager(
  99. SIPTransport sipTransport,
  100. SIPEndPoint outboundProxy,
  101. SIPMonitorLogDelegate logDelegate,
  102. SIPDialogueManager sipDialogueManager,
  103. SIPAssetPersistor<SIPDialogueAsset> sipDialoguePersistor,
  104. SIPAssetPersistor<SIPCDRAsset> sipCDRPersistor,
  105. DialPlanEngine dialPlanEngine,
  106. SIPAssetGetDelegate<SIPDialPlan> getDialPlan,
  107. SIPAssetGetDelegate<SIPAccount> getSIPAccount,
  108. SIPAssetGetListDelegate<SIPRegistrarBinding> getSIPAccountBindings,
  109. SIPAssetGetListDelegate<SIPProvider> getSIPProviders,
  110. GetCanonicalDomainDelegate getCanonicalDomain,
  111. SIPAssetPersistor<Customer> customerPersistor,
  112. SIPAssetPersistor<SIPDialPlan> dialPlanPersistor,
  113. string traceDirectory,
  114. bool monitorCalls,
  115. int dailyCallLimit)
  116. {
  117. m_sipTransport = sipTransport;
  118. m_outboundProxy = outboundProxy;
  119. Log_External = logDelegate;
  120. m_sipDialogueManager = sipDialogueManager;
  121. m_sipDialoguePersistor = sipDialoguePersistor;
  122. m_sipCDRPersistor = sipCDRPersistor;
  123. m_dialPlanEngine = dialPlanEngine;
  124. GetDialPlan_External = getDialPlan;
  125. GetSIPAccount_External = getSIPAccount;
  126. GetSIPAccountBindings_External = getSIPAccountBindings;
  127. GetSIPProviders_External = getSIPProviders;
  128. GetCanonicalDomain_External = getCanonicalDomain;
  129. m_customerPersistor = customerPersistor;
  130. m_dialPlanPersistor = dialPlanPersistor;
  131. m_traceDirectory = traceDirectory;
  132. m_monitorCalls = monitorCalls;
  133. m_pid = Process.GetCurrentProcess().Id;
  134. m_dailyCallLimit = dailyCallLimit;
  135. }
  136. public void Start()
  137. {
  138. InitialiseDispatcherProxies();
  139. if (m_monitorCalls)
  140. {
  141. ThreadPool.QueueUserWorkItem(delegate { MonitorCalls(); });
  142. }
  143. ThreadPool.QueueUserWorkItem(delegate { ProcessNewCalls(PROCESS_CALLS_THREAD_NAME_PREFIX + "-1"); });
  144. ThreadPool.QueueUserWorkItem(delegate { ProcessNewCalls(PROCESS_CALLS_THREAD_NAME_PREFIX + "-2"); });
  145. ThreadPool.QueueUserWorkItem(delegate { ProcessNewCalls(PROCESS_CALLS_THREAD_NAME_PREFIX + "-3"); });
  146. }
  147. public void Stop()
  148. {
  149. logger.Debug("SIPCallManager stopping.");
  150. m_stop = true;
  151. m_newCallReady.Set();
  152. }
  153. private void MonitorCalls()
  154. {
  155. try
  156. {
  157. Thread.CurrentThread.Name = MONITOR_CALLLIMITS_THREAD_NAME;
  158. while (!m_stop)
  159. {
  160. try
  161. {
  162. SIPDialogueAsset expiredCall = GetNextExpiredCall();
  163. if (expiredCall != null)
  164. {
  165. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Hanging up expired call to " + expiredCall.RemoteTarget + " after " + expiredCall.CallDurationLimit + "s.", expiredCall.Owner));
  166. //expiredCall.SIPDialogue.Hangup(m_sipTransport, m_outboundProxy);
  167. m_sipDialogueManager.CallHungup(expiredCall.SIPDialogue, "Call duration limit reached", true);
  168. }
  169. }
  170. catch (Exception monitorExcp)
  171. {
  172. logger.Error("Exception MonitorCalls Monitoring. " + monitorExcp.Message);
  173. }
  174. Thread.Sleep(1000);
  175. }
  176. logger.Warn("SIPCallManger MonitorCalls thread stopping.");
  177. }
  178. catch (Exception excp)
  179. {
  180. logger.Error("Exception MonitorCalls. " + excp.Message);
  181. }
  182. }
  183. private SIPDialogueAsset GetNextExpiredCall()
  184. {
  185. //logger.Debug("GetNextExpiredCall");
  186. using (var trans = new TransactionScope())
  187. {
  188. SIPDialogueAsset expiredCall = m_sipDialoguePersistor.Get(d => d.HangupAt <= DateTimeOffset.UtcNow);
  189. if (expiredCall != null)
  190. {
  191. //logger.Debug("GetNextExpiredCall, expired call found " + expiredCall.RemoteTarget + ".");
  192. m_sipDialoguePersistor.UpdateProperty(expiredCall.Id, "HangupAt", DateTimeOffset.UtcNow.AddSeconds(EXPIRECALL_HANGUP_FAILURE_RETRY));
  193. }
  194. trans.Complete();
  195. return expiredCall;
  196. }
  197. }
  198. public void QueueNewCall(ISIPServerUserAgent serverUA)
  199. {
  200. try
  201. {
  202. // Attempt to queue the call.
  203. if (m_newCalls.Count < MAX_NEWCALL_QUEUE)
  204. {
  205. lock (m_newCalls)
  206. {
  207. m_newCalls.Enqueue(serverUA);
  208. m_newCallReady.Set();
  209. }
  210. }
  211. else
  212. {
  213. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call Manager rejected call as new calls queue full.", null));
  214. serverUA.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "Call Manager overloaded", null);
  215. }
  216. }
  217. catch (Exception excp)
  218. {
  219. logger.Error("Exception SIPCallManager QueueNewCall. " + excp.Message);
  220. }
  221. }
  222. private void ProcessNewCalls(string threadName)
  223. {
  224. try
  225. {
  226. Thread.CurrentThread.Name = threadName;
  227. while (!m_stop)
  228. {
  229. while (m_newCalls.Count > 0)
  230. {
  231. ISIPServerUserAgent newCall = null;
  232. lock (m_newCalls)
  233. {
  234. newCall = m_newCalls.Dequeue();
  235. }
  236. if (newCall != null)
  237. {
  238. if (newCall.CallDirection == SIPCallDirection.In)
  239. {
  240. if (newCall.CallRequest.URI.User == DISPATCHER_SIPACCOUNT_NAME)
  241. {
  242. // This is a special system account used by monitoring or dispatcher agents that want to check
  243. // the state of the application server.
  244. newCall.NoCDR();
  245. ProcessNewCall(newCall);
  246. }
  247. else
  248. {
  249. bool loadInAccountResult = newCall.LoadSIPAccountForIncomingCall();
  250. if (loadInAccountResult && newCall.SIPAccount != null)
  251. {
  252. #region Check if this call is being waited for by a dialplan application.
  253. CallbackWaiter matchingApp = null;
  254. try
  255. {
  256. if (m_waitingForCallbacks.Count > 0)
  257. {
  258. List<CallbackWaiter> expiredWaiters = new List<CallbackWaiter>();
  259. lock (m_waitingForCallbacks)
  260. {
  261. foreach (CallbackWaiter waitingApp in m_waitingForCallbacks.Values)
  262. {
  263. if (DateTime.Now.Subtract(waitingApp.Added).TotalSeconds > MAX_CALLBACK_WAIT_SECONDS)
  264. {
  265. expiredWaiters.Add(waitingApp);
  266. }
  267. else
  268. {
  269. bool match = waitingApp.IsMyCall(newCall);
  270. if (match)
  271. {
  272. matchingApp = waitingApp;
  273. break;
  274. }
  275. }
  276. }
  277. if (expiredWaiters.Count > 0)
  278. {
  279. foreach (CallbackWaiter expiredApp in expiredWaiters)
  280. {
  281. m_waitingForCallbacks.Remove(expiredApp.UniqueId);
  282. }
  283. }
  284. }
  285. }
  286. }
  287. catch (Exception callbackExcp)
  288. {
  289. logger.Error("Exception ProcessNewCalls Checking Callbacks. " + callbackExcp.Message);
  290. }
  291. #endregion
  292. if (matchingApp != null)
  293. {
  294. lock (m_waitingForCallbacks)
  295. {
  296. m_waitingForCallbacks.Remove(matchingApp.UniqueId);
  297. }
  298. }
  299. else
  300. {
  301. ProcessNewCall(newCall);
  302. }
  303. }
  304. else
  305. {
  306. logger.Debug("ProcessNewCalls could not load incoming SIP Account for " + newCall.CallRequest.URI.ToString() + ".");
  307. newCall.Reject(SIPResponseStatusCodesEnum.NotFound, null, null);
  308. }
  309. }
  310. }
  311. else if (newCall.AuthenticateCall())
  312. {
  313. ProcessNewCall(newCall);
  314. }
  315. }
  316. }
  317. m_newCallReady.Reset();
  318. m_newCallReady.WaitOne(MAX_QUEUEWAIT_PERIOD);
  319. }
  320. logger.Warn("SIPCallManager ProcessNewCalls thread stopping.");
  321. }
  322. catch (Exception excp)
  323. {
  324. logger.Error("Exception SIPCallManager ProcessNewCalls. " + excp.Message);
  325. }
  326. }
  327. private void ProcessNewCall(ISIPServerUserAgent uas)
  328. {
  329. //bool wasExecutionCountIncremented = false;
  330. Customer customer = null;
  331. SIPDialPlan dialPlan = null;
  332. try
  333. {
  334. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call Manager processing new call on thread " + Thread.CurrentThread.Name + " for " + uas.CallRequest.Method + " to " + uas.CallRequest.URI.ToString() + ".", null));
  335. #region Do some pre-flight checks on the SIP account to determine if the call should be processed.
  336. if (uas.SIPAccount == null)
  337. {
  338. if (uas.CallRequest.URI.User == DISPATCHER_SIPACCOUNT_NAME)
  339. {
  340. // This is a call from the monitoring system allow to proceed.
  341. }
  342. else if (uas.CallDirection == SIPCallDirection.Out)
  343. {
  344. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SIP account " + uas.CallRequest.Header.From.FromURI.ToParameterlessString() + " not found for outgoing call to " + uas.CallRequest.URI.ToString() + ".", null));
  345. uas.Reject(SIPResponseStatusCodesEnum.Forbidden, null, null);
  346. return;
  347. }
  348. else if (uas.CallDirection == SIPCallDirection.In)
  349. {
  350. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SIP account " + uas.CallRequest.URI.ToParameterlessString() + " not found for incoming call.", null));
  351. uas.Reject(SIPResponseStatusCodesEnum.NotFound, null, null);
  352. return;
  353. }
  354. }
  355. else
  356. {
  357. if (uas.SIPAccount.IsDisabled)
  358. {
  359. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SIP account " + uas.SIPAccount.SIPUsername + "@" + uas.SIPAccount.SIPDomain + " is disabled for " + uas.CallDirection + " call.", uas.SIPAccount.Owner));
  360. uas.Reject(SIPResponseStatusCodesEnum.Forbidden, "SIP account disabled", null);
  361. return;
  362. }
  363. else if (uas.SIPAccount.IsIncomingOnly && uas.CallDirection == SIPCallDirection.Out)
  364. {
  365. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SIP account " + uas.SIPAccount.SIPUsername + "@" + uas.SIPAccount.SIPDomain + " is not permitted to make outgoing calls", uas.SIPAccount.Owner));
  366. uas.Reject(SIPResponseStatusCodesEnum.Forbidden, "SIP account not permitted to make outgoing calls", null);
  367. return;
  368. }
  369. }
  370. #endregion
  371. SIPURI callURI = (uas.CallRequest != null) ? uas.CallRequest.URI : null;
  372. SIPAccount sipAccount = uas.SIPAccount;
  373. if (uas.CallDirection == SIPCallDirection.In && callURI.User == DISPATCHER_SIPACCOUNT_NAME)
  374. {
  375. uas.NoCDR();
  376. #region Create a pseudo-dialplan to process the monitoring process call.
  377. string pseudoScript =
  378. //"sys.Log(\"Dispatcher Call.\")\n" +
  379. "result = sys.DoesSIPAccountExist(\"" + DISPATCHER_SIPACCOUNT_NAME + "\")\n" + // Allows the test call to check the database connectivity.
  380. //"sys.Log(\"DoesSIPAccountExist result=#{result}.\")\n" +
  381. "sys.Respond(420, nil, \"DialPlanEngine-ExecutionCount: " + m_dialPlanEngine.ScriptCount + "\")\n";
  382. SIPDialPlan dispatcherDialPlan = new SIPDialPlan(null, null, null, pseudoScript, SIPDialPlanScriptTypesEnum.Ruby);
  383. dispatcherDialPlan.Id = Guid.Empty; // Prevents the increment and decrement on the execution counts.
  384. DialPlanScriptContext scriptContext = new DialPlanScriptContext(
  385. null,
  386. m_sipTransport,
  387. CreateDialogueBridge,
  388. m_outboundProxy,
  389. uas,
  390. dispatcherDialPlan,
  391. null,
  392. null,
  393. null,
  394. Guid.Empty);
  395. m_dialPlanEngine.Execute(scriptContext, uas, uas.CallDirection, null, this);
  396. #endregion
  397. }
  398. else
  399. {
  400. string dialPlanName = dialPlanName = (uas.CallDirection == SIPCallDirection.Out) ? sipAccount.OutDialPlanName : sipAccount.InDialPlanName;
  401. string owner = (uas.IsB2B) ? uas.SIPAccount.Owner : uas.Owner;
  402. if (GetDialPlanAndCustomer(owner, dialPlanName, uas, out customer, out dialPlan))
  403. {
  404. //IncrementDialPlanExecutionCount(dialPlan, customer, originalExecutionCount + 1);
  405. //IncrementCustomerExecutionCount(customer);
  406. //wasExecutionCountIncremented = true;
  407. if (dialPlan != null)
  408. {
  409. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Using dialplan " + dialPlanName + " for " + uas.CallDirection + " call to " + callURI.ToString() + ".", owner));
  410. if (dialPlan.ScriptType == SIPDialPlanScriptTypesEnum.Asterisk)
  411. {
  412. DialPlanLineContext lineContext = new DialPlanLineContext(
  413. Log_External,
  414. m_sipTransport,
  415. CreateDialogueBridge,
  416. m_outboundProxy,
  417. uas,
  418. dialPlan,
  419. GetSIPProviders_External(p => p.Owner == owner, null, 0, Int32.MaxValue),
  420. m_traceDirectory,
  421. (uas.CallDirection == SIPCallDirection.Out) ? sipAccount.NetworkId : null,
  422. customer.Id);
  423. //lineContext.DialPlanComplete += () => { DecrementCustomerExecutionCount(customer);} ;
  424. m_dialPlanEngine.Execute(lineContext, uas, uas.CallDirection, CreateDialogueBridge, this);
  425. }
  426. else
  427. {
  428. dialPlan.AuthorisedApps = customer.AuthorisedApps + ";" + dialPlan.AuthorisedApps;
  429. DialPlanScriptContext scriptContext = new DialPlanScriptContext(
  430. Log_External,
  431. m_sipTransport,
  432. CreateDialogueBridge,
  433. m_outboundProxy,
  434. uas,
  435. dialPlan,
  436. GetSIPProviders_External(p => p.Owner == owner, null, 0, Int32.MaxValue),
  437. m_traceDirectory,
  438. (uas.CallDirection == SIPCallDirection.Out) ? sipAccount.NetworkId : null,
  439. customer.Id);
  440. //scriptContext.DialPlanComplete += () => { DecrementCustomerExecutionCount(customer);};
  441. m_dialPlanEngine.Execute(scriptContext, uas, uas.CallDirection, CreateDialogueBridge, this);
  442. }
  443. }
  444. else if (uas.CallDirection == SIPCallDirection.In)
  445. {
  446. if (uas.IsB2B)
  447. {
  448. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Dialplan could not be loaded for incoming B2B call to " + callURI.ToString() + ".", owner));
  449. uas.Reject(SIPResponseStatusCodesEnum.InternalServerError, "Error loading incoming dial plan for B2B call", null);
  450. //DecrementCustomerExecutionCount(customer);
  451. }
  452. else
  453. {
  454. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No dialplan specified for incoming call to " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + ", registered bindings will be used.", owner));
  455. // The SIP account has no dialplan for an incoming call therefore send to the SIP account's bindings.
  456. List<SIPRegistrarBinding> bindings = GetSIPAccountBindings_External(b => b.SIPAccountId == sipAccount.Id, null, 0, MAX_FORWARD_BINDINGS);
  457. if (bindings != null && bindings.Count > 0)
  458. {
  459. // Create a pseudo-dialplan to process the incoming call.
  460. string pseudoScript = "sys.Dial(\"" + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + "\")\n";
  461. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Forwarding incoming call for " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + " to " + bindings.Count + " bindings.", owner));
  462. SIPDialPlan incomingDialPlan = new SIPDialPlan(sipAccount.Owner, null, null, pseudoScript, SIPDialPlanScriptTypesEnum.Ruby);
  463. incomingDialPlan.Id = Guid.Empty; // Prevents the increment and decrement on the execution counts.
  464. DialPlanScriptContext scriptContext = new DialPlanScriptContext(
  465. Log_External,
  466. m_sipTransport,
  467. CreateDialogueBridge,
  468. m_outboundProxy,
  469. uas,
  470. incomingDialPlan,
  471. null,
  472. m_traceDirectory,
  473. null,
  474. customer.Id);
  475. //scriptContext.DialPlanComplete += () => { DecrementCustomerExecutionCount(customer); };
  476. m_dialPlanEngine.Execute(scriptContext, uas, uas.CallDirection, CreateDialogueBridge, this);
  477. }
  478. else
  479. {
  480. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No bindings available for " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + " returning temporarily not available.", owner));
  481. uas.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, null, null);
  482. //DecrementDialPlanExecutionCount(null, customer.Id);
  483. //DecrementCustomerExecutionCount(customer);
  484. }
  485. }
  486. }
  487. else
  488. {
  489. // Couldn't load a dialplan for an outgoing call.
  490. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Dialplan could not be loaded for " + uas.CallDirection + " call to " + callURI.ToString() + ".", owner));
  491. uas.Reject(SIPResponseStatusCodesEnum.InternalServerError, "Error loading dial plan", null);
  492. //DecrementDialPlanExecutionCount(null, customer.Id);
  493. //DecrementCustomerExecutionCount(customer);
  494. }
  495. }
  496. }
  497. }
  498. catch (Exception excp)
  499. {
  500. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.Error, "Exception SIPCallManager ProcessNewCall. " + excp.Message, null));
  501. uas.Reject(SIPResponseStatusCodesEnum.InternalServerError, "Exception ProcessNewCall", null);
  502. //if (wasExecutionCountIncremented)
  503. //{
  504. //DecrementDialPlanExecutionCount(dialPlan, customer.Id);
  505. // DecrementCustomerExecutionCount(customer);
  506. //}
  507. }
  508. }
  509. public string ProcessWebCall(string username, string number, string dialplanName, string replacesCallID)
  510. {
  511. //bool wasExecutionCountIncremented = false;
  512. Customer customer = null;
  513. SIPDialPlan dialPlan = null;
  514. try
  515. {
  516. customer = m_customerPersistor.Get(c => c.CustomerUsername == username);
  517. SIPDialogue replacesDialogue = (!replacesCallID.IsNullOrBlank() && customer != null) ? m_sipDialogueManager.GetDialogueRelaxed(customer.CustomerUsername, replacesCallID) : null;
  518. if (customer == null)
  519. {
  520. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Web " + dialplanName + " rejected for " + username + " and " + number + ", as no matching user.", null));
  521. return "Sorry no matching user was found, the " + dialplanName + " was not initiated.";
  522. }
  523. else if (customer.Suspended)
  524. {
  525. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Web " + dialplanName + " rejected for " + username + " and " + number + ", user account is suspended.", null));
  526. return "Sorry the user's account is suspended.";
  527. }
  528. else if (!replacesCallID.IsNullOrBlank() && replacesDialogue == null)
  529. {
  530. return "Sorry the blind transfer could not be initiated, the Call-ID to transfer could not be found.";
  531. }
  532. else
  533. {
  534. dialPlan = GetDialPlan_External(d => d.Owner == username && d.DialPlanName == dialplanName);
  535. if (dialPlan == null)
  536. {
  537. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Web " + dialplanName + " rejected as no " + dialplanName + " dialplan exists.", username));
  538. return "Sorry the specified user has not enabled callbacks, the callback was not initiated.";
  539. }
  540. else
  541. {
  542. if (!IsDialPlanExecutionAllowed(dialPlan, customer))
  543. {
  544. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Execution of web call for dialplan " + dialplanName + " was not processed as maximum execution count has been reached.", username));
  545. return "Sorry the callback was not initiated, dial plan execution exceeded maximum allowed";
  546. }
  547. else
  548. {
  549. //IncrementDialPlanExecutionCount(dialPlan, customer, originalExecutionCount + 1);
  550. //IncrementCustomerExecutionCount(customer);
  551. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Web call for " + dialplanName + " initialising to " + number + ".", username));
  552. ISIPServerUserAgent uas = null;
  553. if (replacesCallID.IsNullOrBlank())
  554. {
  555. UASInviteTransaction dummyTransaction = GetDummyWebCallbackTransaction(number);
  556. uas = new SIPServerUserAgent(m_sipTransport, m_outboundProxy, username, SIPDomainManager.DEFAULT_LOCAL_DOMAIN, SIPCallDirection.Out, GetSIPAccount_External, null, Log_External, dummyTransaction);
  557. }
  558. else
  559. {
  560. SIPDialogue oppositeDialogue = m_sipDialogueManager.GetOppositeDialogue(replacesDialogue);
  561. uas = new SIPTransferServerUserAgent(Log_External, m_sipDialogueManager.DialogueTransfer, m_sipTransport, m_outboundProxy, replacesDialogue, oppositeDialogue, number, customer.CustomerUsername, customer.AdminId);
  562. }
  563. dialPlan.AuthorisedApps = customer.AuthorisedApps + ";" + dialPlan.AuthorisedApps;
  564. DialPlanScriptContext scriptContext = new DialPlanScriptContext(
  565. Log_External,
  566. m_sipTransport,
  567. CreateDialogueBridge,
  568. m_outboundProxy,
  569. uas,
  570. dialPlan,
  571. GetSIPProviders_External(p => p.Owner == username, null, 0, Int32.MaxValue),
  572. m_traceDirectory,
  573. null,
  574. customer.Id);
  575. //scriptContext.DialPlanComplete += () => { DecrementCustomerExecutionCount(customer); };
  576. m_dialPlanEngine.Execute(scriptContext, uas, SIPCallDirection.Out, CreateDialogueBridge, this);
  577. if (replacesCallID.IsNullOrBlank())
  578. {
  579. return "Web call was successfully initiated.";
  580. }
  581. else
  582. {
  583. return "Blind transfer was successfully initiated.";
  584. }
  585. }
  586. }
  587. }
  588. }
  589. catch (Exception excp)
  590. {
  591. logger.Error("Exception SIPCallManager ProcessWebCall. " + excp.Message);
  592. //if (wasExecutionCountIncremented)
  593. //{
  594. //DecrementDialPlanExecutionCount(dialPlan, customer.Id, originalExecutionCount);
  595. //DecrementCustomerExecutionCount(customer);
  596. //}
  597. return "Sorry there was an unexpected error, the callback was not initiated.";
  598. }
  599. }
  600. /// <summary>
  601. /// Processes an in dialogue REFER request that specifies a new destination for an existing call leg.
  602. /// </summary>
  603. /// <param name="username">The username of the user the transfer is being processed for.</param>
  604. /// <param name="referTo">The Refer-To header URI from the REFER request.</param>
  605. /// <param name="dialplanName">The dialplan to use to process the transfer.</param>
  606. /// <param name="replacesCallID">The call ID that is being replaced by the new dialogue if one is created.</param>
  607. /// <returns>A SIP server user agent.</returns>
  608. public ISIPServerUserAgent BlindTransfer(string username, SIPURI referTo, string dialplanName, SIPDialogue replacesDialogue)
  609. {
  610. if (dialplanName.IsNullOrBlank())
  611. {
  612. throw new ApplicationException("A dial plan name must be provided when processing a blind transfer.");
  613. }
  614. else if (referTo == null)
  615. {
  616. throw new ApplicationException("The refer to URI cannot be empty when processing a blind transfer.");
  617. }
  618. else if (replacesDialogue == null)
  619. {
  620. throw new ApplicationException("The blind transfer could not be initiated, the dialogue to transfer could not be found.");
  621. }
  622. //bool wasExecutionCountIncremented = false;
  623. Customer customer = null;
  624. SIPDialPlan dialPlan = null;
  625. try
  626. {
  627. customer = m_customerPersistor.Get(c => c.CustomerUsername == username);
  628. if (customer == null)
  629. {
  630. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Blind transfer using dialplan " + dialplanName + " rejected for " + username + " and " + referTo.ToString() + ", as no matching user.", username));
  631. throw new ApplicationException("No matching user was found, the blind transfer was not initiated.");
  632. }
  633. else if (customer.Suspended)
  634. {
  635. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Blind transfer using dialplan " + dialplanName + " rejected for " + username + " and " + referTo.ToString() + ", user account is suspended.", username));
  636. throw new ApplicationException("The user's account is suspended, the blind transfer was not initiated.");
  637. }
  638. else
  639. {
  640. dialPlan = GetDialPlan_External(d => d.Owner == username && d.DialPlanName == dialplanName);
  641. if (dialPlan == null)
  642. {
  643. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Blind transfer rejected as no " + dialplanName + " dialplan exists.", username));
  644. throw new ApplicationException("The blind transfer could not be initiated, no dialplan with name " + dialplanName + " could be found.");
  645. }
  646. else
  647. {
  648. if (!IsDialPlanExecutionAllowed(dialPlan, customer))
  649. {
  650. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Execution of blind transfer for dialplan " + dialplanName + " was not processed as maximum execution count has been reached.", username));
  651. throw new ApplicationException("The blind transfer was not initiated, dial plan execution exceeded maximum allowed");
  652. }
  653. else
  654. {
  655. //IncrementCustomerExecutionCount(customer);
  656. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Blind transfer for dialplan " + dialplanName + " starting for " + referTo.ToString() + ".", username));
  657. SIPDialogue oppositeDialogue = m_sipDialogueManager.GetOppositeDialogue(replacesDialogue);
  658. ISIPServerUserAgent uas = new SIPTransferServerUserAgent(Log_External, m_sipDialogueManager.DialogueTransfer, m_sipTransport, m_outboundProxy, replacesDialogue, oppositeDialogue, referTo.ToString(), customer.CustomerUsername, customer.AdminId);
  659. DialPlanScriptContext scriptContext = new DialPlanScriptContext(
  660. Log_External,
  661. m_sipTransport,
  662. CreateDialogueBridge,
  663. m_outboundProxy,
  664. uas,
  665. dialPlan,
  666. GetSIPProviders_External(p => p.Owner == username, null, 0, Int32.MaxValue),
  667. m_traceDirectory,
  668. null,
  669. customer.Id);
  670. //scriptContext.DialPlanComplete += () => { DecrementCustomerExecutionCount(customer); };
  671. m_dialPlanEngine.Execute(scriptContext, uas, SIPCallDirection.Out, CreateDialogueBridge, this);
  672. return uas;
  673. }
  674. }
  675. }
  676. }
  677. catch (ApplicationException)
  678. {
  679. throw;
  680. }
  681. catch (Exception excp)
  682. {
  683. logger.Error("Exception SIPCallManager BlindTransfer. " + excp.Message);
  684. //if (wasExecutionCountIncremented)
  685. //{
  686. //DecrementDialPlanExecutionCount(dialPlan, customer.Id, originalExecutionCount);
  687. //DecrementCustomerExecutionCount(customer);
  688. //}
  689. throw;
  690. }
  691. }
  692. private bool GetDialPlanAndCustomer(string owner, string dialPlanName, ISIPServerUserAgent uas, out Customer customer, out SIPDialPlan dialPlan)
  693. {
  694. try
  695. {
  696. dialPlan = null;
  697. customer = m_customerPersistor.Get(c => c.CustomerUsername == owner);
  698. if (customer == null)
  699. {
  700. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected for customer " + owner + " as no matching account found.", null));
  701. uas.Reject(SIPResponseStatusCodesEnum.DoesNotExistAnywhere, "No matching user was found", null);
  702. }
  703. else if (customer.Suspended)
  704. {
  705. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected for customer " + owner + " as account is suspended.", null));
  706. uas.Reject(SIPResponseStatusCodesEnum.DoesNotExistAnywhere, "User account is suspended", null);
  707. }
  708. else if (dialPlanName.IsNullOrBlank() && uas.CallDirection == SIPCallDirection.Out)
  709. {
  710. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected for customer " + owner + " as no dialplan is configured for an " + uas.CallDirection + " call.", null));
  711. uas.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "SIP account missing dialplan setting", null);
  712. }
  713. else
  714. {
  715. dialPlan = GetDialPlan_External(d => d.Owner == owner && d.DialPlanName == dialPlanName);
  716. if (!IsDialPlanExecutionAllowed(dialPlan, customer))
  717. {
  718. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Execution of dial plan " + dialPlanName + " was not processed as maximum execution count has been reached.", owner));
  719. uas.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "Dial plan execution exceeded maximum allowed", null);
  720. }
  721. else
  722. {
  723. if (m_dailyCallLimit == -1)
  724. {
  725. return true;
  726. }
  727. else
  728. {
  729. // Check whether the number of CDR's exceeds the daily call limit.
  730. DateTime yesterday = DateTime.Now.AddDays(-1);
  731. int cdrCount = m_sipCDRPersistor.Count(x => x.Owner == owner && x.Created > yesterday);
  732. if (cdrCount >= m_dailyCallLimit)
  733. {
  734. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Execution of call for " + owner + " was not processed as daily call limit reached.", owner));
  735. uas.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "Daily call limit reached", null);
  736. }
  737. else
  738. {
  739. return true;
  740. }
  741. }
  742. }
  743. }
  744. return false;
  745. }
  746. catch (Exception excp)
  747. {
  748. logger.Error("Exception GetDialPlanAndCustomer. " + excp.Message);
  749. throw;
  750. }
  751. }
  752. private bool IsDialPlanExecutionAllowed(SIPDialPlan dialPlan, Customer customer)
  753. {
  754. try
  755. {
  756. /*int dialPlanExecutionCount = (dialPlan != null) ? dialPlan.ExecutionCount : 0;
  757. int dialPlanMaxExecutionCount = (dialPlan != null) ? dialPlan.MaxExecutionCount : 0;
  758. if (customer.ExecutionCount >= customer.MaxExecutionCount ||
  759. (dialPlan != null && dialPlanExecutionCount >= dialPlanMaxExecutionCount))
  760. {
  761. return false;
  762. }
  763. else
  764. {
  765. return true;
  766. }*/
  767. //logger.Debug("IsDialPlanExecutionAllowed for " + customer.CustomerUsername + " and " + dialPlan.DialPlanName + ", count=" + dialPlan.ExecutionCount + ", max=" + dialPlan.MaxExecutionCount + ".");
  768. //return (customer.ExecutionCount < customer.MaxExecutionCount);
  769. int currentlyExecuting = m_dialPlanEngine.GetExecutionCountForUser(customer.CustomerUsername);
  770. if (dialPlan != null)
  771. {
  772. return currentlyExecuting < customer.MaxExecutionCount && currentlyExecuting < dialPlan.MaxExecutionCount;
  773. }
  774. else
  775. {
  776. return currentlyExecuting < customer.MaxExecutionCount;
  777. }
  778. }
  779. catch (Exception excp)
  780. {
  781. logger.Error("Exception IsDialPlanExecutionAllowed. " + excp.Message);
  782. throw excp;
  783. }
  784. }
  785. /*private void IncrementDialPlanExecutionCount(SIPDialPlan dialPlan, Customer customer, int customerExecutionCount)
  786. {
  787. try
  788. {
  789. using (var trans = new TransactionScope())
  790. {
  791. if (dialPlan != null && dialPlan.Id != Guid.Empty)
  792. {
  793. int executionCount = Convert.ToInt32(m_dialPlanPersistor.GetProperty(dialPlan.Id, m_sipDialPlanExecutionCountPropertyName));
  794. logger.Debug("Incrementing dial plan execution count for " + dialPlan.DialPlanName + "@" + dialPlan.Owner + ", currently=" + executionCount + ".");
  795. m_dialPlanPersistor.UpdateProperty(dialPlan.Id, m_sipDialPlanExecutionCountPropertyName, executionCount + 1);
  796. }
  797. int customerExecutionCount = Convert.ToInt32(m_customerPersistor.GetProperty(customer.Id, m_sipDialPlanExecutionCo…

Large files files are truncated, but you can click here to view the full file