&& clientsTransactionList.size() > 1)
{
Dialog dialog = clientTransaction.getDialog();
Request byeRequest = dialog.createRequest(Request.BYE);
ClientTransaction ct = responseProvider
.getNewClientTransaction(byeRequest);
dialog.sendRequest(ct);
// we have to remove the transaction from the table:
transactionsMapping.removeMapping(clientTransaction);
return;
}
else
{
if (serverTransaction != null)
transactionsMapping.addMapping(serverTransaction,
clientTransaction);
}
}
if (serverTransaction == null)
{
ListeningPoint defaultLP = jiplet.getListeningPointDefault();
jiplet.getSipProvider(defaultLP).sendResponse(response);
return;
}
else
{
// we can try to modify the tags:
Dialog dialog = serverTransaction.getDialog();
if (dialog != null)
{
String localTag = dialog.getLocalTag();
String remoteTag = dialog.getRemoteTag();
ToHeader toHeader = (ToHeader) response
.getHeader(ToHeader.NAME);
FromHeader fromHeader = (FromHeader) response
.getHeader(FromHeader.NAME);
if (localTag != null && remoteTag != null)
{
if (dialog.isServer())
{
toHeader.setTag(localTag);
}
else
{
fromHeader.setTag(remoteTag);
}
}
}
// 8. Record-Route - modify record route header if needed
/*
* If the selected response contains a Record-Route header field
* value originally provided by this proxy, the proxy MAY choose
* to rewrite the value before forwarding the response. This
* allows the proxy to provide different URIs for itself to the
* next upstream and downstream elements. A proxy may choose to
* use this mechanism for any reason. For instance, it is useful
* for multi-homed hosts.
*/
ListIterator rrHeaders = response
.getHeaders(RecordRouteHeader.NAME);
while (rrHeaders.hasNext())
{
// look for the 1st one to replace, replace it & get out
RecordRouteHeader rr = (RecordRouteHeader) rrHeaders.next();
URI uri = rr.getAddress().getURI();
if (uri instanceof SipURI)
{
SipURI sipURI = (SipURI) uri;
// is this a record route header we added?
if (jiplet.hasAddress(sipURI.getHost(), sipURI
.getPort()))
{
// does this one need replacing?
String user = sipURI.getUser();
if (user != null)
{
StringTokenizer tok = new StringTokenizer(user,
"-");
if (tok.countTokens() == 2)
{
SipURI sourceURI = jiplet
.getAddressFactory().createSipURI(
null, tok.nextToken());
sourceURI.setPort(Integer.valueOf(
tok.nextToken()).intValue());
sourceURI.setLrParam();
// rewrite it back into the RR header
rr.getAddress().setURI(sourceURI);
rrHeaders.set(rr);
break;
}
}
}
}
}
try
{
serverTransaction.sendResponse(response);
}
catch (InvalidArgumentException e)
{
// this exception only happens if the Response was created
// by Dialog.createReliableProvisionalResponse(int) and the
// application calls ServerTransaction.sendResponse() to
// send it
JipletLogger
.error("Response forwarding failed - invalid send method for reliable provisional response - need to add a check for this and call dialog method sendReliableProvisionalResponse() instead. Response = \n"
+ response.toString());
}
}
/** ************************************************************************ */
/** ************ 10. Generate CANCELs ******* */
/** ************************************************************************* */
/*
* If the forwarded response was a final response, the jiplet MUST
* generate a CANCEL request for all pending client transactions
* associated with this response context. A jiplet SHOULD also
* generate a CANCEL request for all pending client transactions
* associated with this response context when it receives a 6xx
* response. A pending client transaction is one that has received a
* provisional response, but no final response (it is in the
* proceeding state) and has not had an associated CANCEL generated
* for it. Generating CANCEL requests is described in Section 9.1.
*/
if (response.getStatusCode() == Response.OK
|| (response.getStatusCode() >= Response.BUSY_EVERYWHERE && response
.getStatusCode() <= Response.SESSION_NOT_ACCEPTABLE))
{
Vector clientsTransactionList = transactionsMapping
.getClientTransactions(serverTransaction);
for (Enumeration e = clientsTransactionList.elements(); e
.hasMoreElements();)
{
ClientTransaction ctr = (ClientTransaction) e.nextElement();
if (ctr != clientTransaction)
{
TransactionState transactionState = ctr.getState();
if (transactionState == null
|| transactionState.getValue() == TransactionState.PROCEEDING
.getValue())
{
/*
* 9.1: The following procedures are used to
* construct a CANCEL request. The Request-URI,
* Call-ID, To, the numeric part of CSeq, and From
* header fields in the CANCEL request MUST be
* identical to those in the request being
* cancelled, including tags. A CANCEL constructed
* by a client MUST have only a single Via header
* field value matching the top Via value in the
* request being cancelled. Using the same values
* for these header fields allows the CANCEL to be
* matched with the request it cancels (Section 9.2
* indicates how such matching occurs). However, the
* method part of the CSeq header field MUST have a
* value of CANCEL. This allows it to be identified
* and processed as a transaction in its own right
* (See Section 17).
*
* If the request being cancelled contains a Route
* header field, the CANCEL request MUST include
* that Route header field's values.
*/
Request cancelRequest = ctr.createCancel();
// Let's keep only the top most via header:
ListIterator cancelViaList = cancelRequest
.getHeaders(ViaHeader.NAME);
cancelRequest.removeHeader(ViaHeader.NAME);
cancelRequest.addHeader((ViaHeader) cancelViaList
.next());
SipURI localAddr = (SipURI) ctr.getDialog()
.getLocalParty().getURI();
SipProvider p = jiplet.getSipProvider(localAddr
.getHost(), localAddr.getPort());
if (p == null)
{
ListeningPoint defaultLP = jiplet
.getListeningPointDefault();
p = jiplet.getSipProvider(defaultLP);
}
ClientTransaction ct = p
.getNewClientTransaction(cancelRequest);
ct.sendRequest();
}
}
}
}
}