javax.microedition.sip
Interface SipConnection

All Known Subinterfaces:
SipClientConnection, SipServerConnection

public interface SipConnection

SipConnection is the base interface for SIP connections. SipConnection holds the common properties and methods for subinterfaces SipClientConnection and SipServerConnection.

Integration to Generic Connection Framework

Integration to javax.microedition.io.Connector

A new SIP connection is instantiated by a call to Connector.open(). An application SHOULD call close() when it is finished with the connection. It should be noticed that the Connector.open() returns a client mode connection (SipClientConnection) or server mode connection (SipConnectionNotifier) depending on the string (SIP URI) passed to the Connector.open(). The SIP URI is specified in RFC3261 [1] and here it takes general form of:

{scheme}:[{target}][{params}]

where:

The SIP URI may contain quote characters. The application can use either the quote character or it's escaped version (%22), the API implementation must support both forms.

Opening new client connection (SipClientConnection)

If the target host is included a, SipClientConnection will be returned.

Examples:

 sip:bob@biloxi.com
 sip:alice@10.128.0.8:5060
 sips:alice@company.com:5060;transport=tcp
 sip:+358-555-1234567;postd=pp22@foo.com;user=phone
 

Opening new server connection (SipConnectionNotifier)

The server mode is detected by missing target host in the SIP URI. The server connection can be opened in two modes shared and dedicated (see also SIP Identity chapter). It is not required that an implementation of this specification supports both server modes. There may be devices where dedicating separate ports for applications is not feasible. Conversely there may be devices where sharing the SIP listening port among applications is not feasible. Naturally it is required that either shared or dedicated server mode is supported.

This specification defines a special URI format for opening the SIP server mode connections:

{scheme}:[{port}][{params}]

where:

Opening server connection in shared mode

The incoming requests targeted to the application tagged with the parameter 'type' are routed to this SipConnectionNotifier.

Opening server connection in dedicated mode

If the application identifier 'type' is specified the requests targeted to this application are routed to this SipConnectionNotifier.

Examples of opening a SIP server connection:

 // Shared mode, the application MIME type identifier is 
 // application/vnd.company.x-game
 SipConnectionNotifier scn = (SipConnectionNotifier) 
      Connector.open("sip:*;type=\"application/vnd.company.x-game\"");

 // Dedicated mode, port number 5060 opened for the application
 SipConnectionNotifier scn = (SipConnectionNotifier)
      Connector.open("sip:5060");

 // Dedicated mode, port number 5080, using secure transport
 // the application identifier is "application/messenger"
 SipConnectionNotifier scn = (SipConnectionNotifier) 
      Connector.open("sips:5080;type=\"application/messenger\"");

 // Dedicated mode, dedicated port number selected by the system
 SipConnectionNotifier scn = (SipConnectionNotifier) 
      Connector.open("sip:");   
 

Connector.open(String name, String mode)

The optional second parameter 'mode' in Connector.open() specifies the access mode. This is ignored in SIP API. This is because both connection modes: client mode connection and server mode connection can send and receive messages.

Connector.open(String name, String mode, boolean timeouts)

The optional third parameter is a boolean flag that indicates if the calling code can handle timeout exceptions. That parameter is also ignored by the SIP API.

Convenience methods for opening streams

The Connector convenience methods to gain access to a specific input or output stream directly are not supported by the SIP API. The implementations MUST throw IOException if these methods are called with SIP URIs.

The Exceptions when calling Connector.open()

IllegalArgumentException
- If a parameter is invalid.
ConnectionNotFoundException
- If the requested connection cannot be created, or the protocol type does not exist.
IOException
- If some other kind of I/O error occurs. For example the port number for server mode connection is already reserved.
SecurityException
- May be thrown if access to the protocol handler is prohibited.
SipException
- TRANSACTION_UNAVAILABLE if the system can not open new SIP transactions. TRANSPORT_NOT_SUPPORTED if the requested transport is not supported. See above transport URI parameter.

Supported Transport Protocols

