javax.microedition.sip
Interface SipClientConnection

All Superinterfaces:
javax.microedition.io.Connection, SipConnection

public interface SipClientConnection
extends SipConnection

SipClientConnection represents SIP client transaction. application can create a new SipClientConnection with Connector or SipDialog object.

The SipClientConnection has following state diagram:

Note: The state diagram of SipClientConnection differs from the state diagram of SIP client transaction, which can be found in RFC 3261 [1] p.128-133

Following methods are restricted to a certain state. The table shows the list of restricted methods allowed in each state.

Following methods can be called in every state. The functionality is defined by the method depending of the information availability.

Code examples

The example below illustrates the usage of SIP client connection: opening, sending one request (MESSAGE) and receiving response:

 public void sendTextMessage(String msg) {
    SipClientConnection sc = null;
    try {
       sc = (SipClientConnection) Connector.open("sip:sippy.tester@host.com:5060");
       sc.initRequest("MESSAGE", null);
       sc.setHeader("From", "sip:user@host.com");
       sc.setHeader("Subject", "testing...");

       // write message body
       sc.setHeader("Content-Type", "text/plain");
       sc.setHeader("Content-Length", Integer.toString(msg.length()));
       OutputStream os = sc.openContentOutputStream();
       os.write(msg.getBytes());
       os.close(); // close stream and send the message

       // wait maximum 15 seconds for response
       boolean ok = sc.receive(15000);

       if(ok) {  // response received
           if(sc.getStatusCode() == 200) {
              // handle 200 OK response
           } else {
              // handle possible error responses
           }
       }
       sc.close();
     } catch(Exception ex) {
          // handle Exceptions
     }
 }
 
Following class shows the same example using callback listener interface:

 public class SipClient implements SipClientConnectionListener {
    public void sendTextMessage(String msg) {
       SipClientConnection sc = null;
       try {
          sc = (SipClientConnection) Connector.open("sip:sippy.tester@host.com:5060");
          sc.setListener(this);
          sc.initRequest("MESSAGE", null);
          sc.setHeader("From", "sip:user@host.com");
          sc.setHeader("Subject", "testing...");
          sc.setHeader("Content-Type", "text/plain");
          sc.setHeader("Content-Length", Integer.toString(msg.length()));
          OutputStream os = sc.openContentOutputStream();
          os.write(msg.getBytes());
          os.close(); // close stream and send message
       } catch(Exception ex) {
         // handle Exceptions
       }
      return;
    }
 
    public void notifyResponse(SipClientConnection scn) {
       try {
          // retrieve the response received
          sc.receive(0); // does not block response is there
          if(sc.getStatusCode() == 200) {
             // handle 200 OK response
          } else {
             // handle possible error responses
          }
          sc.close();
       } catch(Exception ex) {
             // handle Exceptions
       }
    }
 } 
 

See Also:
SipClientConnectionListener, SipConnectionNotifier, SipServerConnection, SipDialog.getNewClientConnection(String)

Method Summary
 int enableRefresh(SipRefreshListener srl)
          Enables the refresh on for the request to be sent.
 void initAck()
          Convenience method to initialize SipClientConnection with SIP request method ACK.
 SipClientConnection initCancel()
          Convenience method to initialize SipClientConnection with SIP request method CANCEL.
 void initRequest(java.lang.String method, SipConnectionNotifier scn)
          Initializes SipClientConnection to a specific SIP request method (REGISTER, INVITE, MESSAGE, ...).
 boolean receive(long timeout)
          Receives SIP response message.
 void setCredentials(java.lang.String username, java.lang.String password, java.lang.String realm)
          Sets credentials for possible digest authentication.
 void setListener(SipClientConnectionListener sccl)
          Sets the listener for incoming responses.
 void setRequestURI(java.lang.String URI)
          Sets Request-URI explicitly.
 
Methods inherited from interface javax.microedition.sip.SipConnection
addHeader, getDialog, getHeader, getHeaders, getMethod, getReasonPhrase, getRequestURI, getStatusCode, openContentInputStream, openContentOutputStream, removeHeader, send, setHeader
 
