use of gov.nist.javax.sip.header.RecordRoute in project XobotOS by xamarin.
the class SIPDialog method setLastResponse.
/**
* Set the last response for this dialog. This method is called for updating the dialog state
* when a response is either sent or received from within a Dialog.
*
* @param transaction -- the transaction associated with the response
* @param sipResponse -- the last response to set.
*/
public void setLastResponse(SIPTransaction transaction, SIPResponse sipResponse) {
this.callIdHeader = sipResponse.getCallId();
int statusCode = sipResponse.getStatusCode();
if (statusCode == 100) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logWarning("Invalid status code - 100 in setLastResponse - ignoring");
return;
}
this.lastResponse = sipResponse;
this.setAssigned();
// Adjust state of the Dialog state machine.
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("sipDialog: setLastResponse:" + this + " lastResponse = " + this.lastResponse.getFirstLine());
}
if (this.getState() == DialogState.TERMINATED) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("sipDialog: setLastResponse -- dialog is terminated - ignoring ");
}
// This is handy for late arriving OK's that we want to ACK.
if (sipResponse.getCSeq().getMethod().equals(Request.INVITE) && statusCode == 200) {
this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(), this.lastInviteOkReceived);
}
return;
}
String cseqMethod = sipResponse.getCSeq().getMethod();
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logStackTrace();
sipStack.getStackLogger().logDebug("cseqMethod = " + cseqMethod);
sipStack.getStackLogger().logDebug("dialogState = " + this.getState());
sipStack.getStackLogger().logDebug("method = " + this.getMethod());
sipStack.getStackLogger().logDebug("statusCode = " + statusCode);
sipStack.getStackLogger().logDebug("transaction = " + transaction);
}
// responses.
if (transaction == null || transaction instanceof ClientTransaction) {
if (sipStack.isDialogCreated(cseqMethod)) {
// Make a final tag assignment.
if (getState() == null && (statusCode / 100 == 1)) {
/*
* Guard aginst slipping back into early state from confirmed state.
*/
// Was (sipResponse.getToTag() != null || sipStack.rfc2543Supported)
setState(SIPDialog.EARLY_STATE);
if ((sipResponse.getToTag() != null || sipStack.rfc2543Supported) && this.getRemoteTag() == null) {
setRemoteTag(sipResponse.getToTag());
this.setDialogId(sipResponse.getDialogId(false));
sipStack.putDialog(this);
this.addRoute(sipResponse);
}
} else if (getState() != null && getState().equals(DialogState.EARLY) && statusCode / 100 == 1) {
/*
* This case occurs for forked dialog responses. The To tag can change as a
* result of the forking. The remote target can also change as a result of the
* forking.
*/
if (cseqMethod.equals(getMethod()) && transaction != null && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)) {
setRemoteTag(sipResponse.getToTag());
this.setDialogId(sipResponse.getDialogId(false));
sipStack.putDialog(this);
this.addRoute(sipResponse);
}
} else if (statusCode / 100 == 2) {
if (cseqMethod.equals(getMethod()) && (sipResponse.getToTag() != null || sipStack.rfc2543Supported) && this.getState() != DialogState.CONFIRMED) {
setRemoteTag(sipResponse.getToTag());
this.setDialogId(sipResponse.getDialogId(false));
sipStack.putDialog(this);
this.addRoute(sipResponse);
setState(SIPDialog.CONFIRMED_STATE);
}
// Capture the OK response for later use in createAck
if (cseqMethod.equals(Request.INVITE)) {
this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(), this.lastInviteOkReceived);
}
} else if (statusCode >= 300 && statusCode <= 699 && (getState() == null || (cseqMethod.equals(getMethod()) && getState().getValue() == SIPDialog.EARLY_STATE))) {
/*
* This case handles 3xx, 4xx, 5xx and 6xx responses. RFC 3261 Section 12.3 -
* dialog termination. Independent of the method, if a request outside of a
* dialog generates a non-2xx final response, any early dialogs created
* through provisional responses to that request are terminated.
*/
setState(SIPDialog.TERMINATED_STATE);
}
/*
* This code is in support of "proxy" servers that are constructed as back to back
* user agents. This could be a dialog in the middle of the call setup path
* somewhere. Hence the incoming invite has record route headers in it. The
* response will have additional record route headers. However, for this dialog
* only the downstream record route headers matter. Ideally proxy servers should
* not be constructed as Back to Back User Agents. Remove all the record routes
* that are present in the incoming INVITE so you only have the downstream Route
* headers present in the dialog. Note that for an endpoint - you will have no
* record route headers present in the original request so the loop will not
* execute.
*/
if (this.getState() != DialogState.CONFIRMED && this.getState() != DialogState.TERMINATED) {
if (originalRequest != null) {
RecordRouteList rrList = originalRequest.getRecordRouteHeaders();
if (rrList != null) {
ListIterator<RecordRoute> it = rrList.listIterator(rrList.size());
while (it.hasPrevious()) {
RecordRoute rr = (RecordRoute) it.previous();
Route route = (Route) routeList.getFirst();
if (route != null && rr.getAddress().equals(route.getAddress())) {
routeList.removeFirst();
} else
break;
}
}
}
}
} else if (cseqMethod.equals(Request.NOTIFY) && (this.getMethod().equals(Request.SUBSCRIBE) || this.getMethod().equals(Request.REFER)) && sipResponse.getStatusCode() / 100 == 2 && this.getState() == null) {
// This is a notify response.
this.setDialogId(sipResponse.getDialogId(true));
sipStack.putDialog(this);
this.setState(SIPDialog.CONFIRMED_STATE);
} else if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2 && isTerminatedOnBye()) {
// Dialog will be terminated when the transction is terminated.
setState(SIPDialog.TERMINATED_STATE);
}
} else {
if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2 && this.isTerminatedOnBye()) {
/*
* Only transition to terminated state when 200 OK is returned for the BYE. Other
* status codes just result in leaving the state in COMPLETED state.
*/
this.setState(SIPDialog.TERMINATED_STATE);
} else {
boolean doPutDialog = false;
if (getLocalTag() == null && sipResponse.getTo().getTag() != null && sipStack.isDialogCreated(cseqMethod) && cseqMethod.equals(getMethod())) {
setLocalTag(sipResponse.getTo().getTag());
doPutDialog = true;
}
if (statusCode / 100 != 2) {
if (statusCode / 100 == 1) {
if (doPutDialog) {
setState(SIPDialog.EARLY_STATE);
this.setDialogId(sipResponse.getDialogId(true));
sipStack.putDialog(this);
}
} else {
// see https://jain-sip.dev.java.net/servlets/ReadMsg?list=users&msgNo=797
if (statusCode == 489 && (cseqMethod.equals(Request.NOTIFY) || cseqMethod.equals(Request.SUBSCRIBE))) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logDebug("RFC 3265 : Not setting dialog to TERMINATED for 489");
} else {
// see rfc 5057 for better explanation
if (!this.isReInvite() && getState() != DialogState.CONFIRMED) {
this.setState(SIPDialog.TERMINATED_STATE);
}
}
}
} else {
/*
* JvB: RFC4235 says that when sending 2xx on UAS side, state should move to
* CONFIRMED
*/
if (this.dialogState <= SIPDialog.EARLY_STATE && (cseqMethod.equals(Request.INVITE) || cseqMethod.equals(Request.SUBSCRIBE) || cseqMethod.equals(Request.REFER))) {
this.setState(SIPDialog.CONFIRMED_STATE);
}
if (doPutDialog) {
this.setDialogId(sipResponse.getDialogId(true));
sipStack.putDialog(this);
}
/*
* We put the dialog into the table. We must wait for ACK before re-INVITE is
* sent
*/
if (transaction.getState() != TransactionState.TERMINATED && sipResponse.getStatusCode() == Response.OK && cseqMethod.equals(Request.INVITE) && this.isBackToBackUserAgent) {
/*
* Acquire the flag for re-INVITE so that we cannot re-INVITE before
* ACK is received.
*/
if (!this.takeAckSem()) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("Delete dialog -- cannot acquire ackSem");
}
this.delete();
return;
}
}
}
}
}
}
use of gov.nist.javax.sip.header.RecordRoute in project XobotOS by xamarin.
the class SIPDialog method addRoute.
/**
* Add a route list extracted from a record route list. If this is a server dialog then we
* assume that the record are added to the route list IN order. If this is a client dialog
* then we assume that the record route headers give us the route list to add in reverse
* order.
*
* @param recordRouteList -- the record route list from the incoming message.
*/
private void addRoute(RecordRouteList recordRouteList) {
try {
if (this.isClientDialog()) {
// This is a client dialog so we extract the record
// route from the response and reverse its order to
// careate a route list.
this.routeList = new RouteList();
// start at the end of the list and walk backwards
ListIterator li = recordRouteList.listIterator(recordRouteList.size());
boolean addRoute = true;
while (li.hasPrevious()) {
RecordRoute rr = (RecordRoute) li.previous();
if (addRoute) {
Route route = new Route();
AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress()).clone());
route.setAddress(address);
route.setParameters((NameValueList) rr.getParameters().clone());
this.routeList.add(route);
}
}
} else {
// This is a server dialog. The top most record route
// header is the one that is closest to us. We extract the
// route list in the same order as the addresses in the
// incoming request.
this.routeList = new RouteList();
ListIterator li = recordRouteList.listIterator();
boolean addRoute = true;
while (li.hasNext()) {
RecordRoute rr = (RecordRoute) li.next();
if (addRoute) {
Route route = new Route();
AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress()).clone());
route.setAddress(address);
route.setParameters((NameValueList) rr.getParameters().clone());
routeList.add(route);
}
}
}
} finally {
if (sipStack.getStackLogger().isLoggingEnabled()) {
Iterator it = routeList.iterator();
while (it.hasNext()) {
SipURI sipUri = (SipURI) (((Route) it.next()).getAddress().getURI());
if (!sipUri.hasLrParam()) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logWarning("NON LR route in Route set detected for dialog : " + this);
sipStack.getStackLogger().logStackTrace();
}
}
}
}
}
}
use of gov.nist.javax.sip.header.RecordRoute in project XobotOS by xamarin.
the class SIPClientTransaction method createAck.
/*
* (non-Javadoc)
*
* @see javax.sip.ClientTransaction#createAck()
*/
public Request createAck() throws SipException {
SIPRequest originalRequest = this.getOriginalRequest();
if (originalRequest == null)
throw new SipException("bad state " + getState());
if (getMethod().equalsIgnoreCase(Request.ACK)) {
throw new SipException("Cannot ACK an ACK!");
} else if (lastResponse == null) {
throw new SipException("bad Transaction state");
} else if (lastResponse.getStatusCode() < 200) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("lastResponse = " + lastResponse);
}
throw new SipException("Cannot ACK a provisional response!");
}
SIPRequest ackRequest = originalRequest.createAckRequest((To) lastResponse.getTo());
// Pull the record route headers from the last reesponse.
RecordRouteList recordRouteList = lastResponse.getRecordRouteHeaders();
if (recordRouteList == null) {
// request URI.
if (lastResponse.getContactHeaders() != null && lastResponse.getStatusCode() / 100 != 3) {
Contact contact = (Contact) lastResponse.getContactHeaders().getFirst();
javax.sip.address.URI uri = (javax.sip.address.URI) contact.getAddress().getURI().clone();
ackRequest.setRequestURI(uri);
}
return ackRequest;
}
ackRequest.removeHeader(RouteHeader.NAME);
RouteList routeList = new RouteList();
// start at the end of the list and walk backwards
ListIterator<RecordRoute> li = recordRouteList.listIterator(recordRouteList.size());
while (li.hasPrevious()) {
RecordRoute rr = (RecordRoute) li.previous();
Route route = new Route();
route.setAddress((AddressImpl) ((AddressImpl) rr.getAddress()).clone());
route.setParameters((NameValueList) rr.getParameters().clone());
routeList.add(route);
}
Contact contact = null;
if (lastResponse.getContactHeaders() != null) {
contact = (Contact) lastResponse.getContactHeaders().getFirst();
}
if (!((SipURI) ((Route) routeList.getFirst()).getAddress().getURI()).hasLrParam()) {
// Contact may not yet be there (bug reported by Andreas B).
Route route = null;
if (contact != null) {
route = new Route();
route.setAddress((AddressImpl) ((AddressImpl) (contact.getAddress())).clone());
}
Route firstRoute = (Route) routeList.getFirst();
routeList.removeFirst();
javax.sip.address.URI uri = firstRoute.getAddress().getURI();
ackRequest.setRequestURI(uri);
if (route != null)
routeList.add(route);
ackRequest.addHeader(routeList);
} else {
if (contact != null) {
javax.sip.address.URI uri = (javax.sip.address.URI) contact.getAddress().getURI().clone();
ackRequest.setRequestURI(uri);
ackRequest.addHeader(routeList);
}
}
return ackRequest;
}
use of gov.nist.javax.sip.header.RecordRoute in project XobotOS by xamarin.
the class RecordRouteParser method parse.
/**
* parse the String message and generate the RecordRoute List Object
* @return SIPHeader the RecordRoute List object
* @throws ParseException if errors occur during the parsing
*/
public SIPHeader parse() throws ParseException {
RecordRouteList recordRouteList = new RecordRouteList();
if (debug)
dbg_enter("RecordRouteParser.parse");
try {
this.lexer.match(TokenTypes.RECORD_ROUTE);
this.lexer.SPorHT();
this.lexer.match(':');
this.lexer.SPorHT();
while (true) {
RecordRoute recordRoute = new RecordRoute();
super.parse(recordRoute);
recordRouteList.add(recordRoute);
this.lexer.SPorHT();
char la = lexer.lookAhead(0);
if (la == ',') {
this.lexer.match(',');
this.lexer.SPorHT();
} else if (la == '\n')
break;
else
throw createParseException("unexpected char");
}
return recordRouteList;
} finally {
if (debug)
dbg_leave("RecordRouteParser.parse");
}
}
Aggregations