use of gov.nist.javax.sip.message.SIPResponse in project XobotOS by xamarin.
the class SIPDialog method handlePrack.
/**
* Do the processing necessary for the PRACK
*
* @param prackRequest
* @return true if this is the first time the tx has seen the prack ( and hence needs to be
* passed up to the TU)
*/
public boolean handlePrack(SIPRequest prackRequest) {
/*
* The RAck header is sent in a PRACK request to support reliability of provisional
* responses. It contains two numbers and a method tag. The first number is the value from
* the RSeq header in the provisional response that is being acknowledged. The next
* number, and the method, are copied from the CSeq in the response that is being
* acknowledged. The method name in the RAck header is case sensitive.
*/
if (!this.isServer()) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Dropping Prack -- not a server Dialog");
return false;
}
SIPServerTransaction sipServerTransaction = (SIPServerTransaction) this.getFirstTransaction();
SIPResponse sipResponse = sipServerTransaction.getReliableProvisionalResponse();
if (sipResponse == null) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Dropping Prack -- ReliableResponse not found");
return false;
}
RAck rack = (RAck) prackRequest.getHeader(RAckHeader.NAME);
if (rack == null) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Dropping Prack -- rack header not found");
return false;
}
CSeq cseq = (CSeq) sipResponse.getCSeq();
if (!rack.getMethod().equals(cseq.getMethod())) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Dropping Prack -- CSeq Header does not match PRACK");
return false;
}
if (rack.getCSeqNumberLong() != cseq.getSeqNumber()) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Dropping Prack -- CSeq Header does not match PRACK");
return false;
}
RSeq rseq = (RSeq) sipResponse.getHeader(RSeqHeader.NAME);
if (rack.getRSequenceNumber() != rseq.getSeqNumber()) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Dropping Prack -- RSeq Header does not match PRACK");
return false;
}
return sipServerTransaction.prackRecieved();
}
use of gov.nist.javax.sip.message.SIPResponse in project XobotOS by xamarin.
the class SIPDialog method createReliableProvisionalResponse.
/*
* (non-Javadoc)
*
* @see javax.sip.Dialog#createReliableProvisionalResponse(int)
*/
public Response createReliableProvisionalResponse(int statusCode) throws InvalidArgumentException, SipException {
if (!(firstTransactionIsServerTransaction)) {
throw new SipException("Not a Server Dialog!");
}
/*
* A UAS MUST NOT attempt to send a 100 (Trying) response reliably. Only provisional
* responses numbered 101 to 199 may be sent reliably. If the request did not include
* either a Supported or Require header field indicating this feature, the UAS MUST NOT
* send the provisional response reliably.
*/
if (statusCode <= 100 || statusCode > 199)
throw new InvalidArgumentException("Bad status code ");
SIPRequest request = this.originalRequest;
if (!request.getMethod().equals(Request.INVITE))
throw new SipException("Bad method");
ListIterator<SIPHeader> list = request.getHeaders(SupportedHeader.NAME);
if (list == null || !optionPresent(list, "100rel")) {
list = request.getHeaders(RequireHeader.NAME);
if (list == null || !optionPresent(list, "100rel")) {
throw new SipException("No Supported/Require 100rel header in the request");
}
}
SIPResponse response = request.createResponse(statusCode);
/*
* The provisional response to be sent reliably is constructed by the UAS core according
* to the procedures of Section 8.2.6 of RFC 3261. In addition, it MUST contain a Require
* header field containing the option tag 100rel, and MUST include an RSeq header field.
* The value of the header field for the first reliable provisional response in a
* transaction MUST be between 1 and 2**31 - 1. It is RECOMMENDED that it be chosen
* uniformly in this range. The RSeq numbering space is within a single transaction. This
* means that provisional responses for different requests MAY use the same values for the
* RSeq number.
*/
Require require = new Require();
try {
require.setOptionTag("100rel");
} catch (Exception ex) {
InternalErrorHandler.handleException(ex);
}
response.addHeader(require);
RSeq rseq = new RSeq();
/*
* set an arbitrary sequence number. This is actually set when the response is sent out
*/
rseq.setSeqNumber(1L);
/*
* Copy the record route headers from the request to the response ( Issue 160 ). Note that
* other 1xx headers do not get their Record Route headers copied over but reliable
* provisional responses do. See RFC 3262 Table 2.
*/
RecordRouteList rrl = request.getRecordRouteHeaders();
if (rrl != null) {
RecordRouteList rrlclone = (RecordRouteList) rrl.clone();
response.setHeader(rrlclone);
}
return response;
}
use of gov.nist.javax.sip.message.SIPResponse in project XobotOS by xamarin.
the class SIPServerTransaction method sendMessage.
/**
* Send a response message through this transactionand onto the client. The response drives
* the state machine.
*
* @param messageToSend Response to process and send.
*/
public void sendMessage(SIPMessage messageToSend) throws IOException {
try {
// Message typecast as a response
SIPResponse transactionResponse;
// Status code of the response being sent to the client
int statusCode;
// Get the status code from the response
transactionResponse = (SIPResponse) messageToSend;
statusCode = transactionResponse.getStatusCode();
try {
// outgoing via.
if (this.getOriginalRequest().getTopmostVia().getBranch() != null)
transactionResponse.getTopmostVia().setBranch(this.getBranch());
else
transactionResponse.getTopmostVia().removeParameter(ParameterNames.BRANCH);
// transaction rsponse.
if (!this.getOriginalRequest().getTopmostVia().hasPort())
transactionResponse.getTopmostVia().removePort();
} catch (ParseException ex) {
ex.printStackTrace();
}
// create the transaction - transaction state does not change.
if (!transactionResponse.getCSeq().getMethod().equals(getOriginalRequest().getMethod())) {
sendResponse(transactionResponse);
return;
}
if (getRealState() == TransactionState.TRYING) {
if (statusCode / 100 == 1) {
this.setState(TransactionState.PROCEEDING);
} else if (200 <= statusCode && statusCode <= 699) {
// check is necessary.
if (!isInviteTransaction()) {
if (!isReliable()) {
// Linger in the completed state to catch
// retransmissions if the transport is not
// reliable.
this.setState(TransactionState.COMPLETED);
// Note that Timer J is only set for Unreliable
// transports -- see Issue 75.
/*
* From RFC 3261 Section 17.2.2 (non-invite server transaction)
*
* When the server transaction enters the "Completed" state, it MUST
* set Timer J to fire in 64*T1 seconds for unreliable transports, and
* zero seconds for reliable transports. While in the "Completed"
* state, the server transaction MUST pass the final response to the
* transport layer for retransmission whenever a retransmission of the
* request is received. Any other final responses passed by the TU to
* the server transaction MUST be discarded while in the "Completed"
* state. The server transaction remains in this state until Timer J
* fires, at which point it MUST transition to the "Terminated" state.
*/
enableTimeoutTimer(TIMER_J);
} else {
this.setState(TransactionState.TERMINATED);
}
} else {
// this is treated the same as as Proceeding.
if (statusCode / 100 == 2) {
// Status code is 2xx means that the
// transaction transitions to TERMINATED
// for both Reliable as well as unreliable
// transports. Note that the dialog layer
// takes care of retransmitting 2xx final
// responses.
/*
* RFC 3261 Section 13.3.1.4 Note, however, that the INVITE server
* transaction will be destroyed as soon as it receives this final
* response and passes it to the transport. Therefore, it is necessary
* to periodically pass the response directly to the transport until
* the ACK arrives. The 2xx response is passed to the transport with
* an interval that starts at T1 seconds and doubles for each
* retransmission until it reaches T2 seconds (T1 and T2 are defined
* in Section 17). Response retransmissions cease when an ACK request
* for the response is received. This is independent of whatever
* transport protocols are used to send the response.
*/
this.disableRetransmissionTimer();
this.disableTimeoutTimer();
this.collectionTime = TIMER_J;
this.setState(TransactionState.TERMINATED);
if (this.dialog != null)
this.dialog.setRetransmissionTicks();
} else {
// This an error final response.
this.setState(TransactionState.COMPLETED);
if (!isReliable()) {
/*
* RFC 3261
*
* While in the "Proceeding" state, if the TU passes a response
* with status code from 300 to 699 to the server transaction, the
* response MUST be passed to the transport layer for
* transmission, and the state machine MUST enter the "Completed"
* state. For unreliable transports, timer G is set to fire in T1
* seconds, and is not set to fire for reliable transports.
*/
enableRetransmissionTimer();
}
enableTimeoutTimer(TIMER_H);
}
}
}
// If the transaction is in the proceeding state,
} else if (getRealState() == TransactionState.PROCEEDING) {
if (isInviteTransaction()) {
// If the response is a failure message,
if (statusCode / 100 == 2) {
// Set up to catch returning ACKs
// The transaction lingers in the
// terminated state for some time
// to catch retransmitted INVITEs
this.disableRetransmissionTimer();
this.disableTimeoutTimer();
this.collectionTime = TIMER_J;
this.setState(TransactionState.TERMINATED);
if (this.dialog != null)
this.dialog.setRetransmissionTicks();
} else if (300 <= statusCode && statusCode <= 699) {
// Set up to catch returning ACKs
this.setState(TransactionState.COMPLETED);
if (!isReliable()) {
/*
* While in the "Proceeding" state, if the TU passes a response with
* status code from 300 to 699 to the server transaction, the response
* MUST be passed to the transport layer for transmission, and the
* state machine MUST enter the "Completed" state. For unreliable
* transports, timer G is set to fire in T1 seconds, and is not set to
* fire for reliable transports.
*/
enableRetransmissionTimer();
}
enableTimeoutTimer(TIMER_H);
}
// If the transaction is not an invite transaction
// and this is a final response,
} else if (200 <= statusCode && statusCode <= 699) {
// This is for Non-invite server transactions.
// Set up to retransmit this response,
// or terminate the transaction
this.setState(TransactionState.COMPLETED);
if (!isReliable()) {
disableRetransmissionTimer();
enableTimeoutTimer(TIMER_J);
} else {
this.setState(TransactionState.TERMINATED);
}
}
// If the transaction has already completed,
} else if (TransactionState.COMPLETED == this.getRealState()) {
return;
}
try {
// Record the last message sent out.
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("sendMessage : tx = " + this + " getState = " + this.getState());
}
lastResponse = transactionResponse;
this.sendResponse(transactionResponse);
} catch (IOException e) {
this.setState(TransactionState.TERMINATED);
this.collectionTime = 0;
throw e;
}
} finally {
this.startTransactionTimer();
}
}
use of gov.nist.javax.sip.message.SIPResponse in project XobotOS by xamarin.
the class DialogFilter method sendCallOrTransactionDoesNotExistResponse.
/**
* Send a CALL OR TRANSACTION DOES NOT EXIST response.
*
* @param sipRequest
* @param transaction
*/
private void sendCallOrTransactionDoesNotExistResponse(SIPRequest sipRequest, SIPServerTransaction transaction) {
SIPResponse sipResponse = sipRequest.createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);
ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader();
if (serverHeader != null) {
sipResponse.setHeader(serverHeader);
}
try {
if (sipRequest.getMethod().equals(Request.INVITE)) {
sipStack.addTransactionPendingAck(transaction);
}
transaction.sendResponse(sipResponse);
transaction.releaseSem();
} catch (Exception ex) {
sipStack.getStackLogger().logError("Problem sending error response", ex);
transaction.releaseSem();
sipStack.removeTransaction(transaction);
}
}
use of gov.nist.javax.sip.message.SIPResponse in project XobotOS by xamarin.
the class DialogFilter method processResponse.
/**
* Process the response.
*
* @exception SIPServerException is thrown when there is an error processing the response
* @param incomingMessageChannel -- message channel on which the response is received.
*/
public void processResponse(SIPResponse response, MessageChannel incomingMessageChannel, SIPDialog dialog) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("PROCESSING INCOMING RESPONSE" + response.encodeMessage());
}
if (listeningPoint == null) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logError("Dropping message: No listening point" + " registered!");
return;
}
if (sipStack.checkBranchId() && !Utils.getInstance().responseBelongsToUs(response)) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logError("Dropping response - topmost VIA header does not originate from this stack");
}
return;
}
SipProviderImpl sipProvider = listeningPoint.getProvider();
if (sipProvider == null) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logError("Dropping message: no provider");
}
return;
}
if (sipProvider.getSipListener() == null) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logError("No listener -- dropping response!");
}
return;
}
SIPClientTransaction transaction = (SIPClientTransaction) this.transactionChannel;
SipStackImpl sipStackImpl = sipProvider.sipStack;
if (sipStack.isLoggingEnabled()) {
sipStackImpl.getStackLogger().logDebug("Transaction = " + transaction);
}
if (transaction == null) {
// we cannot drop the response.
if (dialog != null) {
if (response.getStatusCode() / 100 != 2) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Response is not a final response and dialog is found for response -- dropping response!");
}
return;
} else if (dialog.getState() == DialogState.TERMINATED) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Dialog is terminated -- dropping response!");
}
return;
} else {
boolean ackAlreadySent = false;
if (dialog.isAckSeen() && dialog.getLastAckSent() != null) {
if (dialog.getLastAckSent().getCSeq().getSeqNumber() == response.getCSeq().getSeqNumber()) {
// the last ack sent corresponded to this 200
ackAlreadySent = true;
}
}
// 200 retransmission for the final response.
if (ackAlreadySent && response.getCSeq().getMethod().equals(dialog.getMethod())) {
try {
// dont pass up the null transaction
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Retransmission of OK detected: Resending last ACK");
}
dialog.resendAck();
return;
} catch (SipException ex) {
// What to do here ?? kill the dialog?
sipStack.getStackLogger().logError("could not resend ack", ex);
}
}
}
}
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("could not find tx, handling statelessly Dialog = " + dialog);
}
// Pass the response up to the application layer to handle
// statelessly.
ResponseEventExt sipEvent = new ResponseEventExt(sipProvider, transaction, dialog, (Response) response);
if (response.getCSeqHeader().getMethod().equals(Request.INVITE)) {
SIPClientTransaction forked = this.sipStack.getForkedTransaction(response.getTransactionId());
sipEvent.setOriginalTransaction(forked);
}
sipProvider.handleEvent(sipEvent, transaction);
return;
}
ResponseEventExt responseEvent = null;
// Here if there is an assigned dialog
responseEvent = new ResponseEventExt(sipProvider, (ClientTransactionExt) transaction, dialog, (Response) response);
if (response.getCSeqHeader().getMethod().equals(Request.INVITE)) {
SIPClientTransaction forked = this.sipStack.getForkedTransaction(response.getTransactionId());
responseEvent.setOriginalTransaction(forked);
}
// Set the Dialog for the response.
if (dialog != null && response.getStatusCode() != 100) {
// set the last response for the dialog.
dialog.setLastResponse(transaction, response);
transaction.setDialog(dialog, dialog.getDialogId());
}
sipProvider.handleEvent(responseEvent, transaction);
}
Aggregations