/// <summary> /// Cleans up any resources being used. /// </summary> public override void Dispose() { lock(this.SyncRoot){ if(m_pTimer100 != null){ m_pTimer100.Dispose(); m_pTimer100 = null; } if(m_pTimerG != null){ m_pTimerG.Dispose(); m_pTimerG = null; } if(m_pTimerH != null){ m_pTimerH.Dispose(); m_pTimerH = null; } if(m_pTimerI != null){ m_pTimerI.Dispose(); m_pTimerI = null; } if(m_pTimerJ != null){ m_pTimerJ.Dispose(); m_pTimerJ = null; } if(m_pTimerL != null){ m_pTimerL.Dispose(); m_pTimerL = null; } } }
/// <summary> /// Default constructor. /// </summary> /// <param name="stack">Owner SIP stack.</param> /// <param name="server">Registrar server URI. For example: sip:domain.com.</param> /// <param name="aor">Address of record. For example: [email protected].</param> /// <param name="contact">Contact URI.</param> /// <param name="expires">Gets after how many seconds reigisration expires.</param> /// <exception cref="ArgumentNullException">Is raised when <b>ua</b>,<b>server</b>,<b>transport</b>,<b>aor</b> or <b>contact</b> is null reference.</exception> /// <exception cref="ArgumentException">Is raised when any of the arguments contains invalid value.</exception> internal SIP_UA_Registration(SIP_Stack stack,SIP_Uri server,string aor,AbsoluteUri contact,int expires) { if(stack == null){ throw new ArgumentNullException("stack"); } if(server == null){ throw new ArgumentNullException("server"); } if(aor == null){ throw new ArgumentNullException("aor"); } if(aor == string.Empty){ throw new ArgumentException("Argument 'aor' value must be specified."); } if(contact == null){ throw new ArgumentNullException("contact"); } m_pStack = stack; m_pServer = server; m_AOR = aor; m_pContact = contact; m_RefreshInterval = expires; m_pContacts = new List<AbsoluteUri>(); m_pTimer = new TimerEx((m_RefreshInterval - 15) * 1000); m_pTimer.AutoReset = false; m_pTimer.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimer_Elapsed); m_pTimer.Enabled = false; }
/// <summary> /// Stops TCP server, all active connections will be terminated. /// </summary> public void Stop() { if (!m_IsRunning) { return; } m_IsRunning = false; // Dispose all old binds. foreach (ListeningPoint listeningPoint in m_pListeningPoints.ToArray()) { try { listeningPoint.Socket.Close(); } catch (Exception x) { OnError(x); } } m_pListeningPoints.Clear(); m_pTimer_IdleTimeout.Dispose(); m_pTimer_IdleTimeout = null; OnStopped(); }
/// <summary> /// Cleans up any resources being used. /// </summary> public override void Dispose() { lock (SyncRoot) { if (m_pTimer100 != null) { m_pTimer100.Dispose(); m_pTimer100 = null; } if (m_pTimerG != null) { m_pTimerG.Dispose(); m_pTimerG = null; } if (m_pTimerH != null) { m_pTimerH.Dispose(); m_pTimerH = null; } if (m_pTimerI != null) { m_pTimerI.Dispose(); m_pTimerI = null; } if (m_pTimerJ != null) { m_pTimerJ.Dispose(); m_pTimerJ = null; } } }
/// <summary> /// Starts SMTP relay server. /// </summary> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception> public virtual void Start() { if (m_IsDisposed) { throw new ObjectDisposedException(this.GetType().Name); } if (m_IsRunning) { return; } m_IsRunning = true; m_pLocalEndPointIPv4 = new CircleCollection <IPBindInfo>(); m_pLocalEndPointIPv6 = new CircleCollection <IPBindInfo>(); m_pSessions = new TCP_SessionCollection <Relay_Session>(); m_pConnectionsPerIP = new Dictionary <IPAddress, long>(); Thread tr1 = new Thread(new ThreadStart(this.Run)); tr1.Start(); m_pTimerTimeout = new TimerEx(30000); m_pTimerTimeout.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerTimeout_Elapsed); m_pTimerTimeout.Start(); }
/// <summary> /// Starts transaction processing. /// </summary> private void Start() { #region INVITE if (Method == SIP_Methods.INVITE) { /* RFC 3261 17.2.1. * When a server transaction is constructed for a request, it enters the "Proceeding" state. The server * transaction MUST generate a 100 (Trying) response unless it knows that the TU will generate a provisional * or final response within 200 ms, in which case it MAY generate a 100 (Trying) response. */ SetState(SIP_TransactionState.Proceeding); m_pTimer100 = new TimerEx(200, false); m_pTimer100.Elapsed += m_pTimer100_Elapsed; m_pTimer100.Enabled = true; } #endregion #region Non-INVITE else { // RFC 3261 17.2.2. The state machine is initialized in the "Trying" state. SetState(SIP_TransactionState.Trying); } #endregion }
/// <summary> /// Is raised when Non-INVITE timer F triggered. /// </summary> /// <param name="sender">Sender.</param> /// <param name="e">Event data.</param> private void m_pTimerF_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { /* RFC 3261 17.1.2.2. * If Timer F fires while in the "Trying" state, the client transaction SHOULD inform the TU about the * timeout, and then it SHOULD enter the "Terminated" state. * * If timer F fires while in the "Proceeding" state, the TU MUST be informed of a timeout, and the * client transaction MUST transition to the terminated state. */ lock (this.SyncRoot){ if (this.State == SIP_TransactionState.Trying || this.State == SIP_TransactionState.Proceeding) { // Log if (this.Stack.Logger != null) { this.Stack.Logger.AddText(this.ID, "Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer F(Non-INVITE trying,proceeding state timeout) triggered."); } OnTimedOut(); SetState(SIP_TransactionState.Terminated); if (m_pTimerE != null) { m_pTimerE.Dispose(); m_pTimerE = null; } if (m_pTimerF != null) { m_pTimerF.Dispose(); m_pTimerF = null; } } } }
/// <summary> /// Default constructor. /// </summary> internal DNS_ClientCache() { m_pCache = new Dictionary<string,CacheEntry>(); m_pTimerTimeout = new TimerEx(60000); m_pTimerTimeout.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerTimeout_Elapsed); m_pTimerTimeout.Start(); }
/// <summary> /// Default constructor. /// </summary> internal DNS_ClientCache() { m_pCache = new Dictionary <string, CacheEntry>(); m_pTimerTimeout = new TimerEx(60000); m_pTimerTimeout.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerTimeout_Elapsed); m_pTimerTimeout.Start(); }
public void InitTimer() { productionTimer = TimerEx.Init("Production ", 1.0f, OnProductionTimer, true); if (productionTimer != null) { productionTimer.Pause(); } }
static void Main(string[] args) { TimerEx timer = new TimerEx(1000, 1, 2, 3, 4, 5); timer.ElapsedEx += new ElapsedExEventHandler(timer_ElapsedEx); timer.Start(); Console.ReadKey(); }
public DateFileAppender() { BaseDir = "Logs"; Encoding = Encoding.UTF8; Pattern = $"yyyy{Path.DirectorySeparatorChar}yyyy-MM-dd.'txt'"; timer = new TimerEx(this.WriteInterval); timer.Elapsed += WriteTimer_Elapsed; }
/// <summary> /// Starts this server. /// </summary> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception> public void Start() { ThrowIfObjectDisposed(); if (m_IsRunning) { return; } m_IsRunning = true; m_StartTime = DateTime.Now; m_ConnectionsProcessed = 0; ThreadPool.QueueUserWorkItem((o) => { StartListen(); }); m_pTimer_IdleTimeout = new TimerEx(30 * 1000); // 30s m_pTimer_IdleTimeout.Elapsed += (sender, e) => { try { foreach (T session in this.Sessions.ToArray()) { try { if (m_SessionIdleTimeout > 0 && DateTime.Now > session.TcpStream.LastActivity.AddSeconds(m_SessionIdleTimeout)) { session.OnTimeout(); // Session didn't dispose itself, so dispose it. if (!session.IsDisposed) { session.Disconnect(); session.Dispose(); } } } catch (Exception ex) { // just skip. string dummy = ex.Message; } } } catch (Exception ex) { OnError(ex); } }; OnStarted(); }
/// <summary> /// Cleans up any resources being used. /// </summary> public override void Dispose() { lock (this.SyncRoot){ if (this.IsDisposed) { return; } // Log if (this.Stack.Logger != null) { this.Stack.Logger.AddText(this.ID, "Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] disposed."); } // Kill timers. if (m_pTimerA != null) { m_pTimerA.Dispose(); m_pTimerA = null; } if (m_pTimerB != null) { m_pTimerB.Dispose(); m_pTimerB = null; } if (m_pTimerD != null) { m_pTimerD.Dispose(); m_pTimerD = null; } if (m_pTimerE != null) { m_pTimerE.Dispose(); m_pTimerE = null; } if (m_pTimerF != null) { m_pTimerF.Dispose(); m_pTimerF = null; } if (m_pTimerK != null) { m_pTimerK.Dispose(); m_pTimerK = null; } this.ResponseReceived = null; base.Dispose(); } }
protected override void OnLoad(EventArgs e) { base.OnLoad(e); #region 写真をリスト化する CreatePhotoList(); #endregion #region 背景用のビットマップを作成、背景は黒で初期化 _baseBitmap = new Bitmap(Width, Height, PixelFormat.Format24bppRgb); _baseBitmap.Clear(Color.Black); #endregion #region 背景のスクロール用のタイマーを作成 _baseTimer = new TimerEx { Interval = ScrollInterval }; _baseTimer.Tick += BaseTimerOnTick; #endregion #region 写真を追加するタイマーを作成 _photoTimer = new TimerEx { Interval = PhotoInterval }; _photoTimer.Tick += PhotoTimerOnTick; #endregion #region 最初の写真を登録 // 写真を追加するタイマーの間隔が長いため、 // 先にイベントを呼び出し写真を登録しておく PhotoTimerOnTick(this, EventArgs.Empty); #endregion #region 背景のスクロール用のタイマーと、写真読み込み用のタイマーを起動する _baseTimer.Start(); _photoTimer.Start(); #endregion }
/// <summary> /// Cleans up any resource being used. /// </summary> public void Dispose() { m_pTimeoutTimer.Dispose(); m_pTimeoutTimer = null; m_pOwner.m_pTransactions.Remove(this.ID); m_pOwner = null; m_pQuery = null; m_pResponse = null; this.Timeout = null; this.Completed = null; }
/// <summary> /// Cleans up nay resource being used. /// </summary> public void Dispose() { if (m_pNonces == null) { m_pNonces.Clear(); m_pNonces = null; } if (m_pTimer != null) { m_pTimer.Dispose(); m_pTimer = null; } }
/// <summary> /// Default constructor. /// </summary> /// <param name="owner">Owner transport layer.</param> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> is null reference.</exception> internal SIP_FlowManager(SIP_TransportLayer owner) { if(owner == null){ throw new ArgumentNullException("owner"); } m_pOwner = owner; m_pFlows = new Dictionary<string,SIP_Flow>(); m_pTimeoutTimer = new TimerEx(15000); m_pTimeoutTimer.AutoReset = true; m_pTimeoutTimer.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimeoutTimer_Elapsed); m_pTimeoutTimer.Enabled = true; }
/// <summary> /// Default constructor. /// </summary> /// <param name="proxy">Owner proxy.</param> /// <exception cref="ArgumentNullException">Is raised when <b>proxy</b> is null reference.</exception> internal SIP_Registrar(SIP_Proxy proxy) { if (proxy == null) { throw new ArgumentNullException("proxy"); } m_pProxy = proxy; m_pStack = m_pProxy.Stack; m_pRegistrations = new SIP_RegistrationCollection(); m_pTimer = new TimerEx(m_pTimer_Elapsed, 15000); m_pTimer.Start(); }
public void Dispose() { if (IsDisposed) { return; } IsDisposed = true; ClearTimer.Stop(); ClearTimer = null; ItemsByKey.Clear(); ItemsByKey = null; }
public MemoryCache(int capacity = 100000) { if (capacity < 1000) { throw new ArgumentException($"Argument '{nameof(capacity)}' value must be >= 1000."); } MaxCapacity = capacity; ItemsByKey = new Dictionary <string, MemoryCacheItem>(capacity); First = Last = new MemoryCacheItem(); ClearTimer = new TimerEx(60 * 1000); ClearTimer.Elapsed += Clear_Elapsed; ClearTimer.Start(); }
/// <summary> /// Cleans up any resources being used. /// </summary> public override void Dispose() { lock(this.SyncRoot){ if(this.IsDisposed){ return; } // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] disposed."); } // Kill timers. if(m_pTimerA != null){ m_pTimerA.Dispose(); m_pTimerA = null; } if(m_pTimerB != null){ m_pTimerB.Dispose(); m_pTimerB = null; } if(m_pTimerD != null){ m_pTimerD.Dispose(); m_pTimerD = null; } if(m_pTimerE != null){ m_pTimerE.Dispose(); m_pTimerE = null; } if(m_pTimerF != null){ m_pTimerF.Dispose(); m_pTimerF = null; } if(m_pTimerK != null){ m_pTimerK.Dispose(); m_pTimerK = null; } if(m_pTimerM != null){ m_pTimerM.Dispose(); m_pTimerM = null; } this.ResponseReceived = null; base.Dispose(); } }
/// <summary> /// 构造函数 /// </summary> /// <param name="currentNodeName">当前节点名称</param> public ProcessNamedPipe(string currentNodeName) { _mutex = new Mutex(true, currentNodeName, out var isSuccess); if (!isSuccess) { throw new ArgumentOutOfRangeException("currentNodeName", "指定名称的管道已被注册,无法重复注册"); } _pipName = currentNodeName; beginwaitForConnection(); _checkConnect = new TimerEx(checkServer, 5000, 0); _checkConnect.Start(); }
/// <summary> /// Is raised when INVITE 100 (Trying) response must be sent if no response sent by transaction user. /// </summary> /// <param name="sender">Sender.</param> /// <param name="e">Event data.</param> private void m_pTimer100_Elapsed(object sender, ElapsedEventArgs e) { lock (SyncRoot) { // RFC 3261 17.2.1. TU didn't generate response in 200 ms, send '100 Trying' to stop request retransmission. if (State == SIP_TransactionState.Proceeding && Responses.Length == 0) { /* RFC 3261 17.2.1. * The 100 (Trying) response is constructed according to the procedures in Section 8.2.6, except that the * insertion of tags in the To header field of the response (when none was present in the request) * is downgraded from MAY to SHOULD NOT. * * RFC 3261 8.2.6. * When a 100 (Trying) response is generated, any Timestamp header field present in the request MUST * be copied into this 100 (Trying) response. If there is a delay in generating the response, the UAS * SHOULD add a delay value into the Timestamp value in the response. This value MUST contain the difference * between the time of sending of the response and receipt of the request, measured in seconds. */ SIP_Response tryingResponse = Stack.CreateResponse(SIP_ResponseCodes.x100_Trying, Request); if (Request.Timestamp != null) { tryingResponse.Timestamp = new SIP_t_Timestamp(Request.Timestamp.Time, (DateTime.Now - CreateTime).Seconds); } try { Stack.TransportLayer.SendResponse(this, tryingResponse); } catch (Exception x) { OnTransportError(x); SetState(SIP_TransactionState.Terminated); return; } } if (m_pTimer100 != null) { m_pTimer100.Dispose(); m_pTimer100 = null; } } }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { lock(m_pLock){ if(m_IsDisposed){ return; } m_IsDisposed = true; foreach(SIP_Flow flow in this.Flows){ flow.Dispose(); } m_pOwner = null; m_pFlows = null; m_pTimeoutTimer.Dispose(); m_pTimeoutTimer = null; } }
/// <summary> /// Default constructor. /// </summary> /// <param name="owner">Owner DNS client.</param> /// <param name="id">Transaction ID.</param> /// <param name="qtype">QTYPE value.</param> /// <param name="qname">QNAME value.</param> /// <param name="timeout">Timeout in milliseconds.</param> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> or <b>qname</b> is null reference.</exception> internal DNS_ClientTransaction(Dns_Client owner,int id,DNS_QType qtype,string qname,int timeout) { if(owner == null){ throw new ArgumentNullException("owner"); } if(qname == null){ throw new ArgumentNullException("qname"); } m_pOwner = owner; m_ID = id; m_QName = qname; m_QType = qtype; m_CreateTime = DateTime.Now; m_pTimeoutTimer = new TimerEx(timeout); m_pTimeoutTimer.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimeoutTimer_Elapsed); }
public SessionHandler() { var procAct = new Action(() => { var now = DateTime.UtcNow; if (IsGameRunning()) { if (_startSessionTime <= DateTime.MinValue) { _startSessionTime = now; } _lastSessionTime = now; } }); procAct.Invoke(); TimerEx.Every(1f, procAct); }
/// <summary> /// Default constructor. /// </summary> /// <param name="owner">Owner DNS client.</param> /// <param name="id">Transaction ID.</param> /// <param name="qtype">QTYPE value.</param> /// <param name="qname">QNAME value.</param> /// <param name="timeout">Timeout in milliseconds.</param> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> or <b>qname</b> is null reference.</exception> internal DNS_ClientTransaction(Dns_Client owner, int id, DNS_QType qtype, string qname, int timeout) { if (owner == null) { throw new ArgumentNullException("owner"); } if (qname == null) { throw new ArgumentNullException("qname"); } m_pOwner = owner; m_ID = id; m_QName = qname; m_QType = qtype; m_CreateTime = DateTime.Now; m_pTimeoutTimer = new TimerEx(timeout); m_pTimeoutTimer.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimeoutTimer_Elapsed); }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { lock (m_pLock){ if (m_IsDisposed) { return; } m_IsDisposed = true; m_pDialog.m_pUasInvite2xxRetransmits.Remove(this); if (m_pTimer != null) { m_pTimer.Dispose(); m_pTimer = null; } m_pDialog = null; m_pResponse = null; } }
/// <summary> /// Cleans up any resource being used. /// </summary> public void Dispose() { lock(m_pLock){ if(this.State == DNS_ClientTransactionState.Disposed){ return; } SetState(DNS_ClientTransactionState.Disposed); m_pTimeoutTimer.Dispose(); m_pTimeoutTimer = null; m_pOwner = null; m_pResponse = null; this.StateChanged = null; this.Timeout = null; } }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { if (m_IsDisposed) { return; } m_IsDisposed = true; m_pStack = null; m_pTimer.Dispose(); m_pTimer = null; SetState(SIP_UA_RegistrationState.Disposed); OnDisposed(); this.Registered = null; this.Unregistered = null; this.Error = null; this.Disposed = null; }
/// <summary> /// Default constructor. /// </summary> /// <param name="owner">Owner DNS client.</param> /// <param name="id">Transaction ID.</param> /// <param name="qname">QNAME value.</param> /// <param name="qtype">QTYPE value.</param> /// <param name="timeout">Timeout in milliseconds.</param> /// <param name="query">Raw DNS query.</param> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> or <b>query</b> is null reference.</exception> public DnsTransaction(Dns_Client owner, int id, string qname, int qtype, int timeout, byte[] query) { if (owner == null) { throw new ArgumentNullException("owner"); } if (query == null) { throw new ArgumentNullException("query"); } m_pOwner = owner; m_ID = id; m_pQuery = query; m_QName = qname; m_QType = qtype; m_CreateTime = DateTime.Now; m_pTimeoutTimer = new TimerEx(timeout); m_pTimeoutTimer.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimeoutTimer_Elapsed); }
/// <summary> /// Cleans up any resource being used. /// </summary> public void Dispose() { lock (m_pLock){ if (this.State == DNS_ClientTransactionState.Disposed) { return; } SetState(DNS_ClientTransactionState.Disposed); m_pTimeoutTimer.Dispose(); m_pTimeoutTimer = null; m_pOwner = null; m_pResponse = null; this.StateChanged = null; this.Timeout = null; } }
/// <summary> /// Default constructor. /// </summary> /// <param name="dialog">Owner INVITE dialog.</param> /// <param name="invite">INVITE request which 2xx retransmission to wait.</param> /// <exception cref="ArgumentNullException">Is raised when <b>dialog</b> or <b>invite</b> is null reference.</exception> public UacInvite2xxRetransmissionWaiter(SIP_Dialog_Invite dialog, SIP_Request invite) { if (dialog == null) { throw new ArgumentNullException("dialog"); } if (invite == null) { throw new ArgumentNullException("invite"); } m_pDialog = dialog; m_pInvite = invite; /* RFC 3261 13.2.2.4. * The UAC core considers the INVITE transaction completed 64*T1 seconds * after the reception of the first 2xx response. */ m_pTimer = new TimerEx(64 * SIP_TimerConstants.T1, false); m_pTimer.Elapsed += m_pTimer_Elapsed; m_pTimer.Enabled = true; }
/// <summary> /// Cleans up any resources being used. /// </summary> internal void Dispose() { if (m_IsDisposed) { return; } m_IsDisposed = true; this.CanRegister = null; this.AorRegistered = null; this.AorUnregistered = null; this.AorUpdated = null; m_pProxy = null; m_pStack = null; m_pRegistrations = null; if (m_pTimer != null) { m_pTimer.Dispose(); m_pTimer = null; } }
public static TimerEx Init(string timerName, float interval, CALLBACK callback, bool loop = false, System.Object parameter = null) { if (_timerRoot == null) { _timerRoot = new GameObject("TimerSpawn"); MonoBehaviour.DontDestroyOnLoad(_timerRoot); } GameObject gameObject = new GameObject(TIMEREX_NAME_PREFIX + timerName); MonoBehaviour.DontDestroyOnLoad(gameObject); gameObject.transform.parent = _timerRoot.transform; TimerEx t = gameObject.AddComponent <TimerEx>(); if (t != null) { t.Init(interval, callback, loop, parameter); return(t); } return(null); }
/// <summary> /// Default constructor. /// </summary> /// <param name="dialog">Owner INVITE dialog.</param> /// <param name="invite">INVITE request which 2xx retransmission to wait.</param> /// <exception cref="ArgumentNullException">Is raised when <b>dialog</b> or <b>invite</b> is null reference.</exception> public UacInvite2xxRetransmissionWaiter(SIP_Dialog_Invite dialog, SIP_Request invite) { if (dialog == null) { throw new ArgumentNullException("dialog"); } if (invite == null) { throw new ArgumentNullException("invite"); } m_pDialog = dialog; m_pInvite = invite; /* RFC 3261 13.2.2.4. The UAC core considers the INVITE transaction completed 64*T1 seconds after the reception of the first 2xx response. */ m_pTimer = new TimerEx(64*SIP_TimerConstants.T1, false); m_pTimer.Elapsed += m_pTimer_Elapsed; m_pTimer.Enabled = true; }
/// <summary> /// Stops this server, all active connections will be terminated. /// </summary> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception> public void Stop() { ThrowIfObjectDisposed(); if (!m_IsRunning) { return; } m_IsRunning = false; // Dispose all old TCP acceptors. foreach (var acceptor in m_pConnectionAcceptors.ToArray()) { try { acceptor.Dispose(); } catch (Exception ex) { OnError(ex); } } m_pConnectionAcceptors.Clear(); // Dispose all old binds. foreach (var listeningPoint in m_pListeningPoints.ToArray()) { try { listeningPoint.Socket.Dispose(); } catch (Exception ex) { OnError(ex); } } m_pListeningPoints.Clear(); m_pTimer_IdleTimeout.Stop(); m_pTimer_IdleTimeout.Dispose(); m_pTimer_IdleTimeout = null; OnStopped(); }
/// <summary> /// Default constructor. /// </summary> /// <param name="stack">Owner SIP stack.</param> /// <param name="server">Registrar server URI. For example: sip:domain.com.</param> /// <param name="aor">Address of record. For example: [email protected].</param> /// <param name="contact">Contact URI.</param> /// <param name="expires">Gets after how many seconds reigisration expires.</param> /// <exception cref="ArgumentNullException">Is raised when <b>ua</b>,<b>server</b>,<b>transport</b>,<b>aor</b> or <b>contact</b> is null reference.</exception> /// <exception cref="ArgumentException">Is raised when any of the arguments contains invalid value.</exception> internal SIP_UA_Registration(SIP_Stack stack, SIP_Uri server, string aor, AbsoluteUri contact, int expires) { if (stack == null) { throw new ArgumentNullException("stack"); } if (server == null) { throw new ArgumentNullException("server"); } if (aor == null) { throw new ArgumentNullException("aor"); } if (aor == string.Empty) { throw new ArgumentException("Argument 'aor' value must be specified."); } if (contact == null) { throw new ArgumentNullException("contact"); } m_pStack = stack; m_pServer = server; m_AOR = aor; m_pContact = contact; m_RefreshInterval = expires; m_pTimer = new TimerEx((m_RefreshInterval - 15) * 1000); m_pTimer.AutoReset = false; m_pTimer.Elapsed += m_pTimer_Elapsed; m_pTimer.Enabled = false; }
/// <summary> /// Starts IDLE command processing. /// </summary> private void Start() { /* RFC 2177 IDLE command example. C: A004 IDLE S: * 2 EXPUNGE S: * 3 EXISTS S: + idling ...time passes; another client expunges message 3... S: * 3 EXPUNGE S: * 2 EXISTS ...time passes; new mail arrives... S: * 3 EXISTS C: DONE S: A004 OK IDLE terminated */ // Send status reponse to connected client if any. m_pSession.ProcessMailboxChanges(folder); // Send "+ idling" to connected client. m_pSession.WriteLine("+ idling"); // Start timer to poll mailbox changes. m_pSession.FolderChanged += m_pSession_FolderChanged; m_pTimer = new TimerEx(5000, true); m_pTimer.Elapsed += m_pTimer_Elapsed; m_pTimer.Enabled = true; // Start waiting DONE command from connected client. m_pSession.ReadAsync(ReadLineCompleted); }
/// <summary> /// Is raised when INVITE timer B triggered. /// </summary> /// <param name="sender">Sender.</param> /// <param name="e">Event data.</param> private void m_pTimerB_Elapsed(object sender,System.Timers.ElapsedEventArgs e) { /* RFC 3261 17.1.1.2. If the client transaction is still in the "Calling" state when timer B fires, the client transaction SHOULD inform the TU that a timeout has occurred. The client transaction MUST NOT generate an ACK. The value of 64*T1 is equal to the amount of time required to send seven requests in the case of an unreliable transport. */ lock(this.SyncRoot){ if(this.State == SIP_TransactionState.Calling){ // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer B(INVITE calling state timeout) triggered."); } OnTimedOut(); SetState(SIP_TransactionState.Terminated); // Stop timers A,B. if(m_pTimerA != null){ m_pTimerA.Dispose(); m_pTimerA = null; } if(m_pTimerB != null){ m_pTimerB.Dispose(); m_pTimerB = null; } } } }
private bool IDLE(string cmdTag,string cmdText) { /* RFC 2177 3. IDLE Command. Arguments: none Responses: continuation data will be requested; the client sends the continuation data "DONE" to end the command Result: OK - IDLE completed after client sent "DONE" NO - failure: the server will not allow the IDLE command at this time BAD - command unknown or arguments invalid The IDLE command may be used with any IMAP4 server implementation that returns "IDLE" as one of the supported capabilities to the CAPABILITY command. If the server does not advertise the IDLE capability, the client MUST NOT use the IDLE command and must poll for mailbox updates. In particular, the client MUST continue to be able to accept unsolicited untagged responses to ANY command, as specified in the base IMAP specification. The IDLE command is sent from the client to the server when the client is ready to accept unsolicited mailbox update messages. The server requests a response to the IDLE command using the continuation ("+") response. The IDLE command remains active until the client responds to the continuation, and as long as an IDLE command is active, the server is now free to send untagged EXISTS, EXPUNGE, and other messages at any time. The IDLE command is terminated by the receipt of a "DONE" continuation from the client; such response satisfies the server's continuation request. At that point, the server MAY send any remaining queued untagged responses and then MUST immediately send the tagged response to the IDLE command and prepare to process other commands. As in the base specification, the processing of any new command may cause the sending of unsolicited untagged responses, subject to the ambiguity limitations. The client MUST NOT send a command while the server is waiting for the DONE, since the server will not be able to distinguish a command from a continuation. The server MAY consider a client inactive if it has an IDLE command running, and if such a server has an inactivity timeout it MAY log the client off implicitly at the end of its timeout period. Because of that, clients using IDLE are advised to terminate the IDLE and re-issue it at least every 29 minutes to avoid being logged off. This still allows a client to receive immediate mailbox updates even though it need only "poll" at half hour intervals. Example: C: A001 SELECT INBOX S: * FLAGS (Deleted Seen) S: * 3 EXISTS S: * 0 RECENT S: * OK [UIDVALIDITY 1] S: A001 OK SELECT completed C: A002 IDLE S: + idling ...time passes; new mail arrives... S: * 4 EXISTS C: DONE S: A002 OK IDLE terminated ...another client expunges message 2 now... C: A003 FETCH 4 ALL S: * 4 FETCH (...) S: A003 OK FETCH completed C: A004 IDLE S: * 2 EXPUNGE S: * 3 EXISTS S: + idling ...time passes; another client expunges message 3... S: * 3 EXPUNGE S: * 2 EXISTS ...time passes; new mail arrives... S: * 3 EXISTS C: DONE S: A004 OK IDLE terminated C: A005 FETCH 3 ALL S: * 3 FETCH (...) S: A005 OK FETCH completed */ if(!this.IsAuthenticated){ m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"NO","Authentication required.")); return true; } m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus("+","idling")); TimerEx timer = new TimerEx(30000,true); timer.Elapsed += new System.Timers.ElapsedEventHandler(delegate(object sender,System.Timers.ElapsedEventArgs e){ try{ UpdateSelectedFolderAndSendChanges(); } catch{ } }); timer.Enabled = true; // Read client response. SmartStream.ReadLineAsyncOP readLineOP = new SmartStream.ReadLineAsyncOP(new byte[32000],SizeExceededAction.JunkAndThrowException); readLineOP.Completed += new EventHandler<EventArgs<SmartStream.ReadLineAsyncOP>>(delegate(object sender,EventArgs<SmartStream.ReadLineAsyncOP> e){ try{ if(readLineOP.Error != null){ LogAddText("Error: " + readLineOP.Error.Message); timer.Dispose(); return; } // Remote host closed connection. else if(readLineOP.BytesInBuffer == 0){ LogAddText("Remote host(connected client) closed IMAP connection."); timer.Dispose(); Dispose(); return; } LogAddRead(readLineOP.BytesInBuffer,readLineOP.LineUtf8); if(string.Equals(readLineOP.LineUtf8,"DONE",StringComparison.InvariantCultureIgnoreCase)){ timer.Dispose(); m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"OK","IDLE terminated.")); BeginReadCmd(); } else{ while(this.TcpStream.ReadLine(readLineOP,true)){ if(readLineOP.Error != null){ LogAddText("Error: " + readLineOP.Error.Message); timer.Dispose(); return; } LogAddRead(readLineOP.BytesInBuffer,readLineOP.LineUtf8); if(string.Equals(readLineOP.LineUtf8,"DONE",StringComparison.InvariantCultureIgnoreCase)){ timer.Dispose(); m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"OK","IDLE terminated.")); BeginReadCmd(); break; } } } } catch(Exception x){ timer.Dispose(); OnError(x); } }); while(this.TcpStream.ReadLine(readLineOP,true)){ if(readLineOP.Error != null){ LogAddText("Error: " + readLineOP.Error.Message); timer.Dispose(); break; } LogAddRead(readLineOP.BytesInBuffer,readLineOP.LineUtf8); if(string.Equals(readLineOP.LineUtf8,"DONE",StringComparison.InvariantCultureIgnoreCase)){ timer.Dispose(); m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"OK","IDLE terminated.")); BeginReadCmd(); break; } } return false; }
/// <summary> /// Is raised when Non-INVITE timer F triggered. /// </summary> /// <param name="sender">Sender.</param> /// <param name="e">Event data.</param> private void m_pTimerF_Elapsed(object sender,System.Timers.ElapsedEventArgs e) { /* RFC 3261 17.1.2.2. If Timer F fires while in the "Trying" state, the client transaction SHOULD inform the TU about the timeout, and then it SHOULD enter the "Terminated" state. If timer F fires while in the "Proceeding" state, the TU MUST be informed of a timeout, and the client transaction MUST transition to the terminated state. */ lock(this.SyncRoot){ if(this.State == SIP_TransactionState.Trying || this.State == SIP_TransactionState.Proceeding){ // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer F(Non-INVITE trying,proceeding state timeout) triggered."); } OnTimedOut(); // User Disposed this transaction in TimedOut if(this.State == SIP_TransactionState.Disposed){ // Do nothing. } // Switch to terminated state. else{ SetState(SIP_TransactionState.Terminated); if(m_pTimerE != null){ m_pTimerE.Dispose(); m_pTimerE = null; } if(m_pTimerF != null){ m_pTimerF.Dispose(); m_pTimerF = null; } } } } }
/// <summary> /// Cleans up any resources being used. /// </summary> /// public void Dispose() { if (m_IsDisposed) { return; } m_IsDisposed = true; try { m_pTimer.Stop(); m_pSession.FolderChanged -= m_pSession_FolderChanged; m_pSession.m_pIDLE = null; m_pSession = null; m_pTimer.Dispose(); m_pTimer = null; } catch (Exception) { } }
/// <summary> /// Processes specified request through this transaction. /// </summary> /// <param name="flow">SIP data flow.</param> /// <param name="request">SIP request.</param> /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception> internal void ProcessRequest(SIP_Flow flow,SIP_Request request) { if(flow == null){ throw new ArgumentNullException("flow"); } if(request == null){ throw new ArgumentNullException("request"); } lock(this.SyncRoot){ if(this.State == SIP_TransactionState.Disposed){ return; } try{ // Log if(this.Stack.Logger != null){ byte[] requestData = request.ToByteData(); this.Stack.Logger.AddRead( Guid.NewGuid().ToString(), null, 0, "Request [transactionID='" + this.ID + "'; method='" + request.RequestLine.Method + "'; cseq='" + request.CSeq.SequenceNumber + "'; " + "transport='" + flow.Transport + "'; size='" + requestData.Length + "'; received '" + flow.LocalEP + "' <- '" + flow.RemoteEP + "'.", flow.LocalEP, flow.RemoteEP, requestData ); } #region INVITE if(this.Method == SIP_Methods.INVITE){ #region INVITE if(request.RequestLine.Method == SIP_Methods.INVITE){ if(this.State == SIP_TransactionState.Proceeding){ /* RFC 3261 17.2.1. If a request retransmission is received while in the "Proceeding" state, the most recent provisional response that was received from the TU MUST be passed to the transport layer for retransmission. */ SIP_Response response = this.LastProvisionalResponse; if(response != null){ this.Stack.TransportLayer.SendResponse(this,response); } } else if(this.State == SIP_TransactionState.Completed){ /* RFC 3261 17.2.1. While in the "Completed" state, if a request retransmission is received, the server SHOULD pass the response to the transport for retransmission. */ this.Stack.TransportLayer.SendResponse(this,this.FinalResponse); } } #endregion #region ACK else if(request.RequestLine.Method == SIP_Methods.ACK){ #region Accepeted if(this.State == SIP_TransactionState.Accpeted){ } #endregion #region Completed else if(this.State == SIP_TransactionState.Completed){ /* RFC 3261 17.2.1 If an ACK is received while the server transaction is in the "Completed" state, the server transaction MUST transition to the "Confirmed" state. As Timer G is ignored in this state, any retransmissions of the response will cease. When this state is entered, timer I is set to fire in T4 seconds for unreliable transports, and zero seconds for reliable transports. */ SetState(SIP_TransactionState.Confirmed); // Stop timers G,H if(m_pTimerG != null){ m_pTimerG.Dispose(); m_pTimerG = null; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer G(INVITE response(3xx - 6xx) retransmission) stopped."); } } if(m_pTimerH != null){ m_pTimerH.Dispose(); m_pTimerH = null; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer H(INVITE ACK wait) stopped."); } } // Start timer I. m_pTimerI = new TimerEx((flow.IsReliable ? 0 : SIP_TimerConstants.T4),false); m_pTimerI.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerI_Elapsed); // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer I(INVITE ACK retransission wait) started, will trigger after " + m_pTimerI.Interval + "."); } m_pTimerI.Enabled = true; } #endregion } #endregion } #endregion #region Non-INVITE else{ // Non-INVITE transaction may have only request retransmission requests. if(this.Method == request.RequestLine.Method){ if(this.State == SIP_TransactionState.Proceeding){ /* RFC 3261 17.2.2. If a retransmission of the request is received while in the "Proceeding" state, the most recently sent provisional response MUST be passed to the transport layer for retransmission. */ this.Stack.TransportLayer.SendResponse(this,this.LastProvisionalResponse); } else if(this.State == SIP_TransactionState.Completed){ /* RFC 3261 17.2.2. While in the "Completed" state, the server transaction MUST pass the final response to the transport layer for retransmission whenever a retransmission of the request is received. */ this.Stack.TransportLayer.SendResponse(this,this.FinalResponse); } } } #endregion } catch(SIP_TransportException x){ // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] transport exception: " + x.Message); } OnTransportError(x); } } }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { if(m_IsDisposed){ return; } m_IsDisposed = true; m_pStack = null; m_pTimer.Dispose(); m_pTimer = null; SetState(SIP_UA_RegistrationState.Disposed); OnDisposed(); this.Registered = null; this.Unregistered = null; this.Error = null; this.Disposed = null; }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { lock(m_pLock){ if(m_IsDisposed){ return; } OnDisposing(); m_IsDisposed = true; if(m_pTcpSession != null){ m_pTcpSession.Dispose(); m_pTcpSession = null; } m_pMessage = null; if(m_pKeepAliveTimer != null){ m_pKeepAliveTimer.Dispose(); m_pKeepAliveTimer = null; } } }
/// <summary> /// Sends specified response to remote party. /// </summary> /// <param name="response">SIP response to send.</param> /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception> /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception> public void SendResponse(SIP_Response response) { lock(this.SyncRoot){ if(this.State == SIP_TransactionState.Disposed){ throw new ObjectDisposedException(this.GetType().Name); } if(response == null){ throw new ArgumentNullException("response"); } try{ #region INVITE /* RFC 6026 7.1. INVITE server transaction. (Udpates RFC 3261) |INVITE |pass INV to TU INVITE V send 100 if TU won't in 200 ms send response+------------+ +--------| |--------+ 101-199 from TU | | | | send response +------->| |<-------+ | Proceeding | | |--------+ Transport Err. | | | Inform TU | |<-------+ +------------+ 300-699 from TU | |2xx from TU send response | |send response +--------------+ +------------+ | | INVITE V Timer G fires | send response +-----------+ send response | +--------| |--------+ | | | | | | +------->| Completed |<-------+ INVITE | Transport Err. | | - | Inform TU +--------| |----+ +-----+ | +---+ | +-----------+ | ACK | | v | v | ^ | | - | +------------+ | | | | | | |---+ ACK +----------+ | | +->| Accepted | | to TU Transport Err. | | | |<--+ Inform TU | V +------------+ | +-----------+ | ^ | | | | | | | | | Confirmed | | +-----+ | | | | 2xx from TU Timer H fires | +-----------+ | send response - | | | | | Timer I fires | | | - | Timer L fires | V | - | +------------+ | | | |<----+ +------->| Terminated | | | +------------+ */ if(this.Method == SIP_Methods.INVITE){ #region Proceeding if(this.State == SIP_TransactionState.Proceeding){ AddResponse(response); // 1xx if(response.StatusCodeType == SIP_StatusCodeType.Provisional){ this.Stack.TransportLayer.SendResponse(this,response); OnResponseSent(response); } // 2xx else if(response.StatusCodeType == SIP_StatusCodeType.Success){ this.Stack.TransportLayer.SendResponse(this,response); OnResponseSent(response); SetState(SIP_TransactionState.Accpeted); /* RFC 6025 7.1. When the "Accepted" state is entered, timer L MUST be set to fire in 64*T1. */ m_pTimerL = new TimerEx(64 * SIP_TimerConstants.T1); m_pTimerL.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerL_Elapsed); m_pTimerL.Enabled = true; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer L(ACK wait) started, will trigger after " + m_pTimerL.Interval + "."); } } // 3xx - 6xx else{ this.Stack.TransportLayer.SendResponse(this,response); OnResponseSent(response); SetState(SIP_TransactionState.Completed); /* RFC 3261 17.2.1. For unreliable transports, timer G is set to fire in T1 seconds, and is not set to fire for reliable transports. */ if(!this.Flow.IsReliable){ m_pTimerG = new TimerEx(SIP_TimerConstants.T1,false); m_pTimerG.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerG_Elapsed); m_pTimerG.Enabled = true; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer G(INVITE response(3xx - 6xx) retransmission) started, will trigger after " + m_pTimerG.Interval + "."); } } /* RFC 3261 17.2.1. When the "Completed" state is entered, timer H MUST be set to fire in 64*T1 seconds for all transports. */ m_pTimerH = new TimerEx(64 * SIP_TimerConstants.T1); m_pTimerH.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerH_Elapsed); m_pTimerH.Enabled = true; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer H(INVITE ACK wait) started, will trigger after " + m_pTimerH.Interval + "."); } } } #endregion #region Accepted else if(this.State == SIP_TransactionState.Accpeted){ this.Stack.TransportLayer.SendResponse(this,response); OnResponseSent(response); } #endregion #region Completed else if(this.State == SIP_TransactionState.Completed){ // We do nothing here, we just wait ACK to arrive. } #endregion #region Confirmed else if(this.State == SIP_TransactionState.Confirmed){ // We do nothing, just wait ACK retransmissions. } #endregion #region Terminated else if(this.State == SIP_TransactionState.Terminated){ // We should never rreach here, but if so, skip it. } #endregion } #endregion #region Non-INVITE /* RFC 3261 17.2.2. |Request received |pass to TU V +-----------+ | | | Trying |-------------+ | | | +-----------+ |200-699 from TU | |send response |1xx from TU | |send response | | | Request V 1xx from TU | send response+-----------+send response| +--------| |--------+ | | | Proceeding| | | +------->| |<-------+ | +<--------------| | | |Trnsprt Err +-----------+ | |Inform TU | | | | | | |200-699 from TU | | |send response | | Request V | | send response+-----------+ | | +--------| | | | | | Completed |<------------+ | +------->| | +<--------------| | |Trnsprt Err +-----------+ |Inform TU | | |Timer J fires | |- | | | V | +-----------+ | | | +-------------->| Terminated| | | +-----------+ */ else{ #region Trying if(this.State == SIP_TransactionState.Trying){ AddResponse(response); // 1xx if(response.StatusCodeType == SIP_StatusCodeType.Provisional){ this.Stack.TransportLayer.SendResponse(this,response); OnResponseSent(response); SetState(SIP_TransactionState.Proceeding); } // 2xx - 6xx else{ this.Stack.TransportLayer.SendResponse(this,response); OnResponseSent(response); SetState(SIP_TransactionState.Completed); /* RFC 3261 17.2.2. When the server transaction enters the "Completed" state, it MUST set Timer J to fire in 64*T1 seconds for unreliable transports, and zero seconds for reliable transports. */ m_pTimerJ = new TimerEx(64 * SIP_TimerConstants.T1,false); m_pTimerJ.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerJ_Elapsed); m_pTimerJ.Enabled = true; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer J(Non-INVITE request retransmission wait) started, will trigger after " + m_pTimerJ.Interval + "."); } } } #endregion #region Proceeding else if(this.State == SIP_TransactionState.Proceeding){ AddResponse(response); // 1xx if(response.StatusCodeType == SIP_StatusCodeType.Provisional){ this.Stack.TransportLayer.SendResponse(this,response); OnResponseSent(response); } // 2xx - 6xx else{ this.Stack.TransportLayer.SendResponse(this,response); OnResponseSent(response); SetState(SIP_TransactionState.Completed); /* RFC 3261 17.2.2. When the server transaction enters the "Completed" state, it MUST set Timer J to fire in 64*T1 seconds for unreliable transports, and zero seconds for reliable transports. */ m_pTimerJ = new TimerEx(64 * SIP_TimerConstants.T1,false); m_pTimerJ.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerJ_Elapsed); m_pTimerJ.Enabled = true; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer J(Non-INVITE request retransmission wait) started, will trigger after " + m_pTimerJ.Interval + "."); } } } #endregion #region Completed else if(this.State == SIP_TransactionState.Completed){ // Do nothing. } #endregion #region Terminated else if(this.State == SIP_TransactionState.Terminated){ // Do nothing. } #endregion } #endregion } catch(SIP_TransportException x){ // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] transport exception: " + x.Message); } OnTransportError(x); } } }
/// <summary> /// Starts transaction processing. /// </summary> /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception> /// <exception cref="InvalidOperationException">Is raised when <b>Start</b> is called other state than 'WaitingToStart'.</exception> public void Start() { lock(this.SyncRoot){ if(this.State == SIP_TransactionState.Disposed){ throw new ObjectDisposedException(this.GetType().Name); } else if(this.State != SIP_TransactionState.WaitingToStart){ throw new InvalidOperationException("Start method is valid only in 'WaitingToStart' state."); } // Move processing to thread pool. ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state){ lock(this.SyncRoot){ #region INVITE if(this.Method == SIP_Methods.INVITE){ /* RFC 3261 17.1.1.2. The initial state, "calling", MUST be entered when the TU initiates a new client transaction with an INVITE request. The client transaction MUST pass the request to the transport layer for transmission (see Section 18). If an unreliable transport is being used, the client transaction MUST start timer A with a value of T1. If a reliable transport is being used, the client transaction SHOULD NOT start timer A (Timer A controls request retransmissions). For any transport, the client transaction MUST start timer B with a value of 64*T1 seconds (Timer B controls transaction timeouts). */ SetState(SIP_TransactionState.Calling); try{ // Send initial request. this.Stack.TransportLayer.SendRequest(this.Flow,this.Request,this); } catch(Exception x){ OnTransportError(x); // NOTE: TransportError event handler could Dispose this transaction, so we need to check it. if(this.State != SIP_TransactionState.Disposed){ SetState(SIP_TransactionState.Terminated); } return; } // Start timer A for unreliable transports. if(!this.Flow.IsReliable){ m_pTimerA = new TimerEx(SIP_TimerConstants.T1,false); m_pTimerA.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerA_Elapsed); m_pTimerA.Enabled = true; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer A(INVITE request retransmission) started, will trigger after " + m_pTimerA.Interval + "."); } } // Start timer B. m_pTimerB = new TimerEx(64 * SIP_TimerConstants.T1,false); m_pTimerB.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerB_Elapsed); m_pTimerB.Enabled = true; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer B(INVITE calling state timeout) started, will trigger after " + m_pTimerB.Interval + "."); } } #endregion #region Non-INVITE else{ /* RFC 3261 17.1.2.2. The "Trying" state is entered when the TU initiates a new client transaction with a request. When entering this state, the client transaction SHOULD set timer F to fire in 64*T1 seconds. The request MUST be passed to the transport layer for transmission. If an unreliable transport is in use, the client transaction MUST set timer E to fire in T1 seconds. */ SetState(SIP_TransactionState.Trying); // Start timer F. m_pTimerF = new TimerEx(64 * SIP_TimerConstants.T1,false); m_pTimerF.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerF_Elapsed); m_pTimerF.Enabled = true; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer F(Non-INVITE trying,proceeding state timeout) started, will trigger after " + m_pTimerF.Interval + "."); } try{ // Send initial request. this.Stack.TransportLayer.SendRequest(this.Flow,this.Request,this); } catch(Exception x){ OnTransportError(x); // NOTE: TransportError event handler could Dispose this transaction, so we need to check it. if(this.State != SIP_TransactionState.Disposed){ SetState(SIP_TransactionState.Terminated); } return; } // Start timer E for unreliable transports. if(!this.Flow.IsReliable){ m_pTimerE = new TimerEx(SIP_TimerConstants.T1,false); m_pTimerE.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerE_Elapsed); m_pTimerE.Enabled = true; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer E(Non-INVITE request retransmission) started, will trigger after " + m_pTimerE.Interval + "."); } } } #endregion } })); } }
/// <summary> /// Processes specified response through this transaction. /// </summary> /// <param name="flow">SIP data flow what received response.</param> /// <param name="response">SIP response to process.</param> /// <exception cref="ArgumentNullException">Is raised when <b>flow</b>,<b>response</b> is null reference.</exception> internal void ProcessResponse(SIP_Flow flow,SIP_Response response) { if(flow == null){ throw new ArgumentNullException("flow"); } if(response == null){ throw new ArgumentNullException("response"); } lock(this.SyncRoot){ if(this.State == SIP_TransactionState.Disposed){ return; } /* RFC 3261 9.1. CANCEL. *) If provisional response, send CANCEL, we should get '478 Request terminated'. *) If final response, skip canceling, nothing to cancel. */ else if(m_IsCanceling && response.StatusCodeType == SIP_StatusCodeType.Provisional){ SendCancel(); return; } // Log if(this.Stack.Logger != null){ byte[] responseData = response.ToByteData(); this.Stack.Logger.AddRead( Guid.NewGuid().ToString(), null, 0, "Response [transactionID='" + this.ID + "'; method='" + response.CSeq.RequestMethod + "'; cseq='" + response.CSeq.SequenceNumber + "'; " + "transport='" + flow.Transport + "'; size='" + responseData.Length + "'; statusCode='" + response.StatusCode + "'; " + "reason='" + response.ReasonPhrase + "'; received '" + flow.LocalEP + "' <- '" + flow.RemoteEP + "'.", flow.LocalEP, flow.RemoteEP, responseData ); } #region INVITE /* RFC 6026 7.2. INVITE client transaction. (Udpates RFC 3261) +-----------+ +-----------+ | | | | | Calling | | Calling | | |----------->+ | |-----------+ +-----------+ 2xx | +-----------+ 2xx | 2xx to TU | 2xx to TU | | | | | | | | | +-----------+ | +-----------+ | | | | | | | |Proceeding |----------->| |Proceeding |---------->| | | 2xx | | | 2xx | +-----------+ 2xx to TU | +-----------+ 2xx to TU | | | | | | | | V | +-----------+ | | | | | Accepted | | +---| | | 2xx | +-----------+ | 2xx to TU | ^ | | | | | | +-----+ | | | | +-----------------+ | | Timer M fires | | - | V +-----------+ | +-----------+ | | | | | | Terminated|<-----------+ | Terminated| | | | | +-----------+ +-----------+ */ if(this.Method == SIP_Methods.INVITE){ #region Calling if(this.State == SIP_TransactionState.Calling){ // Store response. AddResponse(response); // Stop timer A,B if(m_pTimerA != null){ m_pTimerA.Dispose(); m_pTimerA = null; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer A(INVITE request retransmission) stopped."); } } if(m_pTimerB != null){ m_pTimerB.Dispose(); m_pTimerB = null; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer B(INVITE calling state timeout) stopped."); } } // 1xx response. if(response.StatusCodeType == SIP_StatusCodeType.Provisional){ OnResponseReceived(response); SetState(SIP_TransactionState.Proceeding); } // 2xx response. else if(response.StatusCodeType == SIP_StatusCodeType.Success){ OnResponseReceived(response); SetState(SIP_TransactionState.Accpeted); /* RFC 6025 7.1. When the "Accepted" state is entered, timer L MUST be set to fire in 64*T1. */ m_pTimerM = new TimerEx(64 * SIP_TimerConstants.T1); m_pTimerM.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerM_Elapsed); m_pTimerM.Enabled = true; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer M(2xx retransmission wait) started, will trigger after " + m_pTimerM.Interval + "."); } } // 3xx - 6xx response. else{ SendAck(response); OnResponseReceived(response); SetState(SIP_TransactionState.Completed); /* RFC 3261 17.1.1.2. The client transaction SHOULD start timer D when it enters the "Completed" state, with a value of at least 32 seconds for unreliable transports, and a value of zero seconds for reliable transports. */ m_pTimerD = new TimerEx(this.Flow.IsReliable ? 0 : 32000,false); m_pTimerD.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerD_Elapsed); // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer D(INVITE 3xx - 6xx response retransmission wait) started, will trigger after " + m_pTimerD.Interval + "."); } m_pTimerD.Enabled = true; } } #endregion #region Proceeding else if(this.State == SIP_TransactionState.Proceeding){ // Store response. AddResponse(response); // 1xx response. if(response.StatusCodeType == SIP_StatusCodeType.Provisional){ OnResponseReceived(response); } // 2xx response. else if(response.StatusCodeType == SIP_StatusCodeType.Success){ OnResponseReceived(response); SetState(SIP_TransactionState.Accpeted); /* RFC 6025 7.1. When the "Accepted" state is entered, timer L MUST be set to fire in 64*T1. */ m_pTimerM = new TimerEx(64 * SIP_TimerConstants.T1); m_pTimerM.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerM_Elapsed); m_pTimerM.Enabled = true; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer M(2xx retransmission wait) started, will trigger after " + m_pTimerM.Interval + "."); } } // 3xx - 6xx response. else{ SendAck(response); OnResponseReceived(response); SetState(SIP_TransactionState.Completed); /* RFC 3261 17.1.1.2. The client transaction SHOULD start timer D when it enters the "Completed" state, with a value of at least 32 seconds for unreliable transports, and a value of zero seconds for reliable transports. */ m_pTimerD = new TimerEx(this.Flow.IsReliable ? 0 : 32000,false); m_pTimerD.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerD_Elapsed); // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer D(INVITE 3xx - 6xx response retransmission wait) started, will trigger after " + m_pTimerD.Interval + "."); } m_pTimerD.Enabled = true; } } #endregion #region Accepted else if(this.State == SIP_TransactionState.Accpeted){ if(response.StatusCodeType == SIP_StatusCodeType.Success){ OnResponseReceived(response); } } #endregion #region Completed else if(this.State == SIP_TransactionState.Completed){ // 3xx - 6xx if(response.StatusCode >= 300){ SendAck(response); } } #endregion #region Terminated else if(this.State == SIP_TransactionState.Terminated){ // We should never reach here, but if so, do nothing. } #endregion } #endregion #region Non-INVITE /* RFC 3251 17.1.2.2 |Request from TU |send request Timer E V send request +-----------+ +---------| |-------------------+ | | Trying | Timer F | +-------->| | or Transport Err.| +-----------+ inform TU | 200-699 | | | resp. to TU | |1xx | +---------------+ |resp. to TU | | | | | Timer E V Timer F | | send req +-----------+ or Transport Err. | | +---------| | inform TU | | | |Proceeding |------------------>| | +-------->| |-----+ | | +-----------+ |1xx | | | ^ |resp to TU | | 200-699 | +--------+ | | resp. to TU | | | | | | V | | +-----------+ | | | | | | | Completed | | | | | | | +-----------+ | | ^ | | | | | Timer K | +--------------+ | - | | | V | NOTE: +-----------+ | | | | transitions | Terminated|<------------------+ labeled with | | the event +-----------+ over the action to take */ else{ #region Trying if(this.State == SIP_TransactionState.Trying){ // Store response. AddResponse(response); // Stop timer E if(m_pTimerE != null){ m_pTimerE.Dispose(); m_pTimerE = null; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer E(Non-INVITE request retransmission) stopped."); } } // 1xx response. if(response.StatusCodeType == SIP_StatusCodeType.Provisional){ OnResponseReceived(response); SetState(SIP_TransactionState.Proceeding); } // 2xx - 6xx response. else{ // Stop timer F if(m_pTimerF != null){ m_pTimerF.Dispose(); m_pTimerF = null; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer F(Non-INVITE trying,proceeding state timeout) stopped."); } } OnResponseReceived(response); SetState(SIP_TransactionState.Completed); /* RFC 3261 17.1.2.2. The client transaction enters the "Completed" state, it MUST set Timer K to fire in T4 seconds for unreliable transports, and zero seconds for reliable transports. */ m_pTimerK = new TimerEx(this.Flow.IsReliable ? 1 : SIP_TimerConstants.T4,false); m_pTimerK.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerK_Elapsed); // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer K(Non-INVITE 3xx - 6xx response retransmission wait) started, will trigger after " + m_pTimerK.Interval + "."); } m_pTimerK.Enabled = true; } } #endregion #region Proceeding else if(this.State == SIP_TransactionState.Proceeding){ // Store response. AddResponse(response); // 1xx response. if(response.StatusCodeType == SIP_StatusCodeType.Provisional){ OnResponseReceived(response); } // 2xx - 6xx response. else{ // Stop timer F if(m_pTimerF != null){ m_pTimerF.Dispose(); m_pTimerF = null; // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer F(Non-INVITE trying,proceeding state timeout) stopped."); } } OnResponseReceived(response); SetState(SIP_TransactionState.Completed); /* RFC 3261 17.1.2.2. The client transaction enters the "Completed" state, it MUST set Timer K to fire in T4 seconds for unreliable transports, and zero seconds for reliable transports. */ m_pTimerK = new TimerEx(this.Flow.IsReliable ? 0 : SIP_TimerConstants.T4,false); m_pTimerK.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerK_Elapsed); // Log if(this.Stack.Logger != null){ this.Stack.Logger.AddText(this.ID,"Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=false] timer K(Non-INVITE 3xx - 6xx response retransmission wait) started, will trigger after " + m_pTimerK.Interval + "."); } m_pTimerK.Enabled = true; } } #endregion #region Completed else if(this.State == SIP_TransactionState.Completed){ // Eat retransmited response. } #endregion #region Terminated else if(this.State == SIP_TransactionState.Terminated){ // We should never reach here, but if so, do nothing. } #endregion } #endregion } }
/// <summary> /// Is raised when INVITE 100 (Trying) response must be sent if no response sent by transaction user. /// </summary> /// <param name="sender">Sender.</param> /// <param name="e">Event data.</param> private void m_pTimer100_Elapsed(object sender,System.Timers.ElapsedEventArgs e) { lock(this.SyncRoot){ // RFC 3261 17.2.1. TU didn't generate response in 200 ms, send '100 Trying' to stop request retransmission. if(this.State == SIP_TransactionState.Proceeding && this.Responses.Length == 0){ /* RFC 3261 17.2.1. The 100 (Trying) response is constructed according to the procedures in Section 8.2.6, except that the insertion of tags in the To header field of the response (when none was present in the request) is downgraded from MAY to SHOULD NOT. * RFC 3261 8.2.6. When a 100 (Trying) response is generated, any Timestamp header field present in the request MUST be copied into this 100 (Trying) response. If there is a delay in generating the response, the UAS SHOULD add a delay value into the Timestamp value in the response. This value MUST contain the difference between the time of sending of the response and receipt of the request, measured in seconds. */ SIP_Response tryingResponse = this.Stack.CreateResponse(SIP_ResponseCodes.x100_Trying,this.Request); if(this.Request.Timestamp != null){ tryingResponse.Timestamp = new SIP_t_Timestamp(this.Request.Timestamp.Time,(DateTime.Now - this.CreateTime).Seconds); } try{ this.Stack.TransportLayer.SendResponse(this,tryingResponse); } catch(Exception x){ OnTransportError(x); SetState(SIP_TransactionState.Terminated); return; } } if(m_pTimer100 != null){ m_pTimer100.Dispose(); m_pTimer100 = null; } } }
/// <summary> /// Default constructor. /// </summary> public TCP_Client() { m_pTimer_IdleTimeout = new TimerEx(30000, true); m_pTimer_IdleTimeout.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimer_IdleTimeout_Elapsed); }
/// <summary> /// Default constructor. /// </summary> /// <param name="session">Owner RTP multimedia session.</param> /// <param name="localEP">Local RTP end point.</param> /// <param name="clock">RTP media clock.</param> /// <exception cref="ArgumentNullException">Is raised when <b>localEP</b>, <b>localEP</b> or <b>clock</b> is null reference.</exception> internal RTP_Session(RTP_MultimediaSession session, RTP_Address localEP, RTP_Clock clock) { if (session == null) { throw new ArgumentNullException("session"); } if (localEP == null) { throw new ArgumentNullException("localEP"); } if (clock == null) { throw new ArgumentNullException("clock"); } m_pSession = session; m_pLocalEP = localEP; m_pRtpClock = clock; m_pRtpReceiveBuffer = new byte[Workaround.Definitions.MaxStreamLineLength]; m_pRtcpReceiveBuffer = new byte[Workaround.Definitions.MaxStreamLineLength]; m_pLocalSources = new List<RTP_Source_Local>(); m_pTargets = new List<RTP_Address>(); m_pMembers = new Dictionary<uint, RTP_Source>(); m_pSenders = new Dictionary<uint, RTP_Source>(); m_pConflictingEPs = new Dictionary<string, DateTime>(); m_pRtpSocket = new Socket(localEP.IP.AddressFamily, SocketType.Dgram, ProtocolType.Udp); m_pRtpSocket.Bind(localEP.RtpEP); m_pRtcpSocket = new Socket(localEP.IP.AddressFamily, SocketType.Dgram, ProtocolType.Udp); m_pRtcpSocket.Bind(localEP.RtcpEP); m_pRtcpTimer = new TimerEx(); m_pRtcpTimer.Elapsed += delegate { SendRtcp(); }; m_pRtcpTimer.AutoReset = false; }
/// <summary> /// Starts data connection processing. /// </summary> /// <exception cref="ObjectDisposedException">Is raised when this is disposed and this method is accessed.</exception> public void Start() { if(m_IsDisposed){ throw new ObjectDisposedException(this.GetType().Name); } // Passive mode, start waiting client connection. if(m_pSession.PassiveMode){ WriteLine("150 Waiting data connection on port '" + ((IPEndPoint)m_pSession.m_pPassiveSocket.LocalEndPoint).Port + "'."); // Start connection wait timeout timer. TimerEx timer = new TimerEx(10000,false); timer.Elapsed += delegate(object sender,System.Timers.ElapsedEventArgs e){ WriteLine("550 Data connection wait timeout."); Dispose(); }; timer.Enabled = true; m_pSession.m_pPassiveSocket.BeginAccept( delegate(IAsyncResult ar){ try{ timer.Dispose(); m_pSocket = m_pSession.m_pPassiveSocket.EndAccept(ar); // Log m_pSession.LogAddText("Data connection opened."); StartDataTransfer(); } catch{ WriteLine("425 Opening data connection failed."); Dispose(); } }, null ); } // Active mode, connect to client data port. else{ WriteLine("150 Opening data connection to '" + m_pSession.m_pDataConEndPoint.ToString() + "'."); m_pSocket = new Socket(m_pSession.LocalEndPoint.AddressFamily,SocketType.Stream,ProtocolType.Tcp); m_pSocket.BeginConnect( m_pSession.m_pDataConEndPoint, delegate(IAsyncResult ar){ try{ m_pSocket.EndConnect(ar); // Log m_pSession.LogAddText("Data connection opened."); StartDataTransfer(); } catch{ WriteLine("425 Opening data connection to '" + m_pSession.m_pDataConEndPoint.ToString() + "' failed."); Dispose(); } }, null ); } }
/// <summary> /// Default constructor. /// </summary> /// <param name="dialog">Owner INVITE dialog.</param> /// <param name="response">INVITE 2xx response.</param> /// <exception cref="ArgumentNullException">Is raised when <b>dialog</b> or <b>response</b> is null reference.</exception> public UasInvite2xxRetransmit(SIP_Dialog_Invite dialog, SIP_Response response) { if (dialog == null) { throw new ArgumentNullException("dialog"); } if (response == null) { throw new ArgumentNullException("response"); } m_pDialog = dialog; m_pResponse = response; /* RFC 3261 13.3.1.4. Once the response has been constructed, it is passed to the INVITE server transaction. Note, however, that the INVITE server transaction will be destroyed as soon as it receives this final response and passes it to the transport. Therefore, it is necessary to periodically pass the response directly to the transport until the ACK arrives. The 2xx response is passed to the transport with an interval that starts at T1 seconds and doubles for each retransmission until it reaches T2 seconds (T1 and T2 are defined in Section 17). Response retransmissions cease when an ACK request for the response is received. This is independent of whatever transport protocols are used to send the response. Since 2xx is retransmitted end-to-end, there may be hops between UAS and UAC that are UDP. To ensure reliable delivery across these hops, the response is retransmitted periodically even if the transport at the UAS is reliable. */ m_pTimer = new TimerEx(SIP_TimerConstants.T1, false); m_pTimer.Elapsed += m_pTimer_Elapsed; m_pTimer.Enabled = true; }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { if(m_IsDisposed){ return; } m_IsDisposed = true; foreach(UDP_DataReceiver receiver in m_pUdpDataReceivers){ receiver.Dispose(); } m_pUdpDataReceivers = null; if(m_pRtcpTimer != null){ m_pRtcpTimer.Dispose(); m_pRtcpTimer = null; } m_pSession = null; m_pLocalEP = null; m_pTargets = null; foreach(RTP_Source_Local source in m_pLocalSources.ToArray()){ source.Dispose(); } m_pLocalSources = null; m_pRtcpSource = null; foreach(RTP_Source source in m_pMembers.Values){ source.Dispose(); } m_pMembers = null; m_pSenders = null; m_pConflictingEPs = null; m_pRtpSocket.Close(); m_pRtpSocket = null; m_pRtcpSocket.Close(); m_pRtcpSocket = null; m_pUdpDataReceivers = null; OnDisposed(); this.Disposed = null; this.Closed = null; this.NewSendStream = null; this.NewReceiveStream = null; }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { lock (m_pLock) { if (m_IsDisposed) { return; } m_IsDisposed = true; m_pDialog.m_pUacInvite2xxRetransmitWaits.Remove(this); m_pDialog = null; m_pInvite = null; if (m_pTimer != null) { m_pTimer.Dispose(); m_pTimer = null; } } }
/// <summary> /// Default constructor. /// </summary> /// <param name="session">Owner RTP multimedia session.</param> /// <param name="localEP">Local RTP end point.</param> /// <param name="clock">RTP media clock.</param> /// <exception cref="ArgumentNullException">Is raised when <b>localEP</b>, <b>localEP</b> or <b>clock</b> is null reference.</exception> internal RTP_Session(RTP_MultimediaSession session,RTP_Address localEP,RTP_Clock clock) { if(session == null){ throw new ArgumentNullException("session"); } if(localEP == null){ throw new ArgumentNullException("localEP"); } if(clock == null){ throw new ArgumentNullException("clock"); } m_pSession = session; m_pLocalEP = localEP; m_pRtpClock = clock; m_pLocalSources = new List<RTP_Source_Local>(); m_pTargets = new List<RTP_Address>(); m_pMembers = new Dictionary<uint,RTP_Source>(); m_pSenders = new Dictionary<uint,RTP_Source>(); m_pConflictingEPs = new Dictionary<string,DateTime>(); m_pPayloads = new KeyValueCollection<int,Codec>(); m_pUdpDataReceivers = new List<UDP_DataReceiver>(); m_pRtpSocket = new Socket(localEP.IP.AddressFamily,SocketType.Dgram,ProtocolType.Udp); m_pRtpSocket.Bind(localEP.RtpEP); m_pRtcpSocket = new Socket(localEP.IP.AddressFamily,SocketType.Dgram,ProtocolType.Udp); m_pRtcpSocket.Bind(localEP.RtcpEP); m_pRtcpTimer = new TimerEx(); m_pRtcpTimer.Elapsed += new System.Timers.ElapsedEventHandler(delegate(object sender,System.Timers.ElapsedEventArgs e){ SendRtcp(); }); m_pRtcpTimer.AutoReset = false; }
/// <summary> /// Cleans up any resources being used. /// </summary> internal void Dispose() { m_pCache = null; m_pTimerTimeout.Dispose(); m_pTimerTimeout = null; }
/// <summary> /// Starts transaction processing. /// </summary> private void Start() { #region INVITE if(this.Method == SIP_Methods.INVITE){ /* RFC 3261 17.2.1. When a server transaction is constructed for a request, it enters the "Proceeding" state. The server transaction MUST generate a 100 (Trying) response unless it knows that the TU will generate a provisional or final response within 200 ms, in which case it MAY generate a 100 (Trying) response. */ SetState(SIP_TransactionState.Proceeding); m_pTimer100 = new TimerEx(200,false); m_pTimer100.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimer100_Elapsed); m_pTimer100.Enabled = true; } #endregion #region Non-INVITE else{ // RFC 3261 17.2.2. The state machine is initialized in the "Trying" state. SetState(SIP_TransactionState.Trying); } #endregion }