All compliant implementations MUST support sending and receiving SIP messages, at least on UDP and TCP transport protocols, as defined in RFC 3261 (section 18). The default transport protocol MUST be UDP. Whenever requested, the preferred transport protocol MUST be indicated with the ;transport={transport} parameter within the URI indicated in the Connector.open() method, either for client or server connections. The choice of transport protocols on which an UAS MUST listen are specified by RFC 3261 (18.2.1):

For any port and interface that a server listens on for UDP, it MUST listen on that same port and interface for TCP. This is because a message may need to be sent using TCP, rather than UDP, if it is too large. As a result, the converse is not true. A server need not listen for UDP on a particular address and port just because it is listening on that same address and port for TCP.

This means that for a SipConnectionNotifier listening on UDP transport protocol is not mandatory if all requests have been sent on top of TCP, that is if all the Contact headers sent within a registration or within dialogs indicate transport=tcp.

SIP Identity

SIP identity is a logical identity (address-of-record, AOR), a type of Uniform Resource Identifier (URI) called a SIP URI. SIP identity is frequently thought of as the "public address" of the user. (see RFC 3261 [1], 6 Definitions, p.20). SIP terminal is typically configured for one user at the time (in SIP settings). The AOR is associated (inside the terminal) with one listening port e.g. 5060 (udp/tcp). So, all incoming SIP requests to that particular address-of-record are received through that port.

Now it is still possible to have several applications that want to share the same SIP identity, without specifying own listening ports (audio/video, instant message/presence and e.g. game applications). It is not feasible, or even possible, for every application to reserve own listening port and register that to the SIP registrar. This is particularly not feasible in resource-constrained terminals/networks. On the other hand, some applications can still use their own SIP identity (for that particular service), which does not share the system SIP properties.

In SIP terms: if the request is targeted to specific application (and it is sent outside an existing dialog) it is not possible to always route incoming SIP requests using: port number, SDP media type or SIP method name (INVITE, MESSAGE, SUBSCRIBE, ...).

The issue falls to the decisions on how the initial SIP requests are routed (inside the terminal) to the User Agents (applications). This kind of functionality is specified in SIP Working Group as callee capabilities RFC3840 [4] and caller preferences RFC3841 [5]. The JSR180 specification utilizes similar functinality und uses the media feature tag 'type' for specifying the application identifier, which is used to route the incoming requests for correct applications.

Applications can use the MIME type feature tag first to register locally to the SIP system and second to indicate that in a caller preference header Accept-Contact. Each application is mapped to a certain MIME type. JSR180 SIP API provides the way to utilize this functionality as specified below.

To allow the Java SIP API to share the system SIP identity or use application's own identity, the following rules are defined when the SIP server connection is opened with Connector.open():

Connector SIP URI SIP Identity Request routing
1) sip:*;type="application/subtype"
  • share system SIP port
  • share system SIP identity
  • SIP register done by the system
route incoming SIP requests with MIME type feature tag "application/subtype" to this SipConnectionNotifier
2) sip:5080[;type="application/subtype"]
  • use dedicated port number 5080
  • use identity set by the application
  • application does the SIP register
route all incoming SIP requests on port 5080 to this SipConnectionNotifier. If the optional MIME type feature tag "application/subtype" is set, route only the requests with the matching tag.
3) sip:
  • use dedicated port selected by the system
  • use identity set by the application
  • application does the SIP register
route all incoming SIP requests to the selected port to this SipConnectionNotifier

Routing the incoming request

The following routing rules are based on the information available in the incoming request. The implementations may define local policy that overrides any of these rules for security reasons. The incoming request is routed based on following information:

The request is routed according to the following rules, based on which of the information above is available. Every request may include Accept-Contact and Reject-Contact headers. INVITE request can also have SDP payload.

Accept-Contact SDP media Routing
1) yes - Header field contains feature sets that describe UAs that the caller would like to reach. In this specification the minimum requirement is the application MIME type indicated by the Accept-Contact parameter 'type'
2) yes yes Same as case 1)
3) - yes (OPTIONAL) The request is routed based on SDP media information.

The rule 1) defines the minimum required operation for this specification. The SIP dispatcher should implement the decision rules defined in caller prefs [RFC3841] specification. For security reasons the dispatcher implementation may define routing rules that cannot be overridden by other applications.

