use of gov.nist.javax.sip.header.RecordRouteList 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.RecordRouteList 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.RecordRouteList in project XobotOS by xamarin.
the class SIPDialog method addRoute.
/**
* Add a Route list extracted from a SIPRequest to this Dialog.
*
* @param sipRequest
*/
public synchronized void addRoute(SIPRequest sipRequest) {
if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger().logDebug("setContact: dialogState: " + this + "state = " + this.getState());
}
if (this.dialogState == CONFIRMED_STATE && SIPRequest.isTargetRefresh(sipRequest.getMethod())) {
this.doTargetRefresh(sipRequest);
}
if (this.dialogState == CONFIRMED_STATE || this.dialogState == TERMINATED_STATE) {
return;
}
// Fix for issue #225: mustn't learn Route set from mid-dialog requests
if (sipRequest.getToTag() != null)
return;
// Incoming Request has the route list
RecordRouteList rrlist = sipRequest.getRecordRouteHeaders();
// order
if (rrlist != null) {
this.addRoute(rrlist);
} else {
// Set the rotue list to the last seen route list.
this.routeList = new RouteList();
}
// put the contact header from the incoming request into
// the route set. JvB: some duplication here, ref. doTargetRefresh
ContactList contactList = sipRequest.getContactHeaders();
if (contactList != null) {
this.setRemoteTarget((ContactHeader) contactList.getFirst());
}
}
use of gov.nist.javax.sip.header.RecordRouteList 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.RecordRouteList in project XobotOS by xamarin.
the class SIPResponse method createRequest.
/**
* Generate a request from a response.
*
* @param requestURI -- the request URI to assign to the request.
* @param via -- the Via header to assign to the request
* @param cseq -- the CSeq header to assign to the request
* @param from -- the From header to assign to the request
* @param to -- the To header to assign to the request
* @return -- the newly generated sip request.
*/
public SIPRequest createRequest(SipUri requestURI, Via via, CSeq cseq, From from, To to) {
SIPRequest newRequest = new SIPRequest();
String method = cseq.getMethod();
newRequest.setMethod(method);
newRequest.setRequestURI(requestURI);
this.setBranch(via, method);
newRequest.setHeader(via);
newRequest.setHeader(cseq);
Iterator headerIterator = getHeaders();
while (headerIterator.hasNext()) {
SIPHeader nextHeader = (SIPHeader) headerIterator.next();
// Some headers do not belong in a Request ....
if (SIPMessage.isResponseHeader(nextHeader) || nextHeader instanceof ViaList || nextHeader instanceof CSeq || nextHeader instanceof ContentType || nextHeader instanceof ContentLength || nextHeader instanceof RecordRouteList || nextHeader instanceof RequireList || // JvB: added
nextHeader instanceof ContactList || nextHeader instanceof ContentLength || nextHeader instanceof ServerHeader || nextHeader instanceof ReasonHeader || nextHeader instanceof SessionExpires || nextHeader instanceof ReasonList) {
continue;
}
if (nextHeader instanceof To)
nextHeader = (SIPHeader) to;
else if (nextHeader instanceof From)
nextHeader = (SIPHeader) from;
try {
newRequest.attachHeader(nextHeader, false);
} catch (SIPDuplicateHeaderException e) {
//Should not happen!
e.printStackTrace();
}
}
try {
// JvB: all requests need a Max-Forwards
newRequest.attachHeader(new MaxForwards(70), false);
} catch (Exception d) {
}
if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
}
return newRequest;
}
Aggregations