use of gov.nist.javax.sip.message.SIPRequest in project XobotOS by xamarin.
the class SIPDialog method sendRequest.
public void sendRequest(ClientTransaction clientTransactionId, boolean allowInterleaving) throws TransactionDoesNotExistException, SipException {
if ((!allowInterleaving) && clientTransactionId.getRequest().getMethod().equals(Request.INVITE)) {
new Thread((new ReInviteSender(clientTransactionId))).start();
return;
}
SIPRequest dialogRequest = ((SIPClientTransaction) clientTransactionId).getOriginalRequest();
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("dialog.sendRequest " + " dialog = " + this + "\ndialogRequest = \n" + dialogRequest);
if (clientTransactionId == null)
throw new NullPointerException("null parameter");
if (dialogRequest.getMethod().equals(Request.ACK) || dialogRequest.getMethod().equals(Request.CANCEL))
throw new SipException("Bad Request Method. " + dialogRequest.getMethod());
// JvB: added, allow re-sending of BYE after challenge
if (byeSent && isTerminatedOnBye() && !dialogRequest.getMethod().equals(Request.BYE)) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logError("BYE already sent for " + this);
throw new SipException("Cannot send request; BYE already sent");
}
if (dialogRequest.getTopmostVia() == null) {
Via via = ((SIPClientTransaction) clientTransactionId).getOutgoingViaHeader();
dialogRequest.addHeader(via);
}
if (!this.getCallId().getCallId().equalsIgnoreCase(dialogRequest.getCallId().getCallId())) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logError("CallID " + this.getCallId());
sipStack.getStackLogger().logError("RequestCallID = " + dialogRequest.getCallId().getCallId());
sipStack.getStackLogger().logError("dialog = " + this);
}
throw new SipException("Bad call ID in request");
}
// Set the dialog back pointer.
((SIPClientTransaction) clientTransactionId).setDialog(this, this.dialogId);
this.addTransaction((SIPTransaction) clientTransactionId);
// Enable the retransmission filter for the transaction
((SIPClientTransaction) clientTransactionId).isMapped = true;
From from = (From) dialogRequest.getFrom();
To to = (To) dialogRequest.getTo();
// tag assignment is OK.
if (this.getLocalTag() != null && from.getTag() != null && !from.getTag().equals(this.getLocalTag()))
throw new SipException("From tag mismatch expecting " + this.getLocalTag());
if (this.getRemoteTag() != null && to.getTag() != null && !to.getTag().equals(this.getRemoteTag())) {
if (sipStack.isLoggingEnabled())
this.sipStack.getStackLogger().logWarning("To header tag mismatch expecting " + this.getRemoteTag());
}
/*
* The application is sending a NOTIFY before sending the response of the dialog.
*/
if (this.getLocalTag() == null && dialogRequest.getMethod().equals(Request.NOTIFY)) {
if (!this.getMethod().equals(Request.SUBSCRIBE))
throw new SipException("Trying to send NOTIFY without SUBSCRIBE Dialog!");
this.setLocalTag(from.getTag());
}
try {
if (this.getLocalTag() != null)
from.setTag(this.getLocalTag());
if (this.getRemoteTag() != null)
to.setTag(this.getRemoteTag());
} catch (ParseException ex) {
InternalErrorHandler.handleException(ex);
}
Hop hop = ((SIPClientTransaction) clientTransactionId).getNextHop();
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Using hop = " + hop.getHost() + " : " + hop.getPort());
}
try {
MessageChannel messageChannel = sipStack.createRawMessageChannel(this.getSipProvider().getListeningPoint(hop.getTransport()).getIPAddress(), this.firstTransactionPort, hop);
MessageChannel oldChannel = ((SIPClientTransaction) clientTransactionId).getMessageChannel();
// Remove this from the connection cache if it is in the
// connection
// cache and is not yet active.
oldChannel.uncache();
// Not configured to cache client connections.
if (!sipStack.cacheClientConnections) {
oldChannel.useCount--;
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("oldChannel: useCount " + oldChannel.useCount);
}
if (messageChannel == null) {
/*
* At this point the procedures of 8.1.2 and 12.2.1.1 of RFC3261 have been tried
* but the resulting next hop cannot be resolved (recall that the exception thrown
* is caught and ignored in SIPStack.createMessageChannel() so we end up here with
* a null messageChannel instead of the exception handler below). All else
* failing, try the outbound proxy in accordance with 8.1.2, in particular: This
* ensures that outbound proxies that do not add Record-Route header field values
* will drop out of the path of subsequent requests. It allows endpoints that
* cannot resolve the first Route URI to delegate that task to an outbound proxy.
*
* if one considers the 'first Route URI' of a request constructed according to
* 12.2.1.1 to be the request URI when the route set is empty.
*/
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Null message channel using outbound proxy !");
Hop outboundProxy = sipStack.getRouter(dialogRequest).getOutboundProxy();
if (outboundProxy == null)
throw new SipException("No route found! hop=" + hop);
messageChannel = sipStack.createRawMessageChannel(this.getSipProvider().getListeningPoint(outboundProxy.getTransport()).getIPAddress(), this.firstTransactionPort, outboundProxy);
if (messageChannel != null)
((SIPClientTransaction) clientTransactionId).setEncapsulatedChannel(messageChannel);
} else {
((SIPClientTransaction) clientTransactionId).setEncapsulatedChannel(messageChannel);
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("using message channel " + messageChannel);
}
}
if (messageChannel != null)
messageChannel.useCount++;
// See if we need to release the previously mapped channel.
if ((!sipStack.cacheClientConnections) && oldChannel != null && oldChannel.useCount <= 0)
oldChannel.close();
} catch (Exception ex) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logException(ex);
throw new SipException("Could not create message channel", ex);
}
try {
// Increment before setting!!
localSequenceNumber++;
dialogRequest.getCSeq().setSeqNumber(getLocalSeqNumber());
} catch (InvalidArgumentException ex) {
sipStack.getStackLogger().logFatalError(ex.getMessage());
}
try {
((SIPClientTransaction) clientTransactionId).sendMessage(dialogRequest);
/*
* Note that if the BYE is rejected then the Dialog should bo back to the ESTABLISHED
* state so we only set state after successful send.
*/
if (dialogRequest.getMethod().equals(Request.BYE)) {
this.byeSent = true;
/*
* Dialog goes into TERMINATED state as soon as BYE is sent. ISSUE 182.
*/
if (isTerminatedOnBye()) {
this.setState(DialogState._TERMINATED);
}
}
} catch (IOException ex) {
throw new SipException("error sending message", ex);
}
}
use of gov.nist.javax.sip.message.SIPRequest in project XobotOS by xamarin.
the class MessageChannel method sendMessage.
/**
* Send a formatted message to the specified target.
*
* @param sipMessage Message to send.
* @param hop hop to send it to.
* @throws IOException If there is an error sending the message
*/
public void sendMessage(SIPMessage sipMessage, Hop hop) throws IOException {
long time = System.currentTimeMillis();
InetAddress hopAddr = InetAddress.getByName(hop.getHost());
try {
for (MessageProcessor messageProcessor : getSIPStack().getMessageProcessors()) {
if (messageProcessor.getIpAddress().equals(hopAddr) && messageProcessor.getPort() == hop.getPort() && messageProcessor.getTransport().equals(hop.getTransport())) {
MessageChannel messageChannel = messageProcessor.createMessageChannel(hopAddr, hop.getPort());
if (messageChannel instanceof RawMessageChannel) {
((RawMessageChannel) messageChannel).processMessage(sipMessage);
if (getSIPStack().isLoggingEnabled())
getSIPStack().getStackLogger().logDebug("Self routing message");
return;
}
}
}
byte[] msg = sipMessage.encodeAsBytes(this.getTransport());
this.sendMessage(msg, hopAddr, hop.getPort(), sipMessage instanceof SIPRequest);
} catch (IOException ioe) {
throw ioe;
} catch (Exception ex) {
if (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_ERROR)) {
this.getSIPStack().getStackLogger().logError("Error self routing message cause by: ", ex);
}
// TODO: When moving to Java 6, use the IOExcpetion(message, exception) constructor
throw new IOException("Error self routing message");
} finally {
if (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))
logMessage(sipMessage, hopAddr, hop.getPort(), time);
}
}
use of gov.nist.javax.sip.message.SIPRequest in project XobotOS by xamarin.
the class StringMsgParser method processFirstLine.
private SIPMessage processFirstLine(String firstLine) throws ParseException {
SIPMessage message;
if (!firstLine.startsWith(SIPConstants.SIP_VERSION_STRING)) {
message = new SIPRequest();
try {
RequestLine requestLine = new RequestLineParser(firstLine + "\n").parse();
((SIPRequest) message).setRequestLine(requestLine);
} catch (ParseException ex) {
if (this.parseExceptionListener != null)
this.parseExceptionListener.handleException(ex, message, RequestLine.class, firstLine, rawStringMessage);
else
throw ex;
}
} else {
message = new SIPResponse();
try {
StatusLine sl = new StatusLineParser(firstLine + "\n").parse();
((SIPResponse) message).setStatusLine(sl);
} catch (ParseException ex) {
if (this.parseExceptionListener != null) {
this.parseExceptionListener.handleException(ex, message, StatusLine.class, firstLine, rawStringMessage);
} else
throw ex;
}
}
return message;
}
use of gov.nist.javax.sip.message.SIPRequest in project XobotOS by xamarin.
the class DialogFilter method processRequest.
/**
* Process a request. Check for various conditions in the dialog that can result in the
* message being dropped. Possibly return errors for these conditions.
*
* @exception SIPServerException is thrown when there is an error processing the request.
*/
public void processRequest(SIPRequest sipRequest, MessageChannel incomingMessageChannel) {
// Generate the wrapper JAIN-SIP object.
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("PROCESSING INCOMING REQUEST " + sipRequest + " transactionChannel = " + transactionChannel + " listening point = " + listeningPoint.getIPAddress() + ":" + listeningPoint.getPort());
if (listeningPoint == null) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Dropping message: No listening point registered!");
return;
}
SipStackImpl sipStack = (SipStackImpl) transactionChannel.getSIPStack();
SipProviderImpl sipProvider = listeningPoint.getProvider();
if (sipProvider == null) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("No provider - dropping !!");
return;
}
if (sipStack == null)
InternalErrorHandler.handleException("Egads! no sip stack!");
// Look for the registered SIPListener for the message channel.
SIPServerTransaction transaction = (SIPServerTransaction) this.transactionChannel;
if (transaction != null) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("transaction state = " + transaction.getState());
}
String dialogId = sipRequest.getDialogId(true);
SIPDialog dialog = sipStack.getDialog(dialogId);
/*
* Check if we got this request on the contact address of the dialog If not the dialog
* does not belong to this request. We check this condition if a contact address has been
* assigned to the dialog. Forgive the sins of B2BUA's that like to record route ACK's
*/
if (dialog != null && sipProvider != dialog.getSipProvider()) {
Contact contact = dialog.getMyContactHeader();
if (contact != null) {
SipUri contactUri = (SipUri) (contact.getAddress().getURI());
String ipAddress = contactUri.getHost();
int contactPort = contactUri.getPort();
String contactTransport = contactUri.getTransportParam();
if (contactTransport == null)
contactTransport = "udp";
if (contactPort == -1) {
if (contactTransport.equals("udp") || contactTransport.equals("tcp"))
contactPort = 5060;
else
contactPort = 5061;
}
// dialog to the request.
if (ipAddress != null && (!ipAddress.equals(listeningPoint.getIPAddress()) || contactPort != listeningPoint.getPort())) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("nulling dialog -- listening point mismatch! " + contactPort + " lp port = " + listeningPoint.getPort());
}
dialog = null;
}
}
}
/*
* RFC 3261 8.2.2.2 Merged requests: If the request has no tag in the To header field, the
* UAS core MUST check the request against ongoing transactions. If the From tag, Call-ID,
* and CSeq exactly match those associated with an ongoing transaction, but the request
* does not match that transaction (based on the matching rules in Section 17.2.3), the
* UAS core SHOULD generate a 482 (Loop Detected) response and pass it to the server
* transaction. This support is only enabled when the stack has been instructed to
* function with Automatic Dialog Support.
*/
if (sipProvider.isAutomaticDialogSupportEnabled() && sipProvider.isDialogErrorsAutomaticallyHandled() && sipRequest.getToTag() == null) {
SIPServerTransaction sipServerTransaction = sipStack.findMergedTransaction(sipRequest);
if (sipServerTransaction != null) {
this.sendLoopDetectedResponse(sipRequest, transaction);
return;
}
}
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("dialogId = " + dialogId);
sipStack.getStackLogger().logDebug("dialog = " + dialog);
}
// endpoint, then the stack strips off the route header.
if (sipRequest.getHeader(Route.NAME) != null && transaction.getDialog() != null) {
RouteList routes = sipRequest.getRouteHeaders();
Route route = (Route) routes.getFirst();
SipUri uri = (SipUri) route.getAddress().getURI();
int port;
if (uri.getHostPort().hasPort()) {
port = uri.getHostPort().getPort();
} else {
if (listeningPoint.getTransport().equalsIgnoreCase("TLS"))
port = 5061;
else
port = 5060;
}
String host = uri.getHost();
if ((host.equals(listeningPoint.getIPAddress()) || host.equalsIgnoreCase(listeningPoint.getSentBy())) && port == listeningPoint.getPort()) {
if (routes.size() == 1)
sipRequest.removeHeader(Route.NAME);
else
routes.removeFirst();
}
}
if (sipRequest.getMethod().equals(Request.REFER) && dialog != null && sipProvider.isDialogErrorsAutomaticallyHandled()) {
/*
* An agent responding to a REFER method MUST return a 400 (Bad Request) if the
* request contained zero or more than one Refer-To header field values.
*/
ReferToHeader sipHeader = (ReferToHeader) sipRequest.getHeader(ReferTo.NAME);
if (sipHeader == null) {
this.sendBadRequestResponse(sipRequest, transaction, "Refer-To header is missing");
return;
}
/*
* A refer cannot be processed until we have either sent or received an ACK.
*/
SIPTransaction lastTransaction = ((SIPDialog) dialog).getLastTransaction();
if (lastTransaction != null && sipProvider.isDialogErrorsAutomaticallyHandled()) {
SIPRequest lastRequest = (SIPRequest) lastTransaction.getRequest();
if (lastTransaction instanceof SIPServerTransaction) {
if (!((SIPDialog) dialog).isAckSeen() && lastRequest.getMethod().equals(Request.INVITE)) {
this.sendRequestPendingResponse(sipRequest, transaction);
return;
}
} else if (lastTransaction instanceof SIPClientTransaction) {
long cseqno = lastRequest.getCSeqHeader().getSeqNumber();
String method = lastRequest.getMethod();
if (method.equals(Request.INVITE) && !dialog.isAckSent(cseqno)) {
this.sendRequestPendingResponse(sipRequest, transaction);
return;
}
}
}
} else if (sipRequest.getMethod().equals(Request.UPDATE)) {
/*
* Got an UPDATE method and the user dialog does not exist and the user wants to be a
* User agent.
*
*/
if (sipProvider.isAutomaticDialogSupportEnabled() && dialog == null) {
this.sendCallOrTransactionDoesNotExistResponse(sipRequest, transaction);
return;
}
} else if (sipRequest.getMethod().equals(Request.ACK)) {
if (transaction != null && transaction.isInviteTransaction()) {
// take care of it.
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Processing ACK for INVITE Tx ");
} else {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Processing ACK for dialog " + dialog);
if (dialog == null) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Dialog does not exist " + sipRequest.getFirstLine() + " isServerTransaction = " + true);
}
SIPServerTransaction st = sipStack.getRetransmissionAlertTransaction(dialogId);
if (st != null && st.isRetransmissionAlertEnabled()) {
st.disableRetransmissionAlerts();
}
/*
* JvB: must never drop ACKs that dont match a transaction! One cannot be sure
* if it isn't an ACK for a 2xx response
*
*/
SIPServerTransaction ackTransaction = sipStack.findTransactionPendingAck(sipRequest);
/*
* Found a transaction ( that we generated ) which is waiting for ACK. So ACK
* it and return.
*/
if (ackTransaction != null) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Found Tx pending ACK");
try {
ackTransaction.setAckSeen();
sipStack.removeTransaction(ackTransaction);
sipStack.removeTransactionPendingAck(ackTransaction);
} catch (Exception ex) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logError("Problem terminating transaction", ex);
}
}
return;
}
} else {
if (!dialog.handleAck(transaction)) {
if (!dialog.isSequnceNumberValidation()) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Dialog exists with loose dialog validation " + sipRequest.getFirstLine() + " isServerTransaction = " + true + " dialog = " + dialog.getDialogId());
}
SIPServerTransaction st = sipStack.getRetransmissionAlertTransaction(dialogId);
if (st != null && st.isRetransmissionAlertEnabled()) {
st.disableRetransmissionAlerts();
}
} else {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Dropping ACK - cannot find a transaction or dialog");
}
SIPServerTransaction ackTransaction = sipStack.findTransactionPendingAck(sipRequest);
if (ackTransaction != null) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Found Tx pending ACK");
try {
ackTransaction.setAckSeen();
sipStack.removeTransaction(ackTransaction);
sipStack.removeTransactionPendingAck(ackTransaction);
} catch (Exception ex) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logError("Problem terminating transaction", ex);
}
}
}
return;
}
} else {
transaction.passToListener();
dialog.addTransaction(transaction);
dialog.addRoute(sipRequest);
transaction.setDialog(dialog, dialogId);
if (sipRequest.getMethod().equals(Request.INVITE) && sipProvider.isDialogErrorsAutomaticallyHandled()) {
sipStack.putInMergeTable(transaction, sipRequest);
}
if (sipStack.deliverTerminatedEventForAck) {
try {
sipStack.addTransaction(transaction);
transaction.scheduleAckRemoval();
} catch (IOException ex) {
}
} else {
transaction.setMapped(true);
}
}
}
}
} else if (sipRequest.getMethod().equals(Request.PRACK)) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Processing PRACK for dialog " + dialog);
if (dialog == null && sipProvider.isAutomaticDialogSupportEnabled()) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Dialog does not exist " + sipRequest.getFirstLine() + " isServerTransaction = " + true);
}
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Sending 481 for PRACK - automatic dialog support is enabled -- cant find dialog!");
}
SIPResponse notExist = sipRequest.createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);
try {
sipProvider.sendResponse(notExist);
} catch (SipException e) {
sipStack.getStackLogger().logError("error sending response", e);
}
if (transaction != null) {
sipStack.removeTransaction(transaction);
transaction.releaseSem();
}
return;
} else if (dialog != null) {
if (!dialog.handlePrack(sipRequest)) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Dropping out of sequence PRACK ");
if (transaction != null) {
sipStack.removeTransaction(transaction);
transaction.releaseSem();
}
return;
} else {
try {
sipStack.addTransaction(transaction);
dialog.addTransaction(transaction);
dialog.addRoute(sipRequest);
transaction.setDialog(dialog, dialogId);
} catch (Exception ex) {
InternalErrorHandler.handleException(ex);
}
}
} else {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Processing PRACK without a DIALOG -- this must be a proxy element");
}
} else if (sipRequest.getMethod().equals(Request.BYE)) {
// Check for correct sequence numbering of the BYE
if (dialog != null && !dialog.isRequestConsumable(sipRequest)) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Dropping out of sequence BYE " + dialog.getRemoteSeqNumber() + " " + sipRequest.getCSeq().getSeqNumber());
if (dialog.getRemoteSeqNumber() >= sipRequest.getCSeq().getSeqNumber() && transaction.getState() == TransactionState.TRYING) {
this.sendServerInternalErrorResponse(sipRequest, transaction);
}
// If the stack knows about the tx, then remove it.
if (transaction != null)
sipStack.removeTransaction(transaction);
return;
} else if (dialog == null && sipProvider.isAutomaticDialogSupportEnabled()) {
// Drop bye's with 481 if dialog does not exist.
// If dialog support is enabled then
// there must be a dialog associated with the bye
// No dialog could be found and requests on this
// provider. Must act like a user agent -- so drop the request.
// NOTE: if Automatic dialog support is not enabled,
// then it is the application's responsibility to
// take care of this error condition possibly.
SIPResponse response = sipRequest.createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);
response.setReasonPhrase("Dialog Not Found");
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("dropping request -- automatic dialog " + "support enabled and dialog does not exist!");
try {
transaction.sendResponse(response);
} catch (SipException ex) {
sipStack.getStackLogger().logError("Error in sending response", ex);
}
// If the stack knows about the tx, then remove it.
if (transaction != null) {
sipStack.removeTransaction(transaction);
transaction.releaseSem();
transaction = null;
}
return;
}
// to manage its own dialog layer.
if (transaction != null && dialog != null) {
try {
if (sipProvider == dialog.getSipProvider()) {
sipStack.addTransaction(transaction);
dialog.addTransaction(transaction);
transaction.setDialog(dialog, dialogId);
}
} catch (IOException ex) {
InternalErrorHandler.handleException(ex);
}
}
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("BYE Tx = " + transaction + " isMapped =" + transaction.isTransactionMapped());
}
} else if (sipRequest.getMethod().equals(Request.CANCEL)) {
SIPServerTransaction st = (SIPServerTransaction) sipStack.findCancelTransaction(sipRequest, true);
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Got a CANCEL, InviteServerTx = " + st + " cancel Server Tx ID = " + transaction + " isMapped = " + transaction.isTransactionMapped());
}
// Check if we can process the CANCEL request.
if (sipRequest.getMethod().equals(Request.CANCEL)) {
// default action and avoid bothering the listener.
if (st != null && st.getState() == SIPTransaction.TERMINATED_STATE) {
// just respond OK to the CANCEL and bail.
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Too late to cancel Transaction");
// send OK and just ignore the CANCEL.
try {
transaction.sendResponse(sipRequest.createResponse(Response.OK));
} catch (Exception ex) {
if (ex.getCause() != null && ex.getCause() instanceof IOException) {
st.raiseIOExceptionEvent();
}
}
return;
}
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Cancel transaction = " + st);
}
if (transaction != null && st != null && st.getDialog() != null) {
// Found an invite tx corresponding to the CANCEL.
// Set up the client tx and pass up to listener.
transaction.setDialog((SIPDialog) st.getDialog(), dialogId);
dialog = (SIPDialog) st.getDialog();
} else if (st == null && sipProvider.isAutomaticDialogSupportEnabled() && transaction != null) {
// Could not find a invite tx corresponding to the CANCEL.
// Automatic dialog support is enabled so I must behave like
// an endpoint on this provider.
// Send the error response for the cancel.
SIPResponse response = sipRequest.createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("dropping request -- automatic dialog support " + "enabled and INVITE ST does not exist!");
}
try {
sipProvider.sendResponse(response);
} catch (SipException ex) {
InternalErrorHandler.handleException(ex);
}
if (transaction != null) {
sipStack.removeTransaction(transaction);
transaction.releaseSem();
}
return;
}
// statefully handled.
if (st != null) {
try {
if (transaction != null) {
sipStack.addTransaction(transaction);
transaction.setPassToListener();
transaction.setInviteTransaction(st);
// Dont let the INVITE and CANCEL be concurrently
// processed.
st.acquireSem();
}
} catch (Exception ex) {
InternalErrorHandler.handleException(ex);
}
}
} else if (sipRequest.getMethod().equals(Request.INVITE)) {
SIPTransaction lastTransaction = dialog == null ? null : dialog.getInviteTransaction();
if (dialog != null && transaction != null && lastTransaction != null && sipRequest.getCSeq().getSeqNumber() > dialog.getRemoteSeqNumber() && lastTransaction instanceof SIPServerTransaction && sipProvider.isDialogErrorsAutomaticallyHandled() && dialog.isSequnceNumberValidation() && lastTransaction.isInviteTransaction() && lastTransaction.getState() != TransactionState.COMPLETED && lastTransaction.getState() != TransactionState.TERMINATED && lastTransaction.getState() != TransactionState.CONFIRMED) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Sending 500 response for out of sequence message");
}
this.sendServerInternalErrorResponse(sipRequest, transaction);
return;
}
/*
* Saw an interleaved invite before ACK was sent. RFC 3261 Chapter 14. A UAS that
* receives an INVITE on a dialog while an INVITE it had sent on that dialog is in
* progress MUST return a 491 (Request Pending) response to the received INVITE.
*/
lastTransaction = (dialog == null ? null : dialog.getLastTransaction());
if (dialog != null && sipProvider.isDialogErrorsAutomaticallyHandled() && lastTransaction != null && lastTransaction.isInviteTransaction() && lastTransaction instanceof ClientTransaction && lastTransaction.getLastResponse() != null && lastTransaction.getLastResponse().getStatusCode() == 200 && !dialog.isAckSent(lastTransaction.getLastResponse().getCSeq().getSeqNumber())) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Sending 491 response for client Dialog ACK not sent.");
}
this.sendRequestPendingResponse(sipRequest, transaction);
return;
}
if (dialog != null && lastTransaction != null && sipProvider.isDialogErrorsAutomaticallyHandled() && lastTransaction.isInviteTransaction() && lastTransaction instanceof ServerTransaction && !dialog.isAckSeen()) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Sending 491 response for server Dialog ACK not seen.");
}
this.sendRequestPendingResponse(sipRequest, transaction);
return;
}
}
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("CHECK FOR OUT OF SEQ MESSAGE " + dialog + " transaction " + transaction);
}
if (dialog != null && transaction != null && !sipRequest.getMethod().equals(Request.BYE) && !sipRequest.getMethod().equals(Request.CANCEL) && !sipRequest.getMethod().equals(Request.ACK) && !sipRequest.getMethod().equals(Request.PRACK)) {
if (!dialog.isRequestConsumable(sipRequest)) {
// Drop the request
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Dropping out of sequence message " + dialog.getRemoteSeqNumber() + " " + sipRequest.getCSeq());
}
if (dialog.getRemoteSeqNumber() >= sipRequest.getCSeq().getSeqNumber() && sipProvider.isDialogErrorsAutomaticallyHandled() && (transaction.getState() == TransactionState.TRYING || transaction.getState() == TransactionState.PROCEEDING)) {
this.sendServerInternalErrorResponse(sipRequest, transaction);
}
return;
}
try {
if (sipProvider == dialog.getSipProvider()) {
sipStack.addTransaction(transaction);
// This will set the remote sequence number.
dialog.addTransaction(transaction);
dialog.addRoute(sipRequest);
transaction.setDialog(dialog, dialogId);
}
} catch (IOException ex) {
transaction.raiseIOExceptionEvent();
sipStack.removeTransaction(transaction);
return;
}
}
RequestEvent sipEvent;
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug(sipRequest.getMethod() + " transaction.isMapped = " + transaction.isTransactionMapped());
}
if (dialog == null && sipRequest.getMethod().equals(Request.NOTIFY)) {
SIPClientTransaction pendingSubscribeClientTx = sipStack.findSubscribeTransaction(sipRequest, listeningPoint);
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("PROCESSING NOTIFY DIALOG == null " + pendingSubscribeClientTx);
}
/*
* RFC 3265: Upon receiving a NOTIFY request, the subscriber should check that it
* matches at least one of its outstanding subscriptions; if not, it MUST return a
* "481 Subscription does not exist" response unless another 400- or -class response
* is more appropriate.
*/
if (sipProvider.isAutomaticDialogSupportEnabled() && pendingSubscribeClientTx == null && !sipStack.deliverUnsolicitedNotify) {
/*
* This is the case of the UAC receiving a Stray NOTIFY for which it has not
* previously sent out a SUBSCRIBE and for which it does not have an established
* dialog.
*/
try {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Could not find Subscription for Notify Tx.");
}
Response errorResponse = sipRequest.createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);
errorResponse.setReasonPhrase("Subscription does not exist");
sipProvider.sendResponse(errorResponse);
return;
} catch (Exception ex) {
sipStack.getStackLogger().logError("Exception while sending error response statelessly", ex);
return;
}
}
// notify to this dialog and pass it up.
if (pendingSubscribeClientTx != null) {
// The response to the pending subscribe tx can try to create
// a dialog at the same time that the notify is trying to
// create a dialog. Thus we cannot process both at the
// same time.
transaction.setPendingSubscribe(pendingSubscribeClientTx);
// The transaction gets assigned to the dialog from the
// outgoing subscribe. First see if anybody claimed the
// default Dialog for the outgoing Subscribe request.
SIPDialog subscriptionDialog = (SIPDialog) pendingSubscribeClientTx.getDefaultDialog();
// TODO -- refactor this. Can probably be written far cleaner.
if (subscriptionDialog == null || subscriptionDialog.getDialogId() == null || !subscriptionDialog.getDialogId().equals(dialogId)) {
// the notify.
if (subscriptionDialog != null && subscriptionDialog.getDialogId() == null) {
subscriptionDialog.setDialogId(dialogId);
} else {
subscriptionDialog = pendingSubscribeClientTx.getDialog(dialogId);
}
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("PROCESSING NOTIFY Subscribe DIALOG " + subscriptionDialog);
}
// the SUBSCRIBE on the subscribe tx.
if (subscriptionDialog == null && (sipProvider.isAutomaticDialogSupportEnabled() || pendingSubscribeClientTx.getDefaultDialog() != null)) {
Event event = (Event) sipRequest.getHeader(EventHeader.NAME);
if (sipStack.isEventForked(event.getEventType())) {
subscriptionDialog = SIPDialog.createFromNOTIFY(pendingSubscribeClientTx, transaction);
}
}
if (subscriptionDialog != null) {
transaction.setDialog(subscriptionDialog, dialogId);
subscriptionDialog.setState(DialogState.CONFIRMED.getValue());
sipStack.putDialog(subscriptionDialog);
pendingSubscribeClientTx.setDialog(subscriptionDialog, dialogId);
if (!transaction.isTransactionMapped()) {
this.sipStack.mapTransaction(transaction);
// Let the listener see it if it just got
// created.
// otherwise, we have already processed the tx
// so
// we dont want the listener to see it.
transaction.setPassToListener();
try {
this.sipStack.addTransaction(transaction);
} catch (Exception ex) {
}
}
}
} else {
// The subscription default dialog is our dialog.
// Found a subscrbe dialog for the NOTIFY
// So map the tx.
transaction.setDialog(subscriptionDialog, dialogId);
dialog = subscriptionDialog;
if (!transaction.isTransactionMapped()) {
this.sipStack.mapTransaction(transaction);
// Let the listener see it if it just got created.
// otherwise, we have already processed the tx so
// we dont want the listener to see it.
transaction.setPassToListener();
try {
this.sipStack.addTransaction(transaction);
} catch (Exception ex) {
}
}
sipStack.putDialog(subscriptionDialog);
if (pendingSubscribeClientTx != null) {
subscriptionDialog.addTransaction(pendingSubscribeClientTx);
pendingSubscribeClientTx.setDialog(subscriptionDialog, dialogId);
}
}
if (transaction != null && ((SIPServerTransaction) transaction).isTransactionMapped()) {
// Shadow transaction has been created and the stack
// knows
// about it.
sipEvent = new RequestEvent((SipProvider) sipProvider, (ServerTransaction) transaction, subscriptionDialog, (Request) sipRequest);
} else {
// Shadow transaction has been created but the stack
// does
// not know
// about it.
sipEvent = new RequestEvent((SipProvider) sipProvider, null, subscriptionDialog, (Request) sipRequest);
}
} else {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("could not find subscribe tx");
}
// Got a notify out of the blue - just pass it up
// for stateless handling by the application.
sipEvent = new RequestEvent(sipProvider, null, null, (Request) sipRequest);
}
} else {
// The listener can create the dialog if needed.
if (transaction != null && (((SIPServerTransaction) transaction).isTransactionMapped())) {
sipEvent = new RequestEvent(sipProvider, (ServerTransaction) transaction, dialog, (Request) sipRequest);
} else {
sipEvent = new RequestEvent(sipProvider, null, dialog, (Request) sipRequest);
}
}
sipProvider.handleEvent(sipEvent, transaction);
}
use of gov.nist.javax.sip.message.SIPRequest in project XobotOS by xamarin.
the class DialogFilter method processResponse.
/*
* (non-Javadoc)
*
* @see gov.nist.javax.sip.stack.ServerResponseInterface#processResponse(gov.nist.javax.sip.message.SIPResponse,
* gov.nist.javax.sip.stack.MessageChannel)
*/
public void processResponse(SIPResponse sipResponse, MessageChannel incomingChannel) {
String dialogID = sipResponse.getDialogId(false);
SIPDialog sipDialog = this.sipStack.getDialog(dialogID);
String method = sipResponse.getCSeq().getMethod();
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("PROCESSING INCOMING RESPONSE: " + sipResponse.encodeMessage());
}
if (sipStack.checkBranchId() && !Utils.getInstance().responseBelongsToUs(sipResponse)) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logError("Detected stray response -- dropping");
}
return;
}
if (listeningPoint == null) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Dropping message: No listening point" + " registered!");
return;
}
SipProviderImpl sipProvider = listeningPoint.getProvider();
if (sipProvider == null) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Dropping message: no provider");
}
return;
}
if (sipProvider.getSipListener() == null) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Dropping message: no sipListener registered!");
}
return;
}
SIPClientTransaction transaction = (SIPClientTransaction) this.transactionChannel;
// 3PCC).
if (sipDialog == null && transaction != null) {
sipDialog = transaction.getDialog(dialogID);
if (sipDialog != null && sipDialog.getState() == DialogState.TERMINATED)
sipDialog = null;
}
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("Transaction = " + transaction + " sipDialog = " + sipDialog);
if (this.transactionChannel != null) {
String originalFrom = ((SIPRequest) this.transactionChannel.getRequest()).getFromTag();
if (originalFrom == null ^ sipResponse.getFrom().getTag() == null) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response");
return;
}
if (originalFrom != null && !originalFrom.equalsIgnoreCase(sipResponse.getFrom().getTag())) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response");
return;
}
}
if (sipStack.isDialogCreated(method) && sipResponse.getStatusCode() != 100 && sipResponse.getFrom().getTag() != null && sipResponse.getTo().getTag() != null && sipDialog == null) {
if (sipProvider.isAutomaticDialogSupportEnabled()) {
if (this.transactionChannel != null) {
if (sipDialog == null) {
// There could be an existing dialog for this response.
sipDialog = sipStack.createDialog((SIPClientTransaction) this.transactionChannel, sipResponse);
this.transactionChannel.setDialog(sipDialog, sipResponse.getDialogId(false));
}
} else {
sipDialog = this.sipStack.createDialog(sipProvider, sipResponse);
}
}
} else {
// Have a dialog but could not find transaction.
if (sipDialog != null && transaction == null && sipDialog.getState() != DialogState.TERMINATED) {
if (sipResponse.getStatusCode() / 100 != 2) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("status code != 200 ; statusCode = " + sipResponse.getStatusCode());
} else if (sipDialog.getState() == DialogState.TERMINATED) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Dialog is terminated -- dropping response!");
}
// It could be late arriving.
if (sipResponse.getStatusCode() / 100 == 2 && sipResponse.getCSeq().getMethod().equals(Request.INVITE)) {
try {
Request ackRequest = sipDialog.createAck(sipResponse.getCSeq().getSeqNumber());
sipDialog.sendAck(ackRequest);
} catch (Exception ex) {
sipStack.getStackLogger().logError("Error creating ack", ex);
}
}
return;
} else {
boolean ackAlreadySent = false;
if (sipDialog.isAckSeen() && sipDialog.getLastAckSent() != null) {
if (sipDialog.getLastAckSent().getCSeq().getSeqNumber() == sipResponse.getCSeq().getSeqNumber() && sipResponse.getDialogId(false).equals(sipDialog.getLastAckSent().getDialogId(false))) {
// the last ack sent corresponded to this 200
ackAlreadySent = true;
}
}
// 200 retransmission for the final response.
if (ackAlreadySent && sipResponse.getCSeq().getMethod().equals(sipDialog.getMethod())) {
try {
// dont pass up the null transaction
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("resending ACK");
sipDialog.resendAck();
return;
} catch (SipException ex) {
// What to do here ?? kill the dialog?
}
}
}
}
// Pass the response up to the application layer to handle
// statelessly.
}
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("sending response to TU for processing ");
if (sipDialog != null && sipResponse.getStatusCode() != 100 && sipResponse.getTo().getTag() != null) {
sipDialog.setLastResponse(transaction, sipResponse);
}
ResponseEventExt responseEvent = new ResponseEventExt(sipProvider, (ClientTransactionExt) transaction, sipDialog, (Response) sipResponse);
if (sipResponse.getCSeq().getMethod().equals(Request.INVITE)) {
ClientTransactionExt originalTx = this.sipStack.getForkedTransaction(sipResponse.getTransactionId());
responseEvent.setOriginalTransaction(originalTx);
}
sipProvider.handleEvent(responseEvent, transaction);
}
Aggregations