If matching application is not found a suitable error response is sent e.g.

Examples of Accept-Contact header and incoming request

The format of the Accept-Contact header is:

    Accept-Contact: *;<feature_set>
 

Where "*" is purely there to match the SIP extensions syntax and <feature_set> is a list of feature parameters.

Examples:

    Accept-Contact: *;type="application/vnd.company.battleships"
    Accept-Contact: *;type="application/x-chess";
    Accept-Contact: *;audio;voice;mobility="mobile";
 

Example of an incoming request with Accept-Contact header, matching the application MIME type "application/x-chess":

    INVITE sip:UserY@example.com SIP/2.0
    From: sip:UserX@operator.com
    To: sip:UserY@example.com
    Accept-Contact: *;type="application/x-chess";explicit
    Content-Type: application/sdp

    ...SDP...
 

Restricted access to headers

Access to certain header types may be restricted. Typically these headers are related to SIP routing and transaction handling so they are not needed to be read and/or modified by the user. The following two list of headers apply to all header manipulation methods of this class.

Read-only headers

An implementation MAY throw SipException with INVALID_OPERATION error code if the user tries to modify the following headers:

Call-ID, Cseq, Proxy-Authenticate, WWW-Authenticate

Inaccessible headers

An implementation MAY return null if the user tries to read the following headers. Trying to modify these headers will result in SipException.INVALID_OPERATION:

Authentication-Info, Authorization, Max-Forwards, Min-Expires, Proxy-Authorization, Record-Route, Security-Server, Security-Verify, Service-Route, Via

Identification of the SIP API

To enable applications to test for the presence of the SIP API and its version during runtime, a system property is defined. Platforms where this API is implemented according to this specification shall include a system property with a key "microedition.sip.version". When System.getProperty is called with this key, implementations conforming to this specification shall return the version string "1.1.1".

See Also:
SipClientConnection, SipServerConnection, SipConnectionNotifier

Method Summary
 void addHeader(java.lang.String name, java.lang.String value)
          Adds a header to the SIP message.
 SipDialog getDialog()
          Returns the current SIP dialog.
 java.lang.String getHeader(java.lang.String name)
          Gets the header field value of specified header type.
 java.lang.String[] getHeaders(java.lang.String name)
          Gets the header field value(s) of specified header type.
 java.lang.String getMethod()
          Gets the SIP method.
 java.lang.String getReasonPhrase()
          Gets SIP response reason phrase.
 java.lang.String getRequestURI()
          Gets Request-URI.
 int getStatusCode()
          Gets SIP response status code.
 java.io.InputStream openContentInputStream()
          Returns InputStream to read the message body content of a request or response received.
 java.io.OutputStream openContentOutputStream()
          Returns OutputStream to fill the SIP message body content.
 void removeHeader(java.lang.String name)
          Removes header from the message.
 void send()
          Sends the SIP message.
 void setErrorListener(SipErrorListener sel)
          Sets the listener for error notifications.
 void setHeader(java.lang.String name, java.lang.String value)
          Sets header value in SIP message.
 

Method Detail

send

void send()
          throws java.io.IOException,
                 SipException

Sends the SIP message. Send must also close the OutputStream if it was opened. Calling send() is asynchronous. Any kind of immediate failure will throw IOException or SipException. Errors during the send operation can be handled with the SipErrorListener mechanism. With SipServerConnection it is possible to resend 2xx responses in Completed state, by calling directly send().

Throws:
java.io.IOException - if the message could not be sent or because of network failure. When IOException is thrown the connection moves to the Terminated state.
SipException - INVALID_STATE if the message can not be sent in this state. INVALID_MESSAGE if there was an error in the message format.
See Also:
SipErrorListener

setHeader

void setHeader(java.lang.String name,
               java.lang.String value)
               throws SipException

Sets header value in SIP message. If the header does not exist it will be added to the message, otherwise the existing header is overwritten. If multiple header field values exist the topmost is overwritten. The implementations MAY restrict the access to some headers according to RFC 3261 [1], see also "Restricted access to headers".

The implementations are free to store the multiple header field-values either as separate rows or as comma-separated list (if the header type follows the grammar defined in [RFC3261] section 7.3).

