internal const Int64 SHUTDOWN_TIMEOUT = 2000; /* miliseconds. */ internal TSIP_Dialog(tsip_dialog_type_t type, String callId, TSip_Session session) { mId = sUniqueId++; mRecordRoutes = new List <TSIP_HeaderRecordRoute>(); mChallenges = new List <TSIP_Challenge>(); mPaths = new List <TSIP_Uri>(); mServiceRoutes = new List <TSIP_Uri>(); mAssociatedUris = new List <TSIP_Uri>(); mState = tsip_dialog_state_t.Initial; mType = type; mCallId = String.IsNullOrEmpty(callId) ? TSIP_HeaderCallId.RandomCallId() : callId; mSipSession = session; /* Sets some default values */ mExpires = TSip_Session.DEFAULT_EXPIRES; mTagLocal = TSK_String.Random(); mCSeqValue = (UInt32) new Random().Next(); /*=== SIP Session ===*/ if (mSipSession != null) { mExpires = mSipSession.Expires; mUriLocal = !String.IsNullOrEmpty(callId) /* Server Side */ ? mSipSession.UriTo : mSipSession.UriFrom; if (mSipSession.UriTo != null) { mUriRemote = mSipSession.UriTo; mUriRemoteTarget = mSipSession.UriTo; } else { mUriRemote = mSipSession.UriFrom; mUriRemoteTarget = mSipSession.Stack.Realm; } } else { TSK_Debug.Error("Invalid Sip Session"); } }
/// <summary> /// Updates the dialog state: /// - Authorizations (using challenges from the @a response message) /// - State (early, established, disconnected, ...) /// - Routes (and Service-Route) /// - Target (remote) /// - ... /// </summary> /// <param name="response"></param> /// <returns></returns> protected Boolean UpdateWithResponse(TSIP_Response response) { if (response == null || response.To == null || response.CSeq == null) { return(false); } String tag = response.To.Tag; /* * 1xx (!100) or 2xx */ /* * 401 or 407 or 421 or 494 */ if (response.StatusCode == 401 || response.StatusCode == 407 || response.StatusCode == 421 || response.StatusCode == 494) { Boolean acceptNewVector; /* 3GPP IMS - Each authentication vector is used only once. * ==> Re-registration/De-registration ==> Allow 401/407 challenge. */ acceptNewVector = (response.CSeq.RequestType == TSIP_Message.tsip_request_type_t.REGISTER && this.State == tsip_dialog_state_t.Established); return(this.UpdateChallenges(response, acceptNewVector)); } else if (100 < response.StatusCode && response.StatusCode < 300) { tsip_dialog_state_t state = this.State; /* 1xx */ if (response.StatusCode <= 199) { if (String.IsNullOrEmpty(response.To.Tag)) { TSK_Debug.Error("Invalid tag parameter"); return(false); } state = tsip_dialog_state_t.Early; } /* 2xx */ else { state = tsip_dialog_state_t.Established; } /* Remote target */ { /* RFC 3261 12.2.1.2 Processing the Responses * When a UAC receives a 2xx response to a target refresh request, it * MUST replace the dialog's remote target URI with the URI from the * Contact header field in that response, if present. * * FIXME: Because PRACK/UPDATE sent before the session is established MUST have * the rigth target URI to be delivered to the UAS ==> Do not not check that we are connected */ if (response.CSeq.RequestType != TSIP_Message.tsip_request_type_t.REGISTER && response.Contact != null && response.Contact.Uri != null) { mUriRemoteTarget = response.Contact.Uri.Clone(true, false); } } /* Route sets */ { int index; TSIP_HeaderRecordRoute recordRoute; mRecordRoutes.Clear(); for (index = 0; (recordRoute = response.GetHeaderAtIndex(TSIP_Header.tsip_header_type_t.Record_Route, index) as TSIP_HeaderRecordRoute) != null; index++) { mRecordRoutes.Insert(0, recordRoute); /* Copy reversed. */ } } /* cseq + tags + ... */ if (this.State == tsip_dialog_state_t.Established && String.Equals(mTagRemote, tag, StringComparison.InvariantCultureIgnoreCase)) { return(true); } else { if (response.CSeq.RequestType != TSIP_Message.tsip_request_type_t.REGISTER && response.CSeq.RequestType != TSIP_Message.tsip_request_type_t.PUBLISH) { /* REGISTER and PUBLISH don't establish dialog */ mTagRemote = tag; } #if NEVER_EXECUTE_00 // PRACK and BYE will have same CSeq value ==> Let CSeq value to be incremented by "tsip_dialog_request_new()" self->cseq_value = response->CSeq ? response->CSeq->seq : self->cseq_value; #endif } this.State = state; return(true); } return(true); }