Methods inherited from interface javax.microedition.io.Connection
close
 

Method Detail

initRequest

public void initRequest(java.lang.String method,
                        SipConnectionNotifier scn)
                 throws java.lang.IllegalArgumentException,
                        SipException
Initializes SipClientConnection to a specific SIP request method (REGISTER, INVITE, MESSAGE, ...). The methods are defined in the RFC 3261 [1] and extensional specifications from SIP WG and SIMPLE WG [2][3]. The default RequestURI and headers will be initialized automatically. After this the SipClientConnection is in Initialized state.

The initialized request can be associated with a opened SipConnectionNotifier. Initialization of some headers depends on how the associated SipConnectionNotifier is initialized.

See also chapter "SipConnection: Opening new server connection" for more details.

Headers that will be initialized are as follows:

    To           // To address constructed from SIP URI given in Connector.open()
    From         // Set by the system. If SipConnectionNotifier is given and it is 
                    in shared mode the value will be set according the terminal SIP 
                    settings (see Opening new server connection for more details). 
                    If the SipConnectionNotifier is not given (= null) or it is in 
                    dedicated mode the From header MUST be set to a default value 
                    e.g. anonymous URI (see RFC 3261 [1], chapter 8.1.1.3 From).
    CSeq         // Set by the system
    Call-ID      // Set by the system
    Max-Forwards // Set by the system
    Via          // Set by the system
    Contact      // If SipConnectionNotifier is given the value is set by the 
                    system for REGISTER, INVITE and SUBSCRIBE. The value will be 
                    set according to the terminal IP settings and the 
                    SipConnectionNotifier properties. So the new request is 
                    associated with the SipConnectionNotifier. If the associated
                    SipConnectionNotifier is in the dedicated mode the user part
                    is set to some default value e.g. user.
                    Example (dedicated mode),
                          Contact: sip:user@172.21.55.69:5060
                    Example (shared mode),
                          Contact: "Mr. Watson" <sip:watson@172.21.55.69:5060>
 
Reference RFC 3261 [1] p.35 (8.1.1 Generating the Request) and p.159 (20 Header Fields)

Parameters:
method - Name of the method
scn - SipConnectionNotifier to which the request will be associated. If scn is null the request will not be associated to any user defined listening point.
Throws:
java.lang.IllegalArgumentException - if the method is invalid
SipException - INVALID_STATE if the request can not be set, because of wrong state in SipClientConnection. Furthermore, ACK and CANCEL methods can not be initialized in Created state.
See Also:
SipConnectionNotifier

setRequestURI

public void setRequestURI(java.lang.String URI)
                   throws java.lang.IllegalArgumentException,
                          SipException
Sets Request-URI explicitly. Request-URI can be set only in Initialized state.

Parameters:
URI - Request-URI
Throws:
java.lang.IllegalArgumentException - MAY be thrown if the URI is invalid
SipException - INVALID_STATE if the Request-URI can not be set, because of wrong state, INVALID_OPERATION if the Request-URI is not allowed to be set.

initAck

public void initAck()
             throws SipException
Convenience method to initialize SipClientConnection with SIP request method ACK. ACK can be applied only to INVITE request. The method is available when final response (2xx) has been received. The header fields of the ACK are constructed in the same way as for any request sent within a dialog with the exception of the CSeq and the header fields related to authentication (RFC 3261 [1], p.82). The Request-URI and headers will be initialized automatically. After this the SipClientConnection is in Initialized state.

At least Request-URI and following headers will be set by the method (RFC 3261 [1] 12.2.1.1 Generating the Request p.73 and 8.1.1 Generating the Request p.35).
See also RFC 3261 [1] 13.2.2.4 2xx Responses (p.82)

    Request-URI  // system uses the remote target and route set to build the Request-URI
    To           // remote URI from the dialog state + remote tag of the dialog ID
    From         // local URI from the dialog state + local tag of the dialog ID
    CSeq         // the sequence number of the CSeq header field MUST be the same as 
                    the INVITE being acknowledged, but the CSeq method MUST be ACK.
    Call-ID      // Call-ID of the dialog
    Via          // Via header field indicates the transport used for the transaction 
                    and identifies the location where the response is to be sent
    Route        // system uses the remote target and route set (if present) 
                    to build the Route header
    Contact      // 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
    Max-Forwards // header field serves to limit the number of hops a request can 
                    transit on the way to its destination.
 

