/// <summary>
        /// Starts registering.
        /// </summary>
        /// <param name="autoRefresh">If true, registration takes care of refreshing itself to registrar server.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        public void BeginRegister(bool autoRefresh)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }

            // Fix ME: Stack not running, try register on next step.
            // In ideal solution we need to start registering when stack starts.
            if (!m_pStack.IsRunning)
            {
                m_pTimer.Enabled = true;
                return;
            }

            m_AutoRefresh = autoRefresh;
            SetState(SIP_UA_RegistrationState.Registering);

            /* RFC 3261 10.1 Constructing the REGISTER Request.
             *  Request-URI: The Request-URI names the domain of the location service for which the registration is meant (for example,
             *               "sip:chicago.com").  The "userinfo" and "@" components of the SIP URI MUST NOT be present.
             */

            SIP_Request register = m_pStack.CreateRequest(SIP_Methods.REGISTER, new SIP_t_NameAddress(m_pServer.Scheme + ":" + m_AOR), new SIP_t_NameAddress(m_pServer.Scheme + ":" + m_AOR));

            register.RequestLine.Uri = SIP_Uri.Parse(m_pServer.Scheme + ":" + m_AOR.Substring(m_AOR.IndexOf('@') + 1));
            register.Route.Add(m_pServer.ToString());
            register.Contact.Add("<" + this.Contact + ">;expires=" + m_RefreshInterval);

            m_pRegisterSender = m_pStack.CreateRequestSender(register, m_pFlow);
            m_pRegisterSender.ResponseReceived += new EventHandler <SIP_ResponseReceivedEventArgs>(m_pRegisterSender_ResponseReceived);
            m_pRegisterSender.Start();
        }
        /// <summary>
        /// Re-invites remote party.
        /// </summary>
        /// <param name="contact">New contact value. Value null means current contact value used.</param>
        /// <param name="sdp">SDP media offer.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when there is pending invite and this method is called or dialog is in invalid state.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>sdp</b> is null reference.</exception>
        public void ReInvite(SIP_Uri contact, SDP_Message sdp)
        {
            if (State == SIP_DialogState.Disposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (HasPendingInvite)
            {
                throw new InvalidOperationException("There is pending INVITE.");
            }
            if (State != SIP_DialogState.Confirmed)
            {
                throw new InvalidOperationException("ReInvite is only available in Confirmed state.");
            }
            if (sdp == null)
            {
                throw new ArgumentNullException("sdp");
            }

            lock (SyncRoot)
            {
                // TODO:

                SIP_Request reinvite = CreateRequest(SIP_Methods.INVITE);
                if (contact != null)
                {
                    reinvite.Contact.RemoveAll();
                    reinvite.Contact.Add(contact.ToString());
                }
                reinvite.ContentType = "application/sdp";
                // reinvite.Data = sdp.ToStringData();

                // TODO: Create request sender
                // TODO: Try to reuse existing data flow
                //SIP_RequestSender sender = this.Stack.CreateRequestSender(reinvite);
                //sender.Start();
            }
        }
예제 #3
0
        /// <summary>
        /// Re-invites remote party.
        /// </summary>
        /// <param name="contact">New contact value. Value null means current contact value used.</param>
        /// <param name="sdp">SDP media offer.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when there is pending invite and this method is called or dialog is in invalid state.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>sdp</b> is null reference.</exception>
        public void ReInvite(SIP_Uri contact, SDP_Message sdp)
        {
            if (State == SIP_DialogState.Disposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (HasPendingInvite)
            {
                throw new InvalidOperationException("There is pending INVITE.");
            }
            if (State != SIP_DialogState.Confirmed)
            {
                throw new InvalidOperationException("ReInvite is only available in Confirmed state.");
            }
            if (sdp == null)
            {
                throw new ArgumentNullException("sdp");
            }

            lock (SyncRoot)
            {
                // TODO:

                SIP_Request reinvite = CreateRequest(SIP_Methods.INVITE);
                if (contact != null)
                {
                    reinvite.Contact.RemoveAll();
                    reinvite.Contact.Add(contact.ToString());
                }
                reinvite.ContentType = "application/sdp";
                // reinvite.Data = sdp.ToStringData();

                // TODO: Create request sender
                // TODO: Try to reuse existing data flow
                //SIP_RequestSender sender = this.Stack.CreateRequestSender(reinvite);
                //sender.Start();
            }
        }
예제 #4
0
        /// <summary>
        /// Creates new SIP request using this dialog info.
        /// </summary>
        /// <param name="method">SIP method.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>method</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <returns>Returns created request.</returns>
        public SIP_Request CreateRequest(string method)
        {
            if (State == SIP_DialogState.Disposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }
            if (method == string.Empty)
            {
                throw new ArgumentException("Argument 'method' value must be specified.");
            }

            /* RFC 3261 12.2.1.1.
             *  A request within a dialog is constructed by using many of the
             *  components of the state stored as part of the dialog.
             *
             *  The URI in the To field of the request MUST be set to the remote URI
             *  from the dialog state.  The tag in the To header field of the request
             *  MUST be set to the remote tag of the dialog ID.  The From URI of the
             *  request MUST be set to the local URI from the dialog state.  The tag
             *  in the From header field of the request MUST be set to the local tag
             *  of the dialog ID.  If the value of the remote or local tags is null,
             *  the tag parameter MUST be omitted from the To or From header fields,
             *  respectively.
             *
             *  The Call-ID of the request MUST be set to the Call-ID of the dialog.
             *  Requests within a dialog MUST contain strictly monotonically
             *  increasing and contiguous CSeq sequence numbers (increasing-by-one)
             *  in each direction (excepting ACK and CANCEL of course, whose numbers
             *  equal the requests being acknowledged or cancelled).  Therefore, if
             *  the local sequence number is not empty, the value of the local
             *  sequence number MUST be incremented by one, and this value MUST be
             *  placed into the CSeq header field.  If the local sequence number is
             *  empty, an initial value MUST be chosen using the guidelines of
             *  Section 8.1.1.5.  The method field in the CSeq header field value
             *  MUST match the method of the request.
             *
             *      With a length of 32 bits, a client could generate, within a single
             *      call, one request a second for about 136 years before needing to
             *      wrap around.  The initial value of the sequence number is chosen
             *      so that subsequent requests within the same call will not wrap
             *      around.  A non-zero initial value allows clients to use a time-
             *      based initial sequence number.  A client could, for example,
             *      choose the 31 most significant bits of a 32-bit second clock as an
             *      initial sequence number.
             *
             *  The UAC uses the remote target and route set to build the Request-URI
             *  and Route header field of the request.
             *
             *  If the route set is empty, the UAC MUST place the remote target URI
             *  into the Request-URI.  The UAC MUST NOT add a Route header field to
             *  the request.
             *
             *  If the route set is not empty, and the first URI in the route set
             *  contains the lr parameter (see Section 19.1.1), the UAC MUST place
             *  the remote target URI into the Request-URI and MUST include a Route
             *  header field containing the route set values in order, including all
             *  parameters.
             *
             *  If the route set is not empty, and its first URI does not contain the
             *  lr parameter, the UAC MUST place the first URI from the route set
             *  into the Request-URI, stripping any parameters that are not allowed
             *  in a Request-URI.  The UAC MUST add a Route header field containing
             *  the remainder of the route set values in order, including all
             *  parameters.  The UAC MUST then place the remote target URI into the
             *  Route header field as the last value.
             *
             *  For example, if the remote target is sip:user@remoteua and the route
             *  set contains:
             *      <sip:proxy1>,<sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4>
             *
             *  The request will be formed with the following Request-URI and Route
             *  header field:
             *      METHOD sip:proxy1
             *      Route: <sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4>,<sip:user@remoteua>
             *
             *  If the first URI of the route set does not contain the lr
             *  parameter, the proxy indicated does not understand the routing
             *  mechanisms described in this document and will act as specified in
             *  RFC 2543, replacing the Request-URI with the first Route header
             *  field value it receives while forwarding the message.  Placing the
             *  Request-URI at the end of the Route header field preserves the
             *  information in that Request-URI across the strict router (it will
             *  be returned to the Request-URI when the request reaches a loose-
             *  router).
             *
             *  A UAC SHOULD include a Contact header field in any target refresh
             *  requests within a dialog, and unless there is a need to change it,
             *  the URI SHOULD be the same as used in previous requests within the
             *  dialog.  If the "secure" flag is true, that URI MUST be a SIPS URI.
             *  As discussed in Section 12.2.2, a Contact header field in a target
             *  refresh request updates the remote target URI.  This allows a UA to
             *  provide a new contact address, should its address change during the
             *  duration of the dialog.
             *
             *  However, requests that are not target refresh requests do not affect
             *  the remote target URI for the dialog.
             *
             *  The rest of the request is formed as described in Section 8.1.1.
             */

            lock (m_pLock)
            {
                SIP_Request request = m_pStack.CreateRequest(method,
                                                             new SIP_t_NameAddress("", m_pRemoteUri),
                                                             new SIP_t_NameAddress("", m_pLocalUri));
                if (m_pRouteSet.Length == 0)
                {
                    request.RequestLine.Uri = m_pRemoteTarget;
                }
                else
                {
                    SIP_Uri topmostRoute = ((SIP_Uri)m_pRouteSet[0].Address.Uri);
                    if (topmostRoute.Param_Lr)
                    {
                        request.RequestLine.Uri = m_pRemoteTarget;
                        for (int i = 0; i < m_pRouteSet.Length; i++)
                        {
                            request.Route.Add(m_pRouteSet[i].ToStringValue());
                        }
                    }
                    else
                    {
                        request.RequestLine.Uri = SIP_Utils.UriToRequestUri(topmostRoute);
                        for (int i = 1; i < m_pRouteSet.Length; i++)
                        {
                            request.Route.Add(m_pRouteSet[i].ToStringValue());
                        }
                    }
                }
                request.To.Tag              = m_RemoteTag;
                request.From.Tag            = m_LocalTag;
                request.CallID              = m_CallID;
                request.CSeq.SequenceNumber = ++m_LocalSeqNo;
                request.Contact.Add(m_pLocalContact.ToString());

                return(request);
            }
        }