The value argument of the method may contain a list of comma-separated header values. Note that this feature should not be used for headers (like the Authorization header) which use comma as parameter separator instead of semicolon. If there exist headers of the same type then only the first (topmost) one will be overwritten, indifferently of the number of header values in the comma-separated list. See example 3. below.

The method works atomically, that is if the value argument of the method is a list of comma-separated values then the method should either set all of them or none of them. That is if an exception is thrown from the method then no headers are changed, even if the error occurred when setting the second, third etc header value.

Example1: Replacing single header field row. The message already contains following headers:

 Route: <sip:alice@atlanta.com>
 Route: <sip:carol@chicago.com>
 
 setHeader("Route", "<sip:bob@biloxi.com>");
 
 the result will be
 
 Route: <sip:bob@biloxi.com>
 Route: <sip:carol@chicago.com>
 

Example2: Setting multiple header field rows as a comma-separated list. The message already contains one header:

 Route: <sip:carol@chicago.com>
 
 setHeader("Route", "<sip:alice@atlanta.com>, <sip:bob@biloxi.com>");
 
 the result will be either
 
 Route: <sip:alice@atlanta.com>, <sip:bob@biloxi.com>
 
 or
 
 Route: <sip:alice@atlanta.com>
 Route: <sip:bob@biloxi.com>
 

Example3: Setting multiple header field rows as a comma-separated list. The message already contains two headers:

 Route: <sip:carol@chicago.com>
 Route: <sip:joe@joe.com>
 
 setHeader("Route", "<sip:al@abc.com>, <sip:bob@biloxi.com>");
 
 the result will be either
 
 Route: <sip:al@abc.com>, <sip:bob@biloxi.com>, <sip:joe@joe.com>
 
 or
 
 Route: <sip:al@abc.com>
 Route: <sip:bob@biloxi.com>
 Route: <sip:joe@joe.com>
 
 The result would be the same if the original message contained the 
 headers in a concatenated list form:
 
 Route: <sip:carol@chicago.com>, <sip:joe@joe.com>
 

Parameters:
name - name of the header, either in full or compact form see [1] p.32
value - the header value. Empty string or null means a header with no value.
Throws:
java.lang.NullPointerException - if name is null
java.lang.IllegalArgumentException - if the header or value is invalid.
SipException - INVALID_STATE if header can not be set in this state. INVALID_OPERATION if the system does not allow to set this header.

addHeader

void addHeader(java.lang.String name,
               java.lang.String value)
               throws SipException

Adds a header to the SIP message. If multiple header field values exist the header value is added topmost of this type of headers. The implementations MAY restrict the access to some headers according to RFC 3261 [1], see also "Restricted access to headers".

Some SIP headers can occur only once in a message, for these it is recommended that setHeader is used instead of addHeader. Implementations of this specification are not mandated to check that the multiplicity of headers conform to the relevant RFCs when the message is composed.

The header value string may contain a single value or multiple values as a comma-separated list (that is, if it follows the grammar defined in [RFC3261] section 7.3). Note that this feature should not be used for headers (like the Authorization header) which use comma as parameter separator instead of semicolon. The implementations are free to store the multiple header field rows either as comma separated list or in separate rows.

The method works atomically, that is if the value argument of this method is a list of comma-separated values then the method should either add all of them or none of them. That is if an exception is thrown from the method then no headers are changed, even if the error occurred when adding the second, third etc header value.

Example1: Adding single header field row. The message already contains header

 Route: <sip:carol@chicago.com>.
 
 addHeader("Route", " <sip:alice@atlanta.com>");
 
 the result will be
 
 Route: <sip:alice@atlanta.com>
 Route: <sip:carol@chicago.com>
 
 or
 
 Route: <sip:alice@atlanta.com>, <sip:carol@chicago.com>
 

Example2: Adding multiple header field rows as a comma-separated list. The message already contains header

 Route: <sip:carol@chicago.com>.
 
 addHeader("Route", "<sip:al@abc.com>, <sip:bob@biloxi.com>");
 
 the result will be either
 
 Route: <sip:al@abc.com>, <sip:bob@biloxi.com>
 Route: <sip:carol@chicago.com>
 
 or
 
 Route: <sip:al@abc.com>
 Route: <sip:bob@biloxi.com>
 Route: <sip:carol@chicago.com>
 
 or
 
 Route: <sip:al@abc.com>, <sip:bob@biloxi.com>, <sip:carol@chicago.com>
 