The following rule also applies:
For error responses (3xx-6xx) the ACK is sent automatically by the system in transaction level. If user initializes an ACK which has already been sent an Exception will be thrown.

Throws:
SipException - INVALID_STATE if the request can not be set, because of wrong state, INVALID_OPERATION if the ACK request can not be initialized for other reason (already sent or the original request is non-INVITE).

initCancel

public SipClientConnection initCancel()
                               throws SipException
Convenience method to initialize SipClientConnection with SIP request method CANCEL. The method is available when a provisional response has been received. The CANCEL request starts a new transaction, that is why the method returns a new SipClientConnection. The CANCEL request will be built according to the original INVITE request within this connection. The RequestURI and headers will be initialized automatically. After this the SipClientConnection is in Initialized state. The message is ready to be sent.

The following information will be set by the method:

    Request-URI  // copy from original request
    To           // copy from original request
    From         // copy from original request
    CSeq         // same value for the sequence number as was present in the original 
                    request, but the method parameter MUST be equal to "CANCEL"
    Call-ID      // copy from original request
    Via          // single value equal to the top Via header field of the request 
                    being cancelled
    Route        // If the request being cancelled contains a Route header field, the 
                    CANCEL request MUST include that Route header field's values
    Max-Forwards // header field serves to limit the number of hops a request can 
                    transit on the way to its destination. 
 
Reference RFC 3261 [1] p.53-54

Note: CANCEL request SHOULD NOT be sent to cancel a request other than INVITE.

Returns:
A new SipClientConnection with preinitialized CANCEL request.
Throws:
SipException - INVALID_STATE if the request can not be set, because of wrong state (in SipClientConnection) or the system has already got the 200 OK response (even if not read with receive() method). INVALID_OPERATION if CANCEL method can not be applied to the current request method.

receive

public boolean receive(long timeout)
                throws SipException,
                       java.io.IOException
Receives SIP response message. The receive method will update the SipClientConnection with the last new received response. If no message is received the method will block until something is received or specified amount of time has elapsed.

The SipClientConnection is always associated with the latest response received succesfully by calling the receive() method.

Parameters:
timeout - the maximum time to wait in milliseconds. 0 = do not wait, just poll
Returns:
Returns true if response was received. Returns false if the given timeout elapsed and no response was received.
Throws:
java.io.IOException - if the message could not be received or because of network failure
SipException - INVALID_STATE if the receive can not be called because of wrong state.
See Also:
SipConnection.send()

setListener

public void setListener(SipClientConnectionListener sccl)
                 throws java.io.IOException
Sets the listener for incoming responses. If a listener is already set it will be overwritten. Setting listener to null will remove the current listener.

Parameters:
sccl - reference to the listener object. Value null will remove the existing listener.
Throws:
java.io.IOException - if the connection is closed

enableRefresh

public int enableRefresh(SipRefreshListener srl)
                  throws SipException
Enables the refresh on for the request to be sent. The method return a refresh ID, which can be used to update or stop the refresh.

Parameters:
srl - callback interface for refresh events, if this is null the method returns 0 and refresh is not enabled.
Returns:
refresh ID. If the request is not refreshable returns 0.
Throws:
SipException - INVALID_STATE if the refresh can not be enabled in this state.
See Also:
SipRefreshHelper

setCredentials

public void setCredentials(java.lang.String username,
                           java.lang.String password,
                           java.lang.String realm)
                    throws SipException
Sets credentials for possible digest authentication. The application can set multiple credential triplets (username, password, realm) for one SipClientConnection. The username and password are specified for certain protection domain, which is defined by the realm parameter.

