return;
}
}
RequestEvent sipEvent;
if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
sipStack.getStackLogger().logDebug(
sipRequest.getMethod() + " transaction.isMapped = "
+ transaction.isTransactionMapped());
}
/*
* RFC 3265: Each event package MUST specify whether forked SUBSCRIBE requests are allowed
* to install multiple subscriptions. If such behavior is not allowed, the first potential
* dialog- establishing message will create a dialog. All subsequent NOTIFY messages which
* correspond to the SUBSCRIBE message (i.e., match "To", "From", "From" header "tag"
* parameter, "Call-ID", "CSeq", "Event", and "Event" header "id" parameter) but which do
* not match the dialog would be rejected with a 481 response. Note that the 200-class
* response to the SUBSCRIBE can arrive after a matching NOTIFY has been received; such
* responses might not correlate to the same dialog established by the NOTIFY. Except as
* required to complete the SUBSCRIBE transaction, such non-matching 200-class responses
* are ignored.
*/
if (dialog == null && sipRequest.getMethod().equals(Request.NOTIFY)) {
SIPClientTransaction pendingSubscribeClientTx = sipStack.findSubscribeTransaction(
sipRequest, listeningPoint);
if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
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.isDeliverUnsolicitedNotify()) {
/*
* 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(LogWriter.TRACE_DEBUG)) {
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;
}
}
// If the server transaction cannot be found or if it
// aleady has a dialog attached to it then just assign the
// 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)) {
// Notify came in before you could assign a response to
// the subscribe.
// grab the default dialog and assign it to the tags in
// the notify.
if (subscriptionDialog != null && subscriptionDialog.getDialogId() == null) {
subscriptionDialog.setDialogId(dialogId);
} else {
subscriptionDialog = pendingSubscribeClientTx.getDialog(dialogId);
}
if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
sipStack.getStackLogger().logDebug(
"PROCESSING NOTIFY Subscribe DIALOG " + subscriptionDialog);
}
// The user could have createed a dialog before sending out
// 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);
if ( subscriptionDialog.getState() != DialogState.CONFIRMED ) {
subscriptionDialog.setPendingRouteUpdateOn202Response(sipRequest);
}
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(LogWriter.TRACE_DEBUG)) {
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 {
// For a dialog creating event - set the transaction to null.
// 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);
}