SipClientConnectionImplpublic class SipClientConnectionImpl extends Object implements javax.microedition.sip.SipClientConnection
Fields Summary |
---|
private com.sun.midp.security.SecurityToken | classSecurityTokenSecurity token for SIP/SIPS protocol class | public static final int | TERMINATEDTerminated, the final state, in which the SIP connection has
been terminated by error or closed | public static final int | CREATEDCreated, SipClientConnection created from Connector or SipDialog | public static final int | INITIALIZEDInitialized, request has been initialized with initRequest(...)
or initAck() or initCancel() | public static final int | STREAM_OPENStream Open, OutputStream opened with openContentOutputStream().
Opening InputStream for received response does not trigger
state transition. | public static final int | PROCEEDINGProceeding, request has been sent, waiting for the response, or
provisional 1xx response received. initCancel() can be called,
which will spawn a new SipClientConnection which is in
Initialized state | public static final int | UNAUTHORIZEDUnauthorized, transaction completed with response 401
(Unauthorized) or 407 (Proxy Authentication Required). The
application can re-originate the request with proper
credentials by calling setCredentials() method. After this the
SipClientConnection is back in Proceeding state. | public static final int | COMPLETEDCompleted, transaction completed with final response
(2xx, 3xx, 4xx, 5xx, 6xx) in this state the ACK can be initialized.
Multiple 200 OK responses can be received. Note different state
transition for responses 401 and 407. | private static final int | MAX_NUM_RESPONSESMax length of queue of incoming responses. | private javax.microedition.sip.SipDialog | sipDialogthe sip dialog this client transaction belongs to | private javax.microedition.sip.SipClientConnectionListener | sipClientConnectionListenerListener to notify when a response will be received | private javax.microedition.sip.SipConnectionNotifier | sipConnectionNotifierThe Sip Connection notifier associated with this client connection | private javax.microedition.sip.SipRefreshListener | sipRefreshListenerCallback interface for refresh events | private String | refreshIDThe refresh ID of the refresh task associated with this client
connection if there is any | protected int | statecurrent state of this client transaction | private boolean | connectionOpenflag to know the state of the connection (open or close) | private Vector | credentialslist of credentials that can be used for authorization | private Request | requestThe request for this client transaction. | private Request | requestSavedBeforeACKThe initial request saved before ACK is sent. | private Response | responsethe response to the actual request | private Vector | responsesThe queue of responses for processing. | private Response | responseReceivedthe last received response | private SDPOutputStream | contentOutputStreamcontent of the response body | private InputStream | contentInputStreamcontent from the request body | private gov.nist.siplite.address.URI | requestURIThe request URI created from the user, host, port and
parameters attributes | private String | schemeScheme name | private String | userthe user part of the SIP URI | private String | hostthe host part of the SIP URI | private int | portthe port Number on which to send the request, part of
the SIP URI | private gov.nist.core.NameValueList | parametersthe parameters of the SIP URI | private String | userSipURIthe sip uri of the user | private gov.nist.siplite.stack.ClientTransaction | clientTransactionthe client Transaction for an INVITE request | private Thread | listeningThreadHandle for asynchronous listening thread. | private StackConnector | stackConnectorCurrent stack of connectors. | private boolean | isNotifierCreatedFlag of creating internal notifier. | private boolean | useRequestFlag indicating which SIP message (request or response)
should be used in getHeader()/getHeaders(). | protected boolean | enableInitCancelPermission of generating CANCEL request. | private int | countReoriginateRequestCount of authorization requests (RFC 2617, 3.2.2). |
Constructors Summary |
---|
protected SipClientConnectionImpl(gov.nist.siplite.address.SipURI inputURI, com.sun.midp.security.SecurityToken classSecurityToken)Creates a sip Client Connection to send a request to the
following SIP URI user@host:portNumber;parameters
this.user = inputURI.getUser();
this.host = inputURI.getHost();
this.port = inputURI.getPort();
this.parameters = inputURI.getUriParms();
this.classSecurityToken = classSecurityToken;
this.scheme = inputURI.getScheme();
connectionOpen = true;
credentials = new Vector();
try {
stackConnector = StackConnector.getInstance(classSecurityToken);
} catch (IOException ioe) {
}
// Create the REQUEST URI of the request
try {
requestURI = StackConnector.addressFactory.createURI(scheme + ":" +
((user == null) ? "" : (user + "@")) + host);
if (port != -1) {
((SipURI) requestURI).setPort(port);
}
// handle the parameters
if (parameters != null) {
Enumeration parNames = parameters.getKeys();
while (parNames.hasMoreElements()) {
String name = (String) parNames.nextElement();
String value = (String) parameters.getValue(name);
((SipURI) requestURI).setParameter(name, value);
}
}
} catch (ParseException pe) {
throw new
IllegalArgumentException("The request URI can not be" +
" created, check the URI syntax");
}
state = CREATED;
useRequest = true;
| protected SipClientConnectionImpl(gov.nist.siplite.address.URI requestURI, javax.microedition.sip.SipDialog sipDialog)Constructs the client connection implementation.
if (!requestURI.isSipURI()) {
throw new IllegalArgumentException("URI is not correct");
}
SipURI sipURI = (SipURI) requestURI;
SipDialogImpl sipDialogImpl = (SipDialogImpl) sipDialog;
user = sipURI.getUser();
host = sipURI.getHost();
port = sipURI.getPort();
parameters = sipURI.getUriParms();
classSecurityToken = sipDialogImpl.getSecurityToken();
scheme = requestURI.getScheme();
connectionOpen = true;
credentials = new Vector();
// Create the REQUEST URI of the request
this.requestURI = requestURI;
this.sipDialog = sipDialog;
this.refreshID = sipDialogImpl.getRefreshID();
// this.sipClientConnectionListener =
// ((SipDialogImpl)sipDialog).getSipClientConnectionListener();
try {
stackConnector = StackConnector.getInstance(classSecurityToken);
} catch (IOException ioe) {
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
"Could not create SipClientConnectionImpl: " +
ioe);
}
}
sipDialogImpl.dialog.setStack(stackConnector.getSipStack());
state = CREATED;
useRequest = true;
| private SipClientConnectionImpl(Request request, javax.microedition.sip.SipConnectionNotifier sipConnectionNotifier, String sipUserURI)Constructs the client connection implementation.
connectionOpen = true;
credentials = new Vector();
// Create the REQUEST of the connection
this.request = request;
this.userSipURI = sipUserURI;
// Create the REQUEST URI of the request
this.requestURI = request.getRequestURI();
this.sipConnectionNotifier = sipConnectionNotifier;
try {
stackConnector = StackConnector.getInstance(classSecurityToken);
} catch (IOException ioe) {
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
"Could not create SipClientConnectionImpl: " +
ioe);
}
}
if (request.getMethod().equals(Request.CANCEL)) {
state = INITIALIZED;
} else {
state = CREATED;
}
useRequest = true;
|
Methods Summary |
---|
public void | addHeader(java.lang.String name, java.lang.String value)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.
if (state != INITIALIZED) {
throw new SipException("the Header can not be add,"
+ " because of wrong state.",
SipException.INVALID_STATE);
}
if (name == null) {
throw new
IllegalArgumentException("The header name can not be null");
}
if (value == null) {
throw new
IllegalArgumentException("The header value can not be null");
}
Header header = null;
try {
header = StackConnector.headerFactory.createHeader(name, value);
} catch (ParseException pe) {
throw new IllegalArgumentException("The header can not be created,"
+ " check if it is correct");
}
request.addHeader(header);
| private void | changeClientConnectionState()Change the state of this Client Connection due to an incoming response.
// Change the Client Connection state
// If it's a trying, the state is PROCEEDING
if (responseReceived.getStatusCode() / 100 == 1
&& state == PROCEEDING) {
state = PROCEEDING;
}
// If it's a 401 or 407, the state is UNAUTHORIZED
else if (state == PROCEEDING &&
(responseReceived.getStatusCode() == Response.UNAUTHORIZED ||
responseReceived.getStatusCode() ==
Response.PROXY_AUTHENTICATION_REQUIRED)) {
state = UNAUTHORIZED;
}
// Otherwise this is COMPLETED
else {
state = COMPLETED;
}
| private void | changeDialogState()Change the state of the dialog due to an incoming response.
// Change the dialog state
// REGISTER method doesn't establish a dialog, so sipDialog
// should be null in this case.
// IMPL_NOTE: check if it is really null as supposed to be.
if (sipDialog == null) {
return;
}
SipDialogImpl sipDialogImpl = (SipDialogImpl) sipDialog;
String method = responseReceived.getCSeqHeader().getMethod();
if (!stackConnector.getSipStack().allowDialogStateChange(method)) {
return;
}
int statusCode = responseReceived.getStatusCode();
if (statusCode / 100 == 2) {
// RFC 3261, section 13.2.2.4:
// If the dialog identifier in the 2xx response matches the dialog
// identifier of an existing dialog, the dialog MUST be transitioned
// to the "confirmed" state.
// sipDialog cannot be null here - this check was done
// at the beginning of the function
sipDialogImpl.setState(SipDialog.CONFIRMED);
sipDialogImpl.setDialogID(responseReceived.getDialogId(false));
if (statusCode == 200) {
if (method.equals(Request.NOTIFY)) {
sipDialogImpl.handleNotify(request, null,
responseReceived.getDialogId(false));
return;
}
// handle the un-Subscribe state
if (method.equals(Request.SUBSCRIBE)) {
ExpiresHeader expiresHeader = (ExpiresHeader)
responseReceived.getHeader(ExpiresHeader.NAME);
// According to RFC3265, p. 6:
// "200-class responses to SUBSCRIBE requests also
// MUST contain an "Expires" header."
//
// But we have to handle a situation when it is missing.
// RFC 3265, p. 8:
// "200-class responses indicate that the subscription
// has been accepted".
//
// So, the dialog state is set to CONFIRMED even if
// no Expires header is present.
if (expiresHeader != null &&
expiresHeader.getExpires() == 0) { // unsubscribe
sipDialogImpl.terminateIfNoSubscriptions();
} else { // subscribe confirmation
sipDialogImpl.setState(SipDialog.CONFIRMED);
sipDialogImpl.setDialogID(
responseReceived.getDialogId(false));
}
} else if (method.equals(Request.BYE)) {
// IMPL_NOTE: check the RFC 3261. Probably we have to terminate
// the dialog for the responses other than 200 OK.
sipDialogImpl.setWaitForBye(false);
sipDialogImpl.terminateIfNoSubscriptions();
}
}
} else if (statusCode / 100 == 1) {
// provisional response
if (statusCode != 100) {
if (sipDialog.getState() == SipDialogImpl.INITIALIZED) {
// switch to EARLY state
sipDialogImpl.setState(SipDialog.EARLY);
}
/*
* Add a check to verify if it is reliable provisional
* response.
*/
Header requireHeader =
(ParameterLessHeader) responseReceived.getHeader(
Header.REQUIRE);
if (requireHeader != null) {
sipDialogImpl.isReliableProvReceived =
Header.isReliableTagPresent(
requireHeader.getHeaderValue());
}
// RFC 3261, 12.1:
// Within this specification, only 2xx and 101-199
// responses with a To tag ... will establish a dialog.
// set the dialog ID
sipDialogImpl.setDialogID(responseReceived.getDialogId(false));
}
} else { // another response code - switch to TERMINATED state
// Remove the subscription if any
sipDialogImpl.removeSubscription(response);
// JSR180 - not from CONFIRMED state
if (sipDialog.getState() != SipDialog.CONFIRMED) {
if (method.equals(Request.INVITE)) {
sipDialogImpl.setWaitForBye(false);
}
sipDialogImpl.terminateIfNoSubscriptions();
}
}
| protected void | clearResponse()Clears the current response.
this.response = null;
| public void | close()Close the clientconnection.
responses.removeAllElements(); // clear queue
// cleanup
if (isNotifierCreated && (sipConnectionNotifier != null)) {
// try {
sipConnectionNotifier.close();
// } catch (IOException exc) { // ignore
// }
}
// Removing the connection from the connection list held by
// the stackConnector
// StackConnector.getInstance().
// clientConnectionList.removeElement(this);
connectionOpen = false;
listeningThread = null;
state = TERMINATED;
| public int | enableRefresh(javax.microedition.sip.SipRefreshListener srl)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.
if (state != INITIALIZED) {
throw new SipException("can not enable the refresh,"
+ " because of wrong state.",
SipException.INVALID_STATE);
}
if (srl == null) {
return 0;
}
String method = request.getMethod();
if (!method.equals(Request.REGISTER) &&
!method.equals(Request.SUBSCRIBE) &&
!method.equals(Request.PUBLISH)) {
return 0;
}
// understand the refresh listener thing
sipRefreshListener = srl;
int taskID = RefreshManager
.getInstance()
.createRefreshTask(
request,
sipConnectionNotifier,
sipRefreshListener,
this);
refreshID = String.valueOf(taskID);
return taskID;
| protected java.lang.String | getCallIdentifier()Return the Call Identifier of this client connection
If there is no call id yet, this method return an empty String
if (request == null) {
return "";
}
return request.getCallIdentifier();
| protected gov.nist.siplite.stack.ClientTransaction | getClientTransaction()Gets the current client transaction.
return clientTransaction;
| public javax.microedition.sip.SipDialog | getDialog()Returns the current SIP dialog. This is available when the SipConnection
belongs to a created SipDialog and the system has received (or sent)
provisional (101-199) or final response (200).
if (sipDialog != null) {
byte dialogState = sipDialog.getState();
if ((dialogState != SipDialog.EARLY) &&
(dialogState != SipDialog.CONFIRMED)) {
return null;
}
}
return sipDialog;
| public java.lang.String | getHeader(java.lang.String name)Gets the header field value of specified header type.
Message currentMessage = useRequest ? (Message) request :
(Message) responseReceived;
if (currentMessage == null) {
// There 'request' may absent in the CREATED state
return null;
}
Header nameHeader = currentMessage.getHeader(name);
if (nameHeader == null) {
return null;
}
return nameHeader.getHeaderValue();
| public java.lang.String[] | getHeaders(java.lang.String name)Gets the header field value(s) of specified header type
Message currentMessage = useRequest ? (Message) request :
(Message) responseReceived;
if (currentMessage == null) {
// There 'request' may absent in the CREATED state
return null;
}
HeaderList nameList = currentMessage.getHeaderList(name);
if (nameList == null) {
return null;
}
int size = nameList.size();
if (size < 1) {
return null;
}
String[] headerValues = new String[size];
for (int count = 0; count < size; count++) {
headerValues[count] =
((Header) nameList.elementAt(count)).getHeaderValue();
}
return headerValues;
| public java.lang.String | getMethod()Gets the SIP method. Applicable when a message has been
initialized or received.
// another implementation returns null in terminated state; so do we
if (null == request || TERMINATED == state) {
return null;
} else {
return request.getMethod();
}
| public java.lang.String | getReasonPhrase()Gets SIP response reason phrase. Available when SipClientConnection is in
Proceeding or Completed state or when SipServerConnection is in
Initialized state.
if (state != PROCEEDING && state != COMPLETED && state != UNAUTHORIZED
|| responseReceived == null) {
return null;
} else {
return responseReceived.getReasonPhrase();
}
| public Request | getRequest()Gets the current request.
return request;
| public java.lang.String | getRequestURI()Gets Request-URI. 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)
if (state != INITIALIZED || request == null) {
return null;
} else {
return request.getRequestURI().toString();
}
| protected Response | getResponse()Gets the response.
return response;
| protected javax.microedition.sip.SipConnectionNotifier | getSipConnectionNotifier()Gets the assigned SipConnectionNotifier.
return sipConnectionNotifier;
| protected gov.nist.siplite.SipStack | getSipStack()Gets the current sip stack.
return stackConnector.getSipStack();
| public int | getState()Gets the current state of connection.
return state;
| public int | getStatusCode()Gets SIP response status code. Available when SipClientConnection is in
Proceeding or Completed state or when SipServerConnection is in
Initialized state.
if (responseReceived == null) {
return 0;
} else {
return responseReceived.getStatusCode();
}
| public void | handleMatchingNotify(Request notifyRequest)The stack connector notifies this class when it receive NOTIFY
request matching the previous SUBSCRIBE or REFER request.
SipDialogImpl sipDialogImpl = (SipDialogImpl) sipDialog;
int state = sipDialogImpl.getState();
SubscriptionStateHeader ssh = (SubscriptionStateHeader)
notifyRequest.getHeader(Header.SUBSCRIPTION_STATE);
boolean isUnsubscribe = (ssh != null && ssh.isTerminated());
if (state == SipDialogImpl.INITIALIZED ||
(state == SipDialogImpl.CONFIRMED && isUnsubscribe)) {
String dialogId = notifyRequest.getDialogId(false);
// sipDialogImpl.setState(isUnsubscribe ?
// SipDialog.TERMINATED : SipDialog.CONFIRMED);
sipDialogImpl.setDialogID(dialogId);
sipDialogImpl.handleNotify(notifyRequest, null, dialogId);
}
| public void | initAck()Convenience method to initialize SipClientConnection with SIP request
method ACK. ACK can be applied only to INVITE request.
if (state != COMPLETED) {
throw new SipException("the ACK request can not be initialized,"
+ " because of wrong state.",
SipException.INVALID_STATE);
}
// restore first request
if (requestSavedBeforeACK != null) {
request = requestSavedBeforeACK;
}
if (!request.getMethod().equals(Request.INVITE)) {
// original request is non-INVITE
throw new SipException("Original request is non-INVITE",
SipException.INVALID_OPERATION);
}
// JSR180: 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.
int statusCode = 0;
if (response != null) {
statusCode = response.getStatusCode() / 100;
} else if (responseReceived != null) {
statusCode = responseReceived.getStatusCode() / 100;
}
if (responseReceived.getStatusCode() / 100 > 2) {
throw new SipException("ACK request was already sent",
SipException.INVALID_OPERATION);
}
requestSavedBeforeACK = request; // save request
// This may throw SipException.
request = clientTransaction.createAck();
state = INITIALIZED;
useRequest = true;
| protected void | initBye()Initialize the session termination transaction.
// Generate Request
SipDialogImpl sipDialogImpl = (SipDialogImpl) sipDialog;
try {
request = sipDialogImpl.dialog.createRequest(Request.BYE);
// handle the parameters
if (parameters != null) {
Enumeration parNames = parameters.getKeys();
while (parNames.hasMoreElements()) {
String name = (String) parNames.nextElement();
String value = (String) parameters.getValue(name);
((SipURI) requestURI).setParameter(name, value);
}
}
} catch (SipException ex) {
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
"Could not create BYE request! " + ex);
}
} catch (ParseException pe) {
// intentionally ignored
// setParameter() is used with verified parameters
}
| public javax.microedition.sip.SipClientConnection | initCancel()Convenience method to initialize SipClientConnection with SIP request
method CANCEL.
if ((state != PROCEEDING) || !enableInitCancel) {
throw new SipException("the CANCEL request can not be initialized,"
+ " because of wrong state.",
SipException.INVALID_STATE);
}
// JSR180: The CANCEL request will be built according to
// the original INVITE request within this connection.
// Therefore building CANCEL request from not-INVITE
// original request is not allowed.
if (!request.getMethod().equals(Request.INVITE)) {
throw new SipException("The method of original request " +
"is not INVITE",
SipException.INVALID_OPERATION);
}
// init the cancel request
Request cancelRequest = clientTransaction.createCancel();
SipClientConnection sipClientConnectionCancel =
new SipClientConnectionImpl(
cancelRequest,
sipConnectionNotifier,
userSipURI);
// stackConnector.clientConnectionList.addElement(
// sipClientConnectionCancel);
return sipClientConnectionCancel;
| protected void | initNotify()Convenience method to initialize SipClientConnection with SIP request
method NOTIFY.
This method is copied from latest updates to NIST workspace
// don't call this method out of dialog
if (sipDialog == null) {
throw new IllegalArgumentException(
"Initialization NOTIFY request out of dialog");
}
// Generate Request
SipDialogImpl sipDialogImpl = (SipDialogImpl) sipDialog;
try {
request = sipDialogImpl.dialog.createRequest(Request.NOTIFY);
// handle the parameters
if (parameters != null) {
Enumeration parNames = parameters.getKeys();
while (parNames.hasMoreElements()) {
String name = (String) parNames.nextElement();
String value = (String) parameters.getValue(name);
((SipURI) requestURI).setParameter(name, value);
}
}
} catch (SipException ex) {
// IMPL_NOTE : cleanup
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
"Could not create the notify request! " + ex);
}
} catch (ParseException pe) {
// intentionally ignored
// setParameter() is used with verified parameters
}
| public void | initRequest(java.lang.String method, javax.microedition.sip.SipConnectionNotifier scn)Initializes the connection.
if (method == null) {
throw new IllegalArgumentException("The method can not be null");
}
if (state != CREATED) {
throw new SipException("the request can not be initialized," +
" because of wrong state.",
SipException.INVALID_STATE);
}
if ((state == CREATED) &&
((method.equals(Request.ACK)) ||
(method.equals(Request.CANCEL)))) {
throw new SipException("the request can not be initialized," +
" because of wrong state.",
SipException.INVALID_STATE);
}
if (!Lexer.isValidName(method)) {
throw new IllegalArgumentException("Invalid method: '" +
method + "'");
}
// Affect the sip connection notifier
if (scn != null) {
sipConnectionNotifier = scn;
} else {
String transport = parameters.getValueDefault(
SIPConstants.GENERAL_TRANSPORT, SIPConstants.TRANSPORT_UDP);
int localPort;
// see RFC 3261, 18.1.1 - selecting port number
if (transport.equalsIgnoreCase(SIPConstants.TRANSPORT_TLS)) {
localPort = SIPConstants.DEFAULT_TLS_PORT;
} else { // other transport protocol
localPort = SIPConstants.DEFAULT_NONTLS_PORT;
}
// Check if sipConnectionNotifier already exists on the same
// port. This is always true when UAC and UAS are in the same
// application and the user has opened a connection (like
// Connector.open("sip:5060");) before calling this function.
Vector connectionNotifiersList =
stackConnector.getConnectionNotifiersList();
try {
for (int i = 0; i < connectionNotifiersList.size(); i++) {
SipConnectionNotifier currNotifier =
(SipConnectionNotifier)
connectionNotifiersList.elementAt(i);
if ((currNotifier.getLocalPort() == localPort) &&
(((SipConnectionNotifierImpl) currNotifier).
getSipProvider().getListeningPoint().
getTransport().equalsIgnoreCase(transport))) {
sipConnectionNotifier = currNotifier;
break;
}
}
} catch (IOException ioe) {
throw new SipException(ioe.getMessage(),
SipException.GENERAL_ERROR);
}
if (sipConnectionNotifier == null) {
// Notifier was not found - create it.
try {
sipConnectionNotifier =
stackConnector.createSipConnectionNotifier(
localPort,
scheme.equals(SIPConstants.SCHEME_SIP),
transport, null);
} catch (IOException ioe) {
throw new SipException(ioe.getMessage(),
SipException.GENERAL_ERROR);
}
isNotifierCreated = true;
} // end if
} // end else (scn == null)
// redirect the methods ACK and CANCEL towards their helper
// methods
if (method.equals(Request.ACK)) {
initAck();
}
if (method.equals(Request.BYE) && (sipDialog != null)) {
initBye();
state = INITIALIZED;
useRequest = true;
return;
}
if (method.equals(Request.NOTIFY)) {
// if a dialog was not created, send NOTIFY out of dialog.
if (sipDialog != null) {
initNotify();
state = INITIALIZED;
useRequest = true;
return;
}
}
// Create request into dialog
if (sipDialog != null) {
byte dialogState = sipDialog.getState();
if ((dialogState == SipDialog.EARLY) ||
(dialogState == SipDialog.CONFIRMED)) {
if (method.equals(Request.PRACK) &&
(! ((SipDialogImpl) sipDialog).isReliableProvReceived)) {
return;
}
// if (sipDialog.getState() == SipDialog.CONFIRMED) {
// When SipDialog instance has CONFIRMED state, any new
// request should be inside of dialog and have same
// headers (To, From, Call-ID...) as original request.
try {
request =
((SipDialogImpl) sipDialog).dialog.createRequest(
method);
} catch (SipException ex) {
throw ex;
// throw new IllegalArgumentException(
// "Could not create the bye request! " + ex);
}
state = INITIALIZED;
useRequest = true;
return;
}
}
// We lookup in a record store to see whether or not there is
// the user sip uri
String sipURI = null;
try {
RecordStore rs = RecordStore.openRecordStore("UserSipUri", false);
RecordEnumeration re = rs.enumerateRecords(null, null, false);
if (re.hasNextElement()) {
int recordID = re.nextRecordId();
sipURI = new String(rs.getRecord(recordID));
}
} catch (RecordStoreException rse) {
// rse.printStackTrace();
}
// if the record store is null the sip uri for the user
// it is an anonymous sip uri
if (sipURI != null) {
userSipURI = sipURI;
}
Address userAddress = null;
try {
userAddress = StackConnector.addressFactory
.createAddress(userSipURI);
} catch (ParseException pe) {
throw new IllegalArgumentException("The system property UserSipUri"
+
"can not be parsed, check the syntax");
}
// Call ID
CallIdHeader callIdHeader = null;
String callId = SIPUtils.generateCallIdentifier
(stackConnector.getSipStack().getIPAddress());
callIdHeader = new CallIdHeader();
callIdHeader.setCallId(callId);
// CSeq
CSeqHeader cSeqHeader = null;
try {
cSeqHeader = StackConnector.headerFactory.createCSeqHeader(1,
method);
} catch (ParseException pe) {
throw new SipException("Problem during the creation" +
" of the CSeqHeader",
SipException.GENERAL_ERROR);
}
// From
FromHeader fromHeader = null;
try {
fromHeader = StackConnector
.headerFactory
.createFromHeader(
userAddress,
StackConnector.generateTag());
} catch (ParseException ex) {
throw new SipException("Problem during the creation" +
" of the FromHeader",
SipException.GENERAL_ERROR);
}
// ToHeader
Address toAddress = StackConnector
.addressFactory.createAddress(
requestURI);
ToHeader toHeader = null;
try {
toHeader = StackConnector
.headerFactory.createToHeader(
toAddress, null);
} catch (ParseException ex) {
throw new SipException("Problem during the creation" +
" of the ToHeader",
SipException.GENERAL_ERROR);
}
// ViaHeader
Vector viaHeaders = new Vector();
String viaLocalAddress;
String viaTransport;
int viaLocalPort;
try {
viaLocalAddress = sipConnectionNotifier.getLocalAddress();
viaLocalPort = sipConnectionNotifier.getLocalPort();
viaTransport =
((SipConnectionNotifierImpl) sipConnectionNotifier)
.getSipProvider().getListeningPoint().getTransport();
} catch (IOException ioe) {
throw new SipException("Internal Error, cannot get " +
"the local port or address",
SipException.GENERAL_ERROR);
}
try {
ViaHeader viaHeader = StackConnector
.headerFactory
.createViaHeader(
viaLocalAddress,
viaLocalPort,
viaTransport,
SIPUtils.generateBranchId());
viaHeaders.addElement(viaHeader);
} catch (ParseException ex) {
throw new SipException("Problem during the creation" +
" of the ViaHeaders",
SipException.GENERAL_ERROR);
}
// Max Forward Header
MaxForwardsHeader maxForwardsHeader =
StackConnector.headerFactory.createMaxForwardsHeader(70);
// generate the request
try {
request = StackConnector
.messageFactory.createRequest(
requestURI,
method,
callIdHeader,
cSeqHeader,
fromHeader,
toHeader,
viaHeaders,
maxForwardsHeader);
} catch (ParseException ex) {
throw new SipException("Problem during the creation " +
" of the Request " + method,
SipException.GENERAL_ERROR);
}
/*
* Contact header - not in MESSAGE request (RFC 3428, 4).
* RFC 3903, p. 5:
* The PUBLISH request MAY contain a Contact header field, but including
* one in a PUBLISH request has no meaning in the event publication
* context and will be ignored by the ESC (Event State Compositor).
*/
if (!method.equals(Request.MESSAGE) &&
!method.equals(Request.PUBLISH)) {
ContactHeader contactHeader = null;
try {
if (isNotifierCreated) {
// Notifier was not passed as an argument to initRequest()
SipURI contactURI = StackConnector
.addressFactory
.createSipURI("anonymous", // name
viaLocalAddress);
contactURI.setTransportParam(viaTransport);
contactURI.setPort(viaLocalPort);
contactHeader =
StackConnector
.headerFactory
.createContactHeader(
StackConnector
.addressFactory
.createAddress(contactURI));
} else { // notifier is given
SipURI contactURI = StackConnector
.addressFactory
.createSipURI(
userSipURI
.substring(scheme.length() + 1,
userSipURI.indexOf("@")),
sipConnectionNotifier.getLocalAddress());
contactURI
.setTransportParam(
((SipConnectionNotifierImpl)
sipConnectionNotifier).
getSipProvider().getListeningPoint()
.getTransport());
contactHeader =
StackConnector
.headerFactory
.createContactHeader(
StackConnector
.addressFactory
.createAddress(contactURI));
contactURI.setPort(sipConnectionNotifier.getLocalPort());
}
} catch (IOException ioe) {
throw new SipException("Internal Error, cannot get " +
"the local port or address",
SipException.GENERAL_ERROR);
} catch (ParseException ex) {
throw new SipException("Problem during the creation " +
"of the Contact Header",
SipException.GENERAL_ERROR);
}
// set the header
request.addHeader(contactHeader);
}
state = INITIALIZED;
useRequest = true;
| protected void | notifyResponseReceived(Response response, gov.nist.siplite.stack.ClientTransaction inputClientTransaction)The stack connector notifies this class when it receive a new response.
// System.out.println(">>> Response received : \n" + response);
int statusCode = response.getStatusCode();
int statusGroup = statusCode / 100;
boolean ignoreResponse = false;
if (state == COMPLETED) { // 2xx responses only
if (statusGroup != 2) {
ignoreResponse = true;
}
} else if (state == PROCEEDING) {
// If there is some credentials and the client connection is in an
// UNAUTHORIZED state, the request is reoriginate automatically
if (credentials.size() > 0 &&
((statusCode == Response.UNAUTHORIZED) ||
(statusCode == Response.PROXY_AUTHENTICATION_REQUIRED))) {
this.responseReceived = response;
if (sipDialog != null) {
((SipDialogImpl) sipDialog).setState(SipDialog.TERMINATED);
}
reoriginateRequest();
ignoreResponse = true;
}
} else { // not COMPLETED and PROCEEDING
ignoreResponse = true;
}
// check the queue size
if (responses.size() > MAX_NUM_RESPONSES) {
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
"Queue of incoming SIP packets is overflow");
}
ignoreResponse = true;
}
if (ignoreResponse) { // ignore response
return;
}
IncomingQueueElement incomingElement =
new IncomingQueueElement(response, inputClientTransaction);
responses.addElement(incomingElement); // put to queue
this.response = response;
if (state == PROCEEDING) {
if (statusGroup == 1) {
// provisional response
// JSR180: SipClientConnection: initCancel: The method is
// available when a provisional response
// has been received.
enableInitCancel = true;
} else {
// All responses from 200-699 are final
// JSR180: SipClientConnection: initCancel:
// Throws: SipException - INVALID_STATE if ... or the system
// has already got the 200 OK response (even if not read with
// receive() method).
enableInitCancel = false;
}
}
if (response.getCSeqHeaderNumber() == request.getCSeqHeaderNumber()) {
synchronized (this) {
notify();
}
// We notify the listener that a response has been received
if (sipClientConnectionListener != null) {
sipClientConnectionListener.notifyResponse(this);
}
}
String method = response.getCSeqHeader().getMethod();
if (method.equals(Request.PUBLISH)) {
// RFC 3903, p. 6:
// When updating previously published event state, PUBLISH
// requests MUST contain a single SIP-If-Match header field
// identifying the specific event state that the request is
// refreshing, modifying or removing. This header field MUST
// contain a single entity-tag that was returned by the ESC
// in the SIP-ETag header field of the response to a previous
// publication.
Header hEtag = response.getHeader(Header.SIP_ETAG);
if (hEtag != null) {
Header hIfMatch = request.getHeader(Header.SIP_IF_MATCH);
if (hIfMatch == null) {
Exception ex = null;
// Create SIP_IF_MATCH header
try {
hIfMatch = StackConnector.headerFactory.createHeader(
Header.SIP_IF_MATCH, hEtag.getHeaderValue());
request.addHeader(hIfMatch);
} catch (NullPointerException npe) {
ex = npe;
} catch (ParseException pe) {
ex = pe;
} catch (SipException se) {
ex = se;
}
if (ex != null) {
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR,
LogChannels.LC_JSR180,
"scc.notifyResponseReceived(): can't create " +
"SIP-If-Match header:" + ex);
ex.printStackTrace();
}
}
} else {
hIfMatch.setHeaderValue(hEtag.getHeaderValue());
}
request.removeHeader(Header.SIP_ETAG);
} else {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
"scc.notifyResponseReceived(): response to PUBLISH " +
"doesn't contain SIP-Etag header!");
}
}
}
// Schedule the refresh if required (i.e., if the method is
// refreshable). Refresh time is taken from the response,
// either from Expires header or from "expires" parameter
// of Contact header as described in RFCs 3261, section 10.2.4
// and RFC 3265, section 3.1.1.
// If a listener for refresh event has been set, it is notified.
if (statusCode == Response.OK) {
scheduleRefresh(method);
}
// Notify the listener
if (refreshID != null) {
sipRefreshListener.refreshEvent(Integer.parseInt(refreshID),
statusCode,
response.getReasonPhrase());
}
| public java.io.InputStream | openContentInputStream()Returns InputStream to read SIP message body content.
String errStateMsg = "the content input stream can not be open, " +
"because of wrong state.";
if ((state != COMPLETED) && (state != PROCEEDING)) {
throw new SipException(errStateMsg, SipException.INVALID_STATE);
}
if (!connectionOpen) {
throw new IOException("The Connection has been closed!");
}
if (responseReceived == null) {
// Although openContentInputStream() is called in the correct
// user-level state, we may have a situation when this method
// is called before the response was received. In this case
// the internal state of SCC is invalid and the proper exception
// to throw is SipException.INVALID_STATE.
throw new SipException(errStateMsg, SipException.INVALID_STATE);
}
ContentLengthHeader contentLengthHeader =
responseReceived.getContentLengthHeader();
if (contentLengthHeader == null) {
throw new
IOException("Response contains no content length header.");
}
int bodyLength = contentLengthHeader.getContentLength();
if (bodyLength == 0) {
throw new IOException("Response's body has zero length.");
}
byte[] buf = responseReceived.getRawContent();
if (buf == null) { // body is empty
throw new IOException("Body of SIP response is empty.");
}
contentInputStream = new ByteArrayInputStream(buf);
return contentInputStream;
| public java.io.OutputStream | openContentOutputStream()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(). Again send() must
not be called after closing the OutputStream, since it will throw
Exception because of calling the method in wrong state.
Before opening OutputStream the Content-Length and Content-Type headers
has to se set. If not SipException.UNKNOWN_LENGTH or
SipException.UNKNOWN_TYPE will be thrown respectively.
if (state != INITIALIZED) {
throw new SipException("the content output stream can not be open,"
+ " because of wrong state.",
SipException.INVALID_STATE);
}
if (request.getHeader(Header.CONTENT_TYPE) == null) {
throw new SipException(
"Content-Type unknown, set the content-type "
+ "header first",
SipException.UNKNOWN_TYPE);
}
if (request.getHeader(Header.CONTENT_LENGTH) == null) {
throw new SipException("Content-Length unknown, set the "
+ "content-length header first",
SipException.UNKNOWN_LENGTH);
}
if (!connectionOpen) {
throw new IOException("The Connection has been closed!");
}
contentOutputStream = new SDPOutputStream(this);
state = STREAM_OPEN;
return contentOutputStream;
| public boolean | receive(long timeout)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.
if ((state != PROCEEDING) && (state != COMPLETED)) {
throw new SipException(SipException.INVALID_STATE);
}
// check for a response
if (responses.isEmpty()) {
// wait for a response during the time specified by the timeout
if (timeout != 0) {
synchronized (this) {
try {
// listeningThread.sleep(timeout);
wait(timeout);
} catch (InterruptedException ie) {
}
}
}
}
if (responses.isEmpty()) {
return false; // queue is empty
}
// get first response from queue
IncomingQueueElement incomingElement =
(IncomingQueueElement) responses.firstElement();
responseReceived = incomingElement.getResponse();
responses.removeElementAt(0); // remove from queue
useRequest = false;
// change client transaction if need
if (incomingElement.containsClientTransaction()) {
clientTransaction = incomingElement.getClientTransaction();
}
if ((responseReceived.getStatusCode() / 100 == 2) &&
(state == COMPLETED)) { // multiple responses
// change dialog
sipDialog = new SipDialogImpl(clientTransaction.getDialog(),
sipConnectionNotifier,
classSecurityToken);
// transaction is INVITE, checked in
// ClientTransaction.isMessageTransOrMult()
((SipDialogImpl) sipDialog).setWaitForBye(true);
((SipDialogImpl) sipDialog).setState(SipDialog.CONFIRMED);
}
changeDialogState();
changeClientConnectionState();
return true;
| public void | removeHeader(java.lang.String name)Reomves header from the SIP message. If multiple header field
values exist
the topmost is removed.
The implementations MAY restrict the access to some headers
according to RFC 3261.
If the named header is not found this method does nothing.
if (state != INITIALIZED) {
throw new SipException("the Header can not be removed,"
+ " because of wrong state.",
SipException.INVALID_STATE);
}
if (name == null) {
throw new
IllegalArgumentException("The header name can not be null");
}
request.removeHeader(name, true);
| private void | reoriginateRequest()Reoriginate the request with the proper credentials
// clear dialog
if (sipDialog != null) {
if (sipDialog.getState() == SipDialog.TERMINATED) {
sipDialog = null;
}
}
DigestClientAuthentication authentication =
new DigestClientAuthentication(credentials);
// Reoriginate the request with the proper credentials
Request newRequest = authentication.createNewRequest(
stackConnector.sipStack,
this.request,
this.responseReceived,
this.countReoriginateRequest);
if (newRequest != null) {
this.countReoriginateRequest++;
this.request = newRequest;
// The request has been reinitialized...
state = INITIALIZED;
useRequest = true;
// ...so it is sent out
try {
this.send();
} catch (IOException ioe) {
// ioe.printStackTrace();
}
}
| private void | scheduleRefresh(java.lang.String method)Schedules refreshing of the request if required.
if (sipRefreshListener == null) {
return;
}
if (! (method.equals(Request.REGISTER) ||
method.equals(Request.SUBSCRIBE) ||
method.equals(Request.PUBLISH))) {
return;
}
// Remove the body of the message in case if the request is PUBLISH,
// see RFC 3903, p. 7 (section 4.1):
// +-----------+-------+---------------+---------------+
// | Operation | Body? | SIP-If-Match? | Expires Value |
// +-----------+-------+---------------+---------------+
// | Initial | yes | no | > 0 |
// | Refresh | no | yes | > 0 |
// | Modify | yes | yes | > 0 |
// | Remove | no | yes | 0 |
// +-----------+-------+---------------+---------------+
if (method.equals(Request.PUBLISH)) {
request.removeContent();
}
// If the expires is set, the refresh is scheduled for the
// duration of the expires
int expires, minExpires = Integer.MAX_VALUE;
// RFC 3265, p. 6:
// An "expires" parameter on the "Contact" header has no semantics for
// SUBSCRIBE and is explicitly not equivalent to an "Expires" header in
// a SUBSCRIBE request or response.
if (!method.equals(Request.SUBSCRIBE)) {
ContactList cl = response.getContactHeaders();
if (cl != null) {
// Take a minimal expiration time from Contact headers.
Enumeration en = cl.getElements();
while (en.hasMoreElements()) {
ContactHeader contactHeader =
(ContactHeader) en.nextElement();
if (contactHeader != null) {
try {
expires = Integer.parseInt(
contactHeader.getExpires());
if ((expires > 0) && (expires < minExpires)) {
minExpires = expires;
}
} catch (NumberFormatException e) {
// intentionally ignored
// in the worst case
// minExpires = Integer.MAX_VALUE
}
}
}
}
} // end if (not SUBSCRIBE)
// Take an expiration time from the Expires header.
ExpiresHeader expiresHeader =
(ExpiresHeader) response.getHeader(ExpiresHeader.NAME);
if (expiresHeader != null) {
expires = expiresHeader.getExpires();
if ((expires > 0) && (expires < minExpires)) {
minExpires = expires;
}
}
if (minExpires == Integer.MAX_VALUE || minExpires < 0) {
// Apply defaults.
minExpires = 3600;
}
// System.out.println(">>> Refresh time: " + minExpires);
/*
if (expiresHeader != null) {
expires = expiresHeader.getExpires();
System.out.println(">>> From header: " + expires);
}
*/
if (minExpires != 0) {
RefreshManager.getInstance().scheduleTask(refreshID, minExpires);
}
| public void | send()Sends the SIP message. Send must also close the OutputStream
if it was opened.
sendRequestImpl(false);
| private void | sendRequestImpl(boolean isRefreshRequest)This function is an implementation for send(). It sends the SIP message.
Send must also close the OutputStream if it was opened.
if (state != STREAM_OPEN && state != INITIALIZED) {
throw new SipException("can not send the request, " +
"because of wrong state.",
SipException.INVALID_STATE);
}
if (!connectionOpen) {
throw new IOException("The Connection has been closed!");
}
if (contentOutputStream != null) {
contentOutputStream.setOpen(false);
request.setContent(
contentOutputStream.getByteArrayOutputStream().toByteArray(),
(ContentTypeHeader) request.getHeader(Header.CONTENT_TYPE));
contentOutputStream = null;
}
// Check mandatory headers (RFC3261, 8.1.1)
String[] mandatoryHeaders = {
Header.TO, Header.FROM, Header.CSEQ,
Header.CALL_ID, Header.MAX_FORWARDS, Header.VIA};
Vector mandatoryList = new Vector();
// add header names for all types of requests
for (int i = 0; i < mandatoryHeaders.length; i++) {
mandatoryList.addElement(mandatoryHeaders[i]);
}
String method = request.getMethod();
// RFC 3515, p. 6:
// A REFER request MUST contain exactly one Refer-To header field value.
if (method.equals(Request.REFER)) {
mandatoryList.addElement(Header.REFER_TO);
}
// RFC3265, p. 15:
// NOTIFY requests MUST contain a "Subscription-State" header with
// a value of "active", "pending", or "terminated".
if (method.equals(Request.NOTIFY)) {
mandatoryList.addElement(Header.SUBSCRIPTION_STATE);
}
for (int i = 0; i < mandatoryList.size(); i++) {
if (request.getHeader(
(String) mandatoryList.elementAt(i)) == null) {
throw new SipException("Header " +
(String) mandatoryList.elementAt(i) +
" is missed", SipException.INVALID_STATE);
}
}
// add "tag" parameter to "From" header if necessary
FromHeader fromHeader = (FromHeader) request.getHeader(Header.FROM);
// it is not null - please see above
if (!fromHeader.hasTag()) { // no "tag" parameter
fromHeader.setTag(StackConnector.generateTag());
}
// Request-URI
// Fix added per NIST cvs digest dated July 3, 2005
// RFC 3261, 10.2:
// Request-URI: ... The "userinfo" and "@" components of the
// SIP URI MUST NOT be present.
if (method.equals(Request.REGISTER)) {
Address reqUriAddress = null;
try {
reqUriAddress =
StackConnector.addressFactory.createAddress(
requestURI.toString());
if (reqUriAddress.isSIPAddress()) {
((SipURI) reqUriAddress.getURI()).removeUser();
requestURI = reqUriAddress.getURI();
}
request.setRequestURI(requestURI);
} catch (ParseException pe) {
throw new SipException(
"The system property UserSipUri can not be " +
"parsed, check the syntax",
SipException.INVALID_OPERATION);
}
}
// Check that the parameters specified in Via header match
// those which were set in sipConnectionNotifier.
ViaHeader requestViaHeader =
(ViaHeader) request.getViaHeaders().getFirst();
int viaPort = requestViaHeader.getPort();
int localPort = sipConnectionNotifier.getLocalPort();
String transport = requestViaHeader.getTransport();
if (localPort != viaPort) {
throw new IOException("Via port (" + viaPort + ") doesn't " +
"match the listener's port (" + localPort +
")!");
}
SipConnectionNotifierImpl notifierImpl =
(SipConnectionNotifierImpl) sipConnectionNotifier;
if (!notifierImpl.getSipProvider().getListeningPoint().
getTransport().equalsIgnoreCase(transport)) {
throw new IOException("Via transport doesn't match " +
"the listener's transport!");
}
// RFC 3903 (PUBLISH method), p. 5:
// The Record-Route header field has no meaning in PUBLISH
// requests or responses, and MUST be ignored if present.
if (method.equals(Request.PUBLISH)) {
request.removeHeader(Header.RECORD_ROUTE);
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
"Request to be sent : " + request);
}
// System.out.println(">>> Request to be sent: \n" + request);
// Creates the Nist-Siplite client Transaction for this
// request
try {
clientTransaction =
((SipConnectionNotifierImpl) sipConnectionNotifier).
getSipProvider().getNewClientTransaction(request);
} catch (TransactionUnavailableException tue) {
throw new SipException("Cannot create a new Client " +
" Transaction for this request",
SipException.TRANSACTION_UNAVAILABLE);
} catch (IllegalArgumentException iae) {
throw new SipException("SCC.send(): IAE occured (1): " +
iae.getMessage(), SipException.GENERAL_ERROR);
} catch (NullPointerException npe) {
throw new SipException("SCC.send(): NPE occured (1): " +
npe.getMessage(), SipException.GENERAL_ERROR);
}
// Set the application data so that when the response comes in,
// it will retrieve this SipClientConnection
clientTransaction.setApplicationData(this);
// Send the request
if (method.equals(Request.ACK)) {
Dialog dlg = clientTransaction.getDialog();
if (dlg.isServer()) {
// Switch from server side to client side for re-invite
dlg.addTransaction(clientTransaction);
}
try {
dlg.sendAck(request);
} catch (IllegalArgumentException iae) {
throw new SipException("SCC.send(): can't send ACK: " + iae,
SipException.GENERAL_ERROR);
}
state = COMPLETED;
return;
} else if (sipDialog != null && !isRefreshRequest) {
// if (method.equals(Request.BYE) ||
// method.equals(Request.NOTIFY)) {
// If the request is a BYE, we must send it with the dialog
// If the dialog is established, all further requests should
// be sent within it.
SipDialogImpl sipDialogImpl = (SipDialogImpl) sipDialog;
if (method.equals(Request.SUBSCRIBE) ||
method.equals(Request.REFER)) {
// Add a subscription
sipDialogImpl.addSubscription(
new Subscription(sipDialogImpl.getDialog(), request));
} else if (method.equals(Request.INVITE)) {
sipDialogImpl.setWaitForBye(true);
}
sipDialogImpl.dialog.sendRequest(clientTransaction);
state = PROCEEDING;
return;
} else {
clientTransaction.sendRequest();
}
// An INVITE, SUBSCRIBE or REFER has been sent, so a dialog need to
// be created.
if (stackConnector.getSipStack().isDialogCreated(method) &&
!isRefreshRequest) {
sipDialog = new SipDialogImpl(clientTransaction.getDialog(),
sipConnectionNotifier,
classSecurityToken);
SipDialogImpl sipDialogImpl = (SipDialogImpl) sipDialog;
sipDialogImpl.setRefreshID(refreshID);
sipDialogImpl.setSipClientConnectionListener(
sipClientConnectionListener);
stackConnector.sipDialogList.addElement(sipDialog);
// Add a subscription
if (!method.equals(Request.INVITE)) {
sipDialogImpl.addSubscription(
new Subscription(sipDialogImpl.getDialog(), request));
} else {
sipDialogImpl.setWaitForBye(true);
}
}
// If the method is a REGISTER it means that we are using a
// proxy so we put put the route of the proxy in the router
if (request.getMethod().equals(Request.REGISTER)) {
SipURI sipURI = (SipURI) request.getRequestURI();
int requestPort = sipURI.getPort();
if (requestPort == -1) { // get port from sipConnectionNotifier
requestPort = sipConnectionNotifier.getLocalPort();
}
String requestTransport = sipURI.getTransportParam();
if ((requestTransport == null) ||
(requestTransport.length() < 1)) {
// get transport from sipConnectionNotifier
requestTransport =
((SipConnectionNotifierImpl) sipConnectionNotifier).
getSipProvider().getListeningPoint().getTransport();
}
stackConnector.sipStack.getRouter().setOutboundProxy(
sipURI.getHost()
+ ":" + requestPort
+ "/"
+ requestTransport);
// outboundProxy = true;
}
// Refresh must be scheduled after receiving a response,
// refer the comments at the end of notifyResponseReceived().
// scheduleRefresh(request.getMethod(), request, false);
state = PROCEEDING;
| public void | setCredentials(java.lang.String username, java.lang.String password, java.lang.String realm)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:
before sending the original request in Initialized state.
The API implementation caches the credentials for later use.
when 401 (Unauthorized) or 407 (Proxy Authentication Required) response
is received in the Unauthorized state. The API implementation uses the
given credentials to re-originate the request with proper authorization
header. After that the SipClientConnection will be in Proceeding state.
if (state != INITIALIZED && state != UNAUTHORIZED) {
throw new SipException("can not set the credentials, " +
"because of wrong state.",
SipException.INVALID_STATE);
}
if (username == null || password == null || realm == null) {
throw new NullPointerException();
}
Credentials credential = new Credentials(username, password, realm);
credentials.addElement(credential);
// reoriginate the requests with the proper credentials
if (state == UNAUTHORIZED) {
reoriginateRequest();
}
| public void | setHeader(java.lang.String name, java.lang.String value)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.
if (state != INITIALIZED) {
throw new SipException("the Header can not be set,"
+ " because of wrong state.",
SipException.INVALID_STATE);
}
if (name == null) {
throw new
IllegalArgumentException("The header name can not be null");
}
if (value == null) {
throw new
IllegalArgumentException("The header value can not be null");
}
Header header = null;
try {
header = StackConnector.headerFactory.createHeader(name, value);
// name = header.getName(); // The source name might be expanded
} catch (ParseException pe) {
throw new IllegalArgumentException(pe.getMessage());
}
if (header == null) {
throw new IllegalArgumentException("null header!");
}
// Response doesn't exist in the INITIALIZED state, so here
// it's clear which message (request or response) to use.
request.attachHeader(header, true, true);
/*
if (request.getHeader(name) == null) {
request.addHeader(header);
} else {
request.attachHeader(header, true, true);
}
*/
| public void | setListener(javax.microedition.sip.SipClientConnectionListener sccl)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.
if (!connectionOpen) {
throw new IOException("The Connection has been closed!");
}
this.sipClientConnectionListener = sccl;
| public void | setRequestURI(java.lang.String newUri)Sets Request-URI explicitly. Request-URI can be set only in
Initialized state.
if (state != INITIALIZED) {
throw new SipException("the request URI can not be set, " +
" because of wrong state.",
SipException.INVALID_STATE);
}
if (newUri == null) {
throw new IllegalArgumentException("Invalid URI");
}
URI uri = null;
try {
uri = StackConnector.addressFactory.createURI(newUri);
} catch (ParseException pe) {
throw new IllegalArgumentException("Invalid URI");
}
request.setRequestURI(uri);
requestURI = uri;
| protected void | updateAndSendRequestFromRefresh(Request updatedRequest)Updates and sends the request from the refresh.
request = updatedRequest;
state = INITIALIZED;
// If the request to be refreshed creates a dialog (i.e. SUBSCRIBE),
// the next request will be sent within a dialog using the rules for
// sending in-dialog requests. To avoid it, isRefreshRequest parameter
// is used.
sendRequestImpl(true);
| protected java.io.OutputStream | updateRequestAndOpenOutputStream(Request updatedRequest)Updates the request and calls openContentOutputStream()
to fill the new message body.
request = updatedRequest;
state = INITIALIZED;
return openContentOutputStream();
|
|