Parameters:
name - name of the header, either in full or compact form see [1] p.32
value - the header value. Empty string or null means a header with no value.
Throws:
java.lang.NullPointerException - if name is null
java.lang.IllegalArgumentException - if the header or value is invalid.
SipException - INVALID_STATE if header can not be added in this state. INVALID_OPERATION if the system does not allow to add this header.

removeHeader

void removeHeader(java.lang.String name)
                  throws SipException

Removes header from the message. If multiple header field values exist the topmost is removed. If the named header is not found this method does nothing. The implementations MAY restrict the access to some headers according to RFC 3261 [1], see also "Restricted access to headers". The method only removes one header value even if the header values are stored in a comma-separated list.

Example1: Removing header from a message that contains two Route headers in separate header field rows.

 Route: <sip:alice@atlanta.com>
 Route: <sip:carol@chicago.com>
 
 removeHeader("Route");
 
 the result is:
 
 Route: <sip:carol@chicago.com>
 

Example2: Removing header from a message that contains three Route headers in a comma-separated header field value.

 Route: <sip:al@abc.com>, <sip:carol@chicago.com>, <sip:bob@biloxi.com>
 
 removeHeader("Route");
 
 the result is:
 
 Route: <sip:carol@chicago.com>, <sip:bob@biloxi.com>
 

Parameters:
name - name of the header to be removed, either in full or compact form see [1] p.32
Throws:
java.lang.NullPointerException - if name is null
SipException - INVALID_STATE if header can not be removed in this state. INVALID_OPERATION if the system does not allow to remove this header.

getHeaders

java.lang.String[] getHeaders(java.lang.String name)

Gets the header field value(s) of specified header type. The method returns the header field-values separated in an array regardless of how they are stored in the message. The implementations MAY restrict the access to some headers according to RFC 3261 [1], see also "Restricted access to headers".

Example1: Get Route headers from a message that contains two Route headers in separate header field rows.

 Route: <sip:alice@atlanta.com>
 Route: <sip:carol@chicago.com>
 
 getHeaders("Route");
 
 the result is a String array:
 
 {"<sip:alice@atlanta.com>", "<sip:carol@chicago.com>"}
 
 

Example2: Get Route headers from a message that contains three Route headers in a comma-separated header field value.

 Route: <sip:al@abc.com>,<sip:carol@chicago.com>,<sip:bob@biloxi.com>
 
 getHeaders("Route");
 
 the result is a String array:
 
 {"<sip:al@abc.com>", "<sip:carol@chicago.com>", 
  "<sip:bob@biloxi.com>"}
 

Parameters:
name - name of the header type, either in full or compact form see [1] p.32
Returns:
array of header field values (topmost first), or null if the current message does not have such a header or the header is for other reason not available (e.g. message is not initialized, the connection is closed or the implementation does not allow this header to be read). The returned array may contain empty strings.
Throws:
java.lang.NullPointerException - if name is null

getHeader

java.lang.String getHeader(java.lang.String name)

Gets the header field value of specified header type. The implementations MAY restrict the access to some headers according to RFC 3261 [1], see also "Restricted access to headers".

Example1: Get topmost Route header from a message that contains three Route headers in a comma-separated header field value.

 Route: <sip:al@abc.com>,<sip:carol@chicago.com>,<sip:bob@biloxi.com>
 
 getHeader("Route");
 
 the result is:
 
 <sip:al@abc.com>
 

Parameters:
name - name of the header type, either in full or compact form see [1] p.32
Returns:
topmost header field value. It is an empty String if the value was set to be null or empty. It is null if the current message does not have such a header or the header is for other reason not available (e.g. message is not initialized, the connection is closed or the implementation does not allow this header to be read).
Throws:
java.lang.NullPointerException - if name is null

getMethod

java.lang.String getMethod()