The credentials can be set: See also SipClientConnection state diagram.

Example 1

The following simplified example shows how the credentials are set before sending the original request.
  1. Initialize the original REGISTER request.
  2. Set credentials username, password for some realm. The credentials are saved by the system.
  3. Application calls send()
  4. The API implementation sends REGISTER request to the SIP server.
  5. Application calls receive() to wait for the next response.
  6. SIP server responds with the "401 Unauthorized". The response is not passed up to the application, since the API implementation either prompts for the credentials (ask them with a dialog) or uses the previously saved credentials set by the application.
  7. The API implementation calculates the authorization headers and resends the REGISTER.
  8. Now the server accepts the REGISTER and responds with 200 OK. The response is passed to the application.
  9. The receive() returns and the application calls getStatusCode(), which returns 200.
  10. Application ends the connection by calling close().


Example 2

The following example shows how the credentials are set when the authentication response is received by the application.
  1. The application initializes the original REGISTER request.
  2. Application calls send()
  3. The API implementation sends REGISTER request to the SIP server.
  4. Application calls receive() to wait for the next response.
  5. SIP server responds with the "401 Unauthorized". The response is passed up to the application, since the API implementation does not have the credentials or it is not able to collect them from the user.
  6. The application calls getStatusCode(), which returns now 401.
  7. The application gathers the credentials and calls setCredentials().
  8. The API implementation calculates the authorization headers and resends the REGISTER.
  9. Application calls receive() to wait for the next response.
  10. The server accepts the REGISTER and responds with 200 OK. The response is passed to the application.
  11. The receive() returns and the application calls getStatusCode(), which returns now 200.
  12. Application ends the connection by calling close().

The following example code shows an outline how the application could send the REGISTER and handle the authentication responses as shown in the Example 2.

 public void doRegister(String username, String password, String realm) {
	
  SipClientConnection scc = null;
  SipConnectionNotifier scn = null;
  String contact = null;
	
  try {
      // open listener in application specific port 5080
      scn = (SipConnectionNotifier) Connector.open("sip:5080");
	    
      // build the contact URI
      contact = 
		new String("sip:user@"+scn.getLocalAddress()+":"+scn.getLocalPort());
	    
      // open client connection to the SIP registrar in this case "host.com"	   
      scc = (SipClientConnection) Connector.open("sip:host.com");
      // initialize REGISTER with appropriate headers
      scc.initRequest("REGISTER", scn);
      scc.setHeader("From", "sip:user@host.com");
      scc.setHeader("To", "sip:user@host.com");
      scc.setHeader("Contact", contact);
	    
      scc.send();
	    
      boolean handled = false;
      int scode = 0;
	    
      while(!handled) {
          SipHeader sh;
          // wait max 30 secs for response
          scc.receive(30000);
          scode = scc.getStatusCode();
          switch(scode)
          {
              case 401:
                  sh = new SipHeader("WWW-Authenticate",
                     scc.getHeader("WWW-Authenticate"));
                  realm = sh.getParameter("realm");                
                  // here for example, prompt user for password for this realm
                  // set credentials to initiate re-REGISTER
                  scc.setCredentials(username, password, realm);
                  break;
			
              case 407:
                  sh = new SipHeader("Proxy-Authenticate", 
                     scc.getHeader("Proxy-Authenticate"));
                  realm = sh.getParameter("realm");                
                  // here for example, prompt user for password for this realm
                  // set credentials to initiate re-REGISTER
                  scc.setCredentials(username, password, realm);
                  break;
			
              case 200:
                  // handle OK response
                  handled = true;
                  break;
              default:
                  // handle other responses
                  handled = true;
          }  
      }
      scc.close();
  } catch(Exception ex) {
      // handle Exceptions
  }
 }
 

Parameters:
username - username (for this protection domain)
password - user password (for this protection domain)
realm - defines the protection domain
Throws:
java.lang.NullPointerException - if the username, password or realm is null
java.lang.SipException - INVALID_STATE if the credentials can not be set in this state.
SipException


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