this.addRecordRoute = addRecordRoute;
this.stateful = stateful;
this.presenceServer = presenceServer;
SipProvider provider = (SipProvider) request.getSource();
Request msg = request.getRequest();
if (serverTransaction == null)
{
if (jiplet.isDebugEnabled() == true)
{
jiplet
.debug("The server transaction is being obtained first time for this proxy object");
}
serverTransaction = request.getServerTransaction();
}
else
{
if (jiplet.isDebugEnabled() == true)
{
jiplet
.debug("The server transaction already exists. This proxy object is being re-used to send another request");
}
}
// PROXY BEHAVIOR
/*
* RFC 3261: 16.2: For all new requests, including any with unknown
* methods, an element intending to proxy the request MUST:
*
* 1. Validate the request (Section 16.3)
*
* 2. Preprocess routing information (Section 16.4)
*
* 3. Determine target(s) for the request (Section 16.5)
*
* 4. Forward the request to each target (Section 16.6)
*
* 5. Process all responses (Section 16.7)
*/
// 1. Validate the request (Section 16.3)
RequestValidation valid = new RequestValidation(jiplet, presenceServer);
if (valid.validateRequest(provider, request.getRequest(),
serverTransaction) == false)
{
jiplet
.warn("A request message that is to be proxied failed validation."
+ " Not going to proxy it. An appropriate response has been sent");
return;
}
// Let's check if the ACK is for the proxy: if there is no Route
// header: it is mandatory for the ACK to be forwarded
if (msg.getMethod().equals(Request.ACK))
{
ListIterator routes = msg.getHeaders(RouteHeader.NAME);
if (routes == null || !routes.hasNext())
{
if (jiplet.isDebugEnabled() == true)
{
jiplet.debug("Proxying an ACK "
+ " targeted for the proxy, we ignore it");
}
return;
}
}
if (stateful == true)
{
String method = msg.getMethod();
// Methods that creates dialogs, so that can
// generate transactions
if (method.equals(Request.INVITE)
|| method.equals(Request.SUBSCRIBE))
{
try
{
if (serverTransaction == null)
{
serverTransaction = provider
.getNewServerTransaction(msg);
}
TransactionsMapping transactionsMapping = jiplet
.getDialog(serverTransaction.getDialog(), true)
.getTransactionsMapping();
if (transactionsMapping == null)
{
transactionsMapping = new TransactionsMapping(
jiplet, serverTransaction);
// save server transaction side SipProvider in JipletDialog
Dialog serverDialog = serverTransaction.getDialog();
JipletDialog jd = jiplet.getDialog(serverDialog, true);
jd.setSipProvider((SipProvider) request.getSource());
}
}
catch (TransactionAlreadyExistsException e)
{
if (jiplet.isDebugEnabled() == true)
{
jiplet.debug("The request message to be proxied"
+ " is a retransmission, we drop it!");
}
}
}
}
// 2. Preprocess routing information (Section 16.4)
/*
* The proxy MUST inspect the Request-URI of the request. If the
* Request-URI of the request contains a value this proxy previously
* placed into a Record-Route header field (see Section 16.6 item
* 4), the proxy MUST replace the Request-URI in the request with
* the last value from the Route header field, and remove that value
* from the Route header field. The proxy MUST then proceed as if it
* received this modified request. ..... (idem to below:) 16.12. The
* proxy will inspect the URI in the topmost Route header field
* value. If it indicates this proxy, the proxy removes it from the
* Route header field (this route node has been reached).
*/
ListIterator routes = msg.getHeaders(RouteHeader.NAME);
if (routes != null)
{
if (routes.hasNext())
{
RouteHeader routeHeader = (RouteHeader) routes.next();
Address routeAddress = routeHeader.getAddress();
SipURI routeSipURI = (SipURI) routeAddress.getURI();
String h = routeSipURI.getHost();
int port = routeSipURI.getPort();
if (jiplet.hasAddress(h, port) == true)
{
if (jiplet.isDebugEnabled() == true)
{
jiplet
.debug("A request message to be proxied has this proxy in the route header. "
+ " We are going to remove the first route from "
+ " the RouteHeader");
}
routes.remove();
}
}
}
// 3. Determine target(s) for the request (Section 16.5)
/*
* The set of targets will either be predetermined by the contents
* of the request or will be obtained from an abstract location
* service. Each target in the set is represented as a URI.
*/
/*
* If the Request-URI of the request contains an maddr parameter,
* the Request-URI MUST be placed into the target set as the only
* target URI, and the proxy MUST proceed to Section 16.6.
*/
URI requestURI = msg.getRequestURI();
if (requestURI.isSipURI())
{
SipURI requestSipURI = (SipURI) requestURI;
if (requestSipURI.getMAddrParam() != null)
{
uris.clear();
uris.add(requestURI);
if (jiplet.isDebugEnabled() == true)
jiplet
.debug("While proxying a request, "
+ " the only target is the Request-URI (mAddr parameter)");
// 4. Forward the request
RequestForwarding forwarder = new RequestForwarding(jiplet,
this, request,
serverTransaction, stateful, addRecordRoute);
forwarder.forwardRequest(uris);
return;
}
}
if (stateful == true)
{
// Forward to next hop but dont reply OK right away for the
// BYE. Bye is end-to-end not hop by hop!
if (msg.getMethod().equals(Request.BYE))
{
if (serverTransaction == null)
{
if (jiplet.isDebugEnabled() == true)
jiplet
.debug("While proxying a request, null server transaction for BYE");
return;
}
Dialog d = serverTransaction.getDialog();
TransactionsMapping transactionsMapping = jiplet.getDialog(
d, true).getTransactionsMapping();
Dialog peerDialog = transactionsMapping
.getPeerDialog(serverTransaction);
Request clonedRequest = (Request) msg.clone();
FromHeader from = (FromHeader) clonedRequest
.getHeader(FromHeader.NAME);
from.removeParameter("tag");
ToHeader to = (ToHeader) clonedRequest
.getHeader(ToHeader.NAME);
to.removeParameter("tag");
if (peerDialog.getState() != null)
{
JipletDialog clientDialog = jiplet.getDialog(peerDialog, false);
SipProvider clientProvider = clientDialog.getSipProvider();
ListeningPoint lp = clientProvider.getListeningPoints()[0];
// TODO, need to save the right transport - save LP instead of SipProvider?
// (in JipletDialog)
ViaHeader via = jiplet.getHeaderFactory().createViaHeader(lp.getIPAddress(),
lp.getPort(), lp.getTransport(), null);
clonedRequest.addHeader(via);
ClientTransaction newct = clientProvider
.getNewClientTransaction(clonedRequest);
transactionsMapping
.addMapping(serverTransaction, newct);
peerDialog.sendRequest(newct);
jiplet.registerForResponse(clonedRequest, 60000L);