Gets the SIP method. Applicable when a message has been initialized or received.

Returns:
SIP method name REGISTER, INVITE, NOTIFY, etc. Returns null if the method is not available (e.g. message is not initialized, the connection is closed).

getRequestURI

java.lang.String getRequestURI()

Gets Request-URI. If supported, available when SipClientConnection is in Initialized state or when SipServerConnection is in Request Received state. Built from the original URI given in Connector.open(). See RFC 3261 p.35 (8.1.1.1 Request-URI)

It is not mandated that this method be supported, an implementation may return null in any state.

Returns:
Request-URI of the message. Returns null if the Request-URI is not available (e.g. message is not initialized or the connection is closed) or getting the Request-URI is not supported.

getStatusCode

int getStatusCode()

Gets SIP response status code. Available when SipClientConnection is in Proceeding, Unauthorized or Completed state or when SipServerConnection is in Initialized state.

Returns:
status code 1xx, 2xx, 3xx, 4xx, ... Returns 0 if the status code is not available.

getReasonPhrase

java.lang.String getReasonPhrase()

Gets SIP response reason phrase. Available when SipClientConnection is in Proceeding, Unauthorized or Completed state or when SipServerConnection is in Initialized state.

Returns:
reason phrase. Returns null if the reason phrase is not available (e.g. message is not initialized or the connection is closed). Returns an empty string is the reason phrase was set with null or empty string in setReasonPhrase.

getDialog

SipDialog getDialog()

Returns the current SIP dialog. This is available when the SipConnection belongs to a created SipDialog, which is in Early or Confirmed state (see SipDialog).

The SipDialog returned from the SipConnection defines always the peer-to-peer association created by the latest sent or received request or response. The method returns null if a terminating error response (3xx - 6xx) is received or sent on the connection or the connection is closed.

The following rules apply when this method is called on a SipServerConnection instance:

Returns:
SipDialog object if this connection belongs to a dialog, otherwise returns null. See also the rules defined at the method's description.
See Also:
SipDialog

openContentInputStream

java.io.InputStream openContentInputStream()
                                           throws java.io.IOException,
                                                  SipException

Returns InputStream to read the message body content of a request or response received. It is not required that implementations store the message content after it was sent, so calling this method after sending a request or response may fail.

Returns:
InputStream to read body content
Throws:
java.io.IOException - if the InputStream can not be opened, because of an I/O error occurred.
SipException - INVALID_STATE if the InputStream can not be opened in this state (e.g. no message received or message has already been sent).

openContentOutputStream

java.io.OutputStream openContentOutputStream()
                                             throws java.io.IOException,
                                                    SipException

Returns OutputStream to fill the SIP message body content. When calling close() on OutputStream the message will be sent to the network. So it is equivalent to call send(). This method must not be called after closing the OutputStream, since it will throw Exception because of calling the method in wrong state.

Before opening the OutputStream the Content-Type header has to be set. If not SipException.UNKNOWN_TYPE will be thrown. The Content-Length header need not be set, it is automatically set by the API implementation immediately before sending the message. If it is set by the application, it will be overwritten with the correct length of the stream.

Returns:
OutputStream to write body content
Throws:
java.io.IOException - if the OutputStream can not be opened, because of an I/O error occurred.
SipException - INVALID_STATE if the OutputStream can not be opened in this state (e.g. no message initialized). UNKNOWN_TYPE Content-Type if the type header is not set.
See Also:
send()

setErrorListener

void setErrorListener(SipErrorListener sel)
                      throws SipException

Sets the listener for error notifications. Applications that want to receive notification about a failure of an asynchoronous send operation must implement the SipErrorListener interface and register it with a connection using this method. Only one listener can be set at any time, if a listener is already set it will be overwritten. Setting listener to null will remove the current listener.

This method is added to version 1.1.0 so that applications can receive notifications about transmission errors, like failure in the GPRS connection.

Parameters:
sel - reference to the listener object. The value null will remove the existing listener.
Throws:
SipException - INVALID_STATE if the connection is closed
Since:
1.1.0


Copyright © 2007 Nokia Corporation. All Rights Reserved.
Java is a trademark of Sun Microsystems, Inc.