|
||
This section describes the sequence that you need to follow to get specifc tasks done:
An application using the SIP Client API first needs to create a
single instance of the CSIP
class, and it must implement
the callback functions defined by MSIPObserver
.
The effect of creating the CSIP
object is to
conect the client to a shared server. The server is started if it is not
already running. This may take a short time while the server side resources are
created and initialized.
The application then creates an instance of the
CSIPConnection
class so that it can use a IAP, and must
implement the callback functions defined by
MSIPConnectionObserver
.
The effect of creating the CSIPConnection
object is to form a sub-session between the client and the server. The
CSIPConnection::NewL()
function is effectively
asynchronous. Once a connection has been created and the connection is active,
the callback function
MSIPConnectionObserver::ConnectionStateChanged(CSIPConnection::
EActive)
is called. The CSIPConnection::EActive
state means
that the object can be used for sending SIP messages and creating registrations
and dialogs. The current state can be queried by calling
CSIPConnection::State()
.
The application can delete any owned API object at any time.
Deleting the CSIP
object causes the connection to
the SIP server to be closed.
Deleting the CSIPConnection
object causes the
sub-session between the client and the server to be closed.
If an application deletes an object on which other objects are
dependent, this can render the other objects unusable. Functions called on
objects that are in an unusable state leave with the error code
KErrSIPResourceNotAvailable
, indicating that they cannot perform
the requested operation.
For example, if an application has CSIPConnection
and CSIPRegistrationBinding
objects, and it then deletes
the CSIPConnection
object, then in most cases, subsequent
attempts to use the CSIPRegistrationBinding
object will fail. This
is because CSIPRegistrationBinding
cannot communicate with the
server side of the SIP stack without the CSIPConnection
object.
The following diagram shows the recommended order for deleting SIP Client API objects.
To send a SIP request:
an application creates a CSIPRequestElements
object, and fills in the desired parts of the request.
The application calls the
CSIPConnection::SendRequestL(CSIPRequestElements*)
function. The
CSIPConnection
object takes ownership of the
CSIPRequestElements
object and communicates the request to
the server side of the SIP stack.
CSIPConnection
creates a
CSIPClientTransaction
object and returns it to the
application.
Note that SendRequestL()
initiates the server side
processing of sending the MESSAGE, but time consuming tasks such as address
resolving and socket operations are done only after the
SendRequestL()
call has returned. If an error occurs after
SendRequestL()
returns, e.g. a failure in address resolution, then
the error is communicated to the application through one of the
MSIPConnectionObserver::ErrorOccured()
callback functions.
It is important to understand that when SendRequestL()
returns,
the MESSAGE has not yet been sent to the network, and is being processed on the
server side of the SIP stack.
Once SendRequestL()
has returned and the sending of a
MESSAGE is in progress on the shared server, there is no way for the
application to cancel that operation. This also applies to other operation
types. However, note that the
CSIPClientTransaction::CancelL()
function can be used to
send a SIP CANCEL request after the application has sent an INVITE request.
When the SIP response message is received from the server side, the
CSIPConnection
object:
creates a CSIPResponseElements
object to
represent the SIP response
attaches it to the CSIPClientTransaction
object.
notifies the application through a call to one of the
MSIPConnectionObserver:: IncomingResponse()
callback
functions.
The application can determine the kind of response received by
accessing the CSIPResponseElements
object through
CSIPClientTransaction
. As the response is provisional, the
application does not delete the CSIPClientTransaction
object. A
'200 response' will be received later, and the application can then delete the
CSIPClientTransaction
object.
creates a CSIPResponseElements
object to represent
the SIP response, attaches it to CSIPClientTransaction and notifies the
application with MSIPConnectionObserver:: IncomingResponse.
The following figure shows the seqence of events iinvolved in sending a MESSAGE request and receiving two responses to it.
A stand-alone SIP request is received through an existing
CSIPConnection
object. This creates
CSIPRequestElements
and
CSIPServerTransaction
objects to represent the incoming
SIP request, before notifying the application through a call to one of the
MSIPConnectionObserver::IncomingRequest()
callback
functions.
The application fetches information about the request by accessing the
CSIPRequestElements
object through the
CSIPServerTransaction
object passed to it via the callback
function.
To send a response, the application creates a
CSIPResponseElements
object and passes it to
CSIPServerTransaction::SendResponseL()
. This causes the
response to be passed to the server side for further processing. Once
SendResponseL()
has returned, the application no longer needs the
CSIPServerTransaction
object and can delete it.
The following diagram shows the sequence of events involved in receiving a MESSAGE and sending a response to it.
The SIP stack receives a SIP INVITE request from the network acting as UAS and creates an invite server transaction for the received request.
The SIP stack sends a '100 SIP response' to the remote UA. After comparing the received request with the stored application capabilities, the SIP stack routes the received INVITE request to the chosen application.
The application creates a CSIPInviteDialogAssoc
object and the SIP stack creates an instance of
CSIPDialog
.
The application sends a '200 SIP response' to the remote UA.
The remote UA acknowledges the '200 SIP' response with ACK and a SIP session is created between the local and remote UA.
The following diagram shows the sequence of events involved in receiving a SIP request and creating a SIP dialog.
To initiate a registration, the application must first create a
CSIPRefresh
object, and then create a
CSIPRegistrationBinding
object, passing
CSIPRefresh
to it. It is not mandatory to create a
CSIPRefresh
object; it is only needed if the registration is to be
refreshed by the SIP stack.
Once the CSIPRegistrationBinding
object exists, the
application can initiate the registration process by calling
RegisterL()
on the CSIPRegistrationBinding
object.
CSIPRegistrationBinding
forms a REGISTER request and communicates
it to the server side of the SIP stack, instantiates
CSIPClientTransaction
object and returns it to the
application.
When the '200 SIP response' is received from the server side,
CSIPConnection
creates the
CSIPResponseElements
object to contain the response, and
then routes the response to CSIPRegistrationBinding
.
CSIPRegistrationBinding
attaches the response to
CSIPClientTransaction
. The application is notified about
the response through one of the
MSIPConnectionObserver::IncomingResponse()
callback
functions.
The application no longer needs the
CSIPClientTransaction
object and can delete it. It can use
IsContextActive()
to find out whether the registration has
succeeded.
The following figure shows the sequence of events involved in registering with a refresh and receiving a '200 OK response'.
To create a dialog, the application creates
CSIPInviteDialogAssoc
and
CSIPMessageElements
objects.
The application needs to fill in the relevant SIP headers in the
CSIPMessageElements
object before passing it to
CSIPInviteDialogAssoc
using the
CSIPInviteDialogAssoc::SendInviteL()
function.
CSIPInviteDialogAssoc
then:
forms an INVITE request
communicates it to the server side of the SIP stack
creates a CSIPClientTransaction
object, and
returns it to the application.
When the '180 response' is received from the server side,
CSIPConnection
creates a
CSIPResponseElements
object to contain the response, and
then routes the response to CSIPDialog
.
CSIPDialog
attaches the response to
CSIPClientTransaction
. The application is informed about
the receipt of the '180 response' through a call to one of the
MSIPConnectionObserver:: IncomingResponse()
callback
functions.
When the '200 response' is received, similar processing occurs as with the '180 response'.
At this point, the application is expected to respond by sending an ACK
request. This is done by invoking the
CSIPInviteDialogAssoc::SendAckL()
function, which forms
the ACK request and sends it to the server side of the SIP stack.
Since there is a possibility that the INVITE request might fork at a
proxy, the SIP stack’s server side waits a while for several possible
responses. When the forking is no longer expected to happen, the SIP stack’s
server side sends an InviteCompleted
event. The SIP Client API
forwards the InviteCompleted
event to the application, indicating
that the application can now delete the
CSIPClientTransaction
.
The following figure shows the sequence of events involved in sending an INVITE, receiving a response and sending ACK.
Applications are not allowed to send '100 responses'. The SIP stack
generates a '100 response' automatically when it receives an
INVITE
request from the network.
When the SIP stack receives a CANCEL
request from the
network, it automatically responds to it. CANCEL
requests are
never passed to an application.
If the SIP stack does not find a matching transaction for a
CANCEL
request, it automatically generates a '481 response'.
If the SIP stack does find a matching transaction for a
CANCEL
request, it automatically generates a '200 response'.
If the SIP stack finds a matching INVITE
server
transaction that is in the Proceeding
state (i.e. a final response
has not been sent yet), it also automatically generates a '487 response' to the
INVITE
transaction.
Once these actions are complete, the SIP stack informs the application
by calling the MSIPConnectionObserver::InviteCanceled()
callback function.
A SIP server in the signalling chain can challenge any SIP request
initiated by the application with an HTTP Digest challenge by responding with a
'401 SIP response', '407 SIP response' or a '494 SIP response'. The responses
contain details of the challenge. These responses are never passed directly to
the application. Instead, they are passed to the application through a call to
the callback function
MSIPHttpDigestChallengeObserver::ChallengeReceived()
.
For an application to be able to respond to a challenge, it must:
create a CSIPHttpDigest
object
provide an implementation of the callback
functionMSIPHttpDigestChallengeObserver::ChallengeReceived()
.
The application can either accept or reject the challenge:
if it accepts the challenge, the callback function must call
CSIPHttpDigest::SetCredentialsL()
, specifying the
username, password, and the realm passed to the callback function.
The SIP stack re-sends the original SIP request with the HTTP Digest response.
if it rejects the challenge, the callback function must call
CSIPHttpDigest::IgnoreChallenge()
, specifying the realm
passed to the callback function.
The SIP stack calls the callback function
MSIPConnectionObserver::ErrorOccured()
, passing the error
code KErrSIPForbidden
.
If an application does not wish to receive HTTP Digest challenges at
all, it must not create a CSIPHttpDigest
object. In this
event, the SIP stack calls the callback function
MSIPConnectionObserver::ErrorOccured()
, passing the error
code KErrSIPForbidden
.
Note that:
if an application uses the SIP Profile Agent for SIP registration, the SIP Profile Agent handles the HTTP Digest challenges related to the registration procedure as per the SIP profile information.
the SIP stack maintains a HTTP Digest cache which stores username
and password pairs for realms. If the username and password have been
configured for a proxy, or if the application has already provided them after
being asked through a
MSIPHttpDigestChallengeObserver::ChallengeReceived()
call,
then the SIP stack uses them to answer subsequent challenges for a matching
realm automatically.
For example, if the application uses a SIP Profile whose proxy has been configured with HTTP Digest passwords, and if the application then sends an INVITE, it does not need to provide the passwords for the proxy as the SIP stack will get them from the HTTP Digest cache.
The following example shows how an application is notified when a
refresh request within a dialog terminates after an error occurs. In this
example the application has sent a SUBSCRIBE
with refresh, and
received a 2xx
class response to the initial
SUBSCRIBE
. The SIP stack periodically sends a refreshed
SUBSCRIBE
.
After a couple of successfully refreshed SUBSCRIBE
s later
the remote server responds with a '481 response', and the application receives
the following callback:
MSIPConnectionObserver::ErrorOccured(TInt aError, CSIPDialogAssocBase& aDialogAssoc)
If the value of aError
is
KErrSIPTerminatedWithResponse
, then the actual SIP
response that caused the refresh to end can be found as follows:
check that aDialogAssoc.Type()
returns
SUBSCRIBE
.
call the function with the signature:
const CSIPRefresh* CSIPSubscribeDialogAssoc::SIPRefresh() const
to get the refresh instance, a CSIPRefresh
object.
Use the CSIPRefresh
object to get the
associated transaction by calling the function with the signature:
const CSIPClientTransaction* CSIPRefresh::SIPTransaction() const
Note that this returned CSIPClientTransaction
object is not the same one that was returned from the call to
SendSubscribeL()
that the application originally used to send the
SUBSCRIBE
.
Use the function with the signature:
const CSIPResponseElements* CSIPClientTransaction::ResponseElements() const
to get the SIP response.
Errors are passed to an application either by calling callback functions or by leaving. See Cleanup support overview.
If an error occurs during the synchronous part of an operation initiated by the application, functions leave with an error code.
If an error occurs later during the asynchronous processing stage, the
error is passed to the application through one of the
MSIPConnectionObserver::ErrorOccured()
callback functions.
There are several overloaded variants of ErrorOccured()
functions,
each of them taking the error code and reference(s) to the SIP Client API
object(s) that encountered the error:
a call to the variants of ErrorOccured()
taking a
CSIPTransactionBase
or
CSIPClientTransaction
parameter means that transaction has
entered the state CTransactionBase::ETerminated
.
a call to the variant of ErrorOccured()
taking a
CSIPRegistrationBinding
parameter means that the
registration context is no longer active, i.e.
CSIPRegistrationBinding::IsContextActive() == EFalse
. If the
registration was being refreshed, then the refresh has also ended and its state
is CSIPRefresh::ETerminated
.
If the callback function
MSIPConnectionObserver::ConnectionStateChanged()
is called
and the aState
parameter is either
CSIPConnection::EInactive
or
CSIPConnection::EUnavailable
, then all dialogs,
registrations and stand-alone transactions using the
CSIPConnection
will have been terminated. To avoid a flood
of callback calls in this kind of situation, calls to
ErrorOccured()
for the individual dialog, registration and
transaction objects are not sent to the application.