use of javax.sip.header.RecordRouteHeader in project load-balancer by RestComm.
the class SIPBalancerForwarder method addLBRecordRoute.
/**
* @param sipProvider
* @param request
* @param hints
* @throws ParseException
*/
private void addLBRecordRoute(SipProvider sipProvider, Request request, RouteHeaderHints hints, String version, boolean isIpv6) throws ParseException {
if (logger.isDebugEnabled()) {
if (!isIpv6)
logger.debug("adding Record Router Header :" + balancerRunner.balancerContext.activeExternalHeader);
else
logger.debug("adding IPv6 Record Router Header :" + Arrays.toString(balancerRunner.balancerContext.activeExternalIpv6Header));
}
String transport = ((ViaHeader) request.getHeader(ViaHeader.NAME)).getTransport().toLowerCase();
if (sipProvider.equals(balancerRunner.balancerContext.externalSipProvider) || sipProvider.equals(balancerRunner.balancerContext.externalIpv6SipProvider)) {
int transportIndex = 0;
int internalTransportIndex = 0;
if (balancerRunner.balancerContext.internalTransport != null) {
if (logger.isDebugEnabled()) {
logger.debug("Set internal transport for adding Record Route): " + balancerRunner.balancerContext.internalTransport);
}
String currExternalTransport = transport.toUpperCase();
switch(currExternalTransport) {
case ListeningPoint.UDP:
transportIndex = UDP;
break;
case ListeningPoint.TCP:
transportIndex = TCP;
break;
case ListeningPoint.TLS:
transportIndex = TLS;
break;
case ListeningPointExt.WS:
transportIndex = WS;
break;
case ListeningPointExt.WSS:
transportIndex = WSS;
break;
}
String currInternalTransport = balancerRunner.balancerContext.internalTransport.toUpperCase();
switch(currInternalTransport) {
case ListeningPoint.UDP:
internalTransportIndex = UDP;
break;
case ListeningPoint.TCP:
internalTransportIndex = TCP;
break;
case ListeningPoint.TLS:
internalTransportIndex = TLS;
break;
case ListeningPointExt.WS:
internalTransportIndex = WS;
break;
case ListeningPointExt.WSS:
internalTransportIndex = WSS;
break;
}
} else {
transportIndex = TLS;
internalTransportIndex = TLS;
if (balancerRunner.balancerContext.terminateTLSTraffic) {
internalTransportIndex = TCP;
}
if (transport.equalsIgnoreCase(ListeningPoint.UDP)) {
transportIndex = UDP;
internalTransportIndex = UDP;
} else if (transport.equalsIgnoreCase(ListeningPoint.TCP)) {
transportIndex = TCP;
internalTransportIndex = TCP;
} else if (transport.equalsIgnoreCase(ListeningPointExt.WS)) {
transportIndex = WS;
internalTransportIndex = WS;
} else if (transport.equalsIgnoreCase(ListeningPointExt.WSS)) {
transportIndex = WSS;
if (balancerRunner.balancerContext.terminateTLSTraffic) {
internalTransportIndex = WS;
} else {
internalTransportIndex = WSS;
}
}
}
// comes from client
String received = ((ViaHeader) request.getHeader(ViaHeader.NAME)).getReceived();
RecordRouteHeader currExternalRR = null;
RecordRouteHeader currInternalRR = null;
if (!isIpv6) {
if (balancerRunner.balancerContext.routingRulesIpv4 != null && received != null) {
boolean found = false;
for (RoutingRule rule : balancerRunner.balancerContext.routingRulesIpv4) {
if (rule.getIpPattern().matcher(received).matches() && !rule.isPatch) {
found = true;
currExternalRR = balancerRunner.balancerContext.activePrivateExternalHeader[transportIndex];
currInternalRR = balancerRunner.balancerContext.activePrivateInternalHeader[internalTransportIndex];
break;
}
}
if (!found) {
currExternalRR = balancerRunner.balancerContext.activeExternalHeader[transportIndex];
currInternalRR = balancerRunner.balancerContext.activeInternalHeader[internalTransportIndex];
}
} else {
currExternalRR = balancerRunner.balancerContext.activeExternalHeader[transportIndex];
currInternalRR = balancerRunner.balancerContext.activeInternalHeader[internalTransportIndex];
}
} else {
if (balancerRunner.balancerContext.routingRulesIpv6 != null && received != null) {
boolean found = false;
for (RoutingRule rule : balancerRunner.balancerContext.routingRulesIpv6) {
if (rule.getIpPattern().matcher(received).matches() && !rule.isPatch) {
found = true;
currExternalRR = balancerRunner.balancerContext.activePrivateExternalIpv6Header[transportIndex];
currInternalRR = balancerRunner.balancerContext.activePrivateInternalIpv6Header[internalTransportIndex];
break;
}
}
if (!found) {
currExternalRR = balancerRunner.balancerContext.activeExternalIpv6Header[transportIndex];
currInternalRR = balancerRunner.balancerContext.activeInternalIpv6Header[internalTransportIndex];
}
} else {
currExternalRR = balancerRunner.balancerContext.activeExternalIpv6Header[transportIndex];
currInternalRR = balancerRunner.balancerContext.activeInternalIpv6Header[internalTransportIndex];
}
}
addTwoRecordRoutes(request, currExternalRR, currInternalRR, hints, getTransportById(internalTransportIndex));
} else {
int transportIndex = TLS;
int externalTransportIndex = TLS;
String externalTransport = transport;
URI requestURI = ((Request) request).getRequestURI();
if (requestURI.isSipURI()) {
if (((SipUri) requestURI).getTransportParam() != null)
externalTransport = ((SipUri) requestURI).getTransportParam();
}
if (transport.equalsIgnoreCase(ListeningPoint.UDP))
transportIndex = UDP;
else if (transport.equalsIgnoreCase(ListeningPoint.TCP))
transportIndex = TCP;
else if (transport.equalsIgnoreCase(ListeningPointExt.WS))
transportIndex = WS;
else if (transport.equalsIgnoreCase(ListeningPointExt.WSS))
transportIndex = WSS;
if (externalTransport.equalsIgnoreCase(ListeningPoint.UDP))
externalTransportIndex = UDP;
else if (externalTransport.equalsIgnoreCase(ListeningPoint.TCP))
externalTransportIndex = TCP;
else if (externalTransport.equalsIgnoreCase(ListeningPointExt.WS))
externalTransportIndex = WS;
else if (externalTransport.equalsIgnoreCase(ListeningPointExt.WSS))
externalTransportIndex = WSS;
// comes from app server
Header routeHeader = request.getHeader(RouteHeader.NAME);
String routeHost = null;
if (routeHeader != null)
routeHost = ((SipURI) ((RouteHeader) routeHeader).getAddress().getURI()).getHost();
RecordRouteHeader currExternalRR = null;
RecordRouteHeader currInternalRR = null;
if (!isIpv6) {
if (balancerRunner.balancerContext.routingRulesIpv4 != null && routeHost != null) {
boolean found = false;
for (RoutingRule rule : balancerRunner.balancerContext.routingRulesIpv4) {
if (rule.getIpPattern().matcher(routeHost).matches() && !rule.isPatch) {
found = true;
currExternalRR = balancerRunner.balancerContext.activePrivateExternalHeader[externalTransportIndex];
currInternalRR = balancerRunner.balancerContext.activePrivateInternalHeader[transportIndex];
break;
}
}
if (!found) {
currExternalRR = balancerRunner.balancerContext.activeExternalHeader[externalTransportIndex];
currInternalRR = balancerRunner.balancerContext.activeInternalHeader[transportIndex];
}
} else {
currExternalRR = balancerRunner.balancerContext.activeExternalHeader[externalTransportIndex];
currInternalRR = balancerRunner.balancerContext.activeInternalHeader[transportIndex];
}
} else {
if (balancerRunner.balancerContext.routingRulesIpv6 != null && routeHost != null) {
boolean found = false;
for (RoutingRule rule : balancerRunner.balancerContext.routingRulesIpv6) {
if (rule.getIpPattern().matcher(routeHost).matches() && !rule.isPatch) {
found = true;
currExternalRR = balancerRunner.balancerContext.activePrivateExternalIpv6Header[externalTransportIndex];
currInternalRR = balancerRunner.balancerContext.activePrivateInternalIpv6Header[transportIndex];
break;
}
}
if (!found) {
currExternalRR = balancerRunner.balancerContext.activeExternalIpv6Header[externalTransportIndex];
currInternalRR = balancerRunner.balancerContext.activeInternalIpv6Header[transportIndex];
}
} else {
currExternalRR = balancerRunner.balancerContext.activeExternalIpv6Header[externalTransportIndex];
currInternalRR = balancerRunner.balancerContext.activeInternalIpv6Header[transportIndex];
}
}
addTwoRecordRoutes(request, currInternalRR, currExternalRR, hints, getTransportById(transportIndex));
if (logger.isInfoEnabled()) {
logger.info("Will patch Request : \"" + request.getRequestURI() + "\" to provide public IP address for the RecordRoute header");
}
patchSipMessageForNAT(request, isIpv6);
}
}
use of javax.sip.header.RecordRouteHeader in project load-balancer by RestComm.
the class SIPBalancerForwarder method patchSipMessageForNAT.
/**
* Patch Response for NAT Environment where the Load Balancer runs on a private IP but UAs need to know the LB public IP to
* send back subsequent requests to it.
* @param sipMessage the response to patch
* @throws PeerUnavailableException
* @throws ParseException
*/
public void patchSipMessageForNAT(javax.sip.message.Message sipMessage, boolean isIpv6) {
// Need to patch the response so the subsequent requests are directly correctly at the public IP Address of the LB
// Useful for NAT environment such as Amazon EC2
String currentPublicIp = null;
if (!isIpv6)
currentPublicIp = balancerRunner.balancerContext.publicIP;
else
currentPublicIp = balancerRunner.balancerContext.publicIPv6;
if (currentPublicIp != null && !currentPublicIp.isEmpty()) {
int[] ports = new int[5];
// int wssPort = 0;
if (!isIpv6) {
for (int i = 0; i < 5; i++) ports[i] = balancerRunner.balancerContext.externalPorts[i];
// udpPort = balancerRunner.balancerContext.externalUdpPort;
// tcpPort = balancerRunner.balancerContext.externalTcpPort;
// tlsPort = balancerRunner.balancerContext.externalTlsPort;
// wsPort = balancerRunner.balancerContext.externalWsPort;
// wssPort = balancerRunner.balancerContext.externalWssPort;
} else {
for (int i = 0; i < 5; i++) ports[i] = balancerRunner.balancerContext.externalIpv6Ports[i];
// udpPort = balancerRunner.balancerContext.externalIpv6UdpPort;
// tcpPort = balancerRunner.balancerContext.externalIpv6TcpPort;
// tlsPort = balancerRunner.balancerContext.externalIpv6TlsPort;
// wsPort = balancerRunner.balancerContext.externalIpv6WsPort;
// wssPort = balancerRunner.balancerContext.externalIpv6WssPort;
}
String transport = null;
if (sipMessage instanceof Response)
transport = ((ViaHeader) sipMessage.getHeader(ViaHeader.NAME)).getTransport().toLowerCase();
else {
URI requestURI = ((Request) sipMessage).getRequestURI();
transport = ((ViaHeader) sipMessage.getHeader(ViaHeader.NAME)).getTransport().toLowerCase();
if (requestURI.isSipURI()) {
if (((SipUri) requestURI).getTransportParam() != null)
transport = ((SipUri) requestURI).getTransportParam();
}
}
String privateIp = balancerRunner.balancerContext.host;
@SuppressWarnings("unchecked") ListIterator<RecordRouteHeader> recordRouteHeaderList = sipMessage.getHeaders(RecordRouteHeader.NAME);
try {
HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory();
Header contactHeader = null;
if (!recordRouteHeaderList.hasNext()) {
if (logger.isDebugEnabled()) {
logger.debug("Record Route header list is empty");
}
}
while (recordRouteHeaderList.hasNext()) {
RecordRouteHeader recordRouteHeader = (RecordRouteHeader) recordRouteHeaderList.next();
if (logger.isDebugEnabled()) {
logger.debug("About to check Record-Route header: " + recordRouteHeader.toString());
}
if (((SipURI) recordRouteHeader.getAddress().getURI()).getHost().equals(privateIp)) {
// If this RecordRoute header is from LB
for (int port : ports) if (((SipURI) recordRouteHeader.getAddress().getURI()).getPort() == port) {
// And if the port is the external Port
SipURI sipURI = (SipURI) recordRouteHeader.getAddress().getURI();
sipURI.setHost(currentPublicIp);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Didn't patched the Record-Route because ip address is not the private one: " + ((SipURI) recordRouteHeader.getAddress().getURI()).getHost());
}
}
}
if (sipMessage.getHeader(ContactHeader.NAME) != null) {
final String displayedName = ((ContactHeader) sipMessage.getHeader("Contact")).getAddress().getDisplayName();
int currPort = balancerRunner.balancerContext.getExternalPortByTransport(transport, isIpv6);
if (displayedName != null && !displayedName.isEmpty()) {
final String contactURI = "sip:" + displayedName + "@" + currentPublicIp + ":" + currPort;
contactHeader = headerFactory.createHeader("Contact", contactURI);
((ContactHeader) contactHeader).getAddress().setDisplayName(displayedName);
} else {
final String contactURI = "sip:" + currentPublicIp + ":" + currPort;
contactHeader = headerFactory.createHeader("Contact", contactURI);
}
if (contactHeader != null) {
sipMessage.removeFirst("Contact");
sipMessage.addHeader(contactHeader);
}
}
if (logger.isDebugEnabled() && contactHeader != null) {
logger.debug("Patched the Contact header with : " + contactHeader.toString());
}
} catch (PeerUnavailableException peerUnavailableException) {
logger.error("Unexpected exception while forwarding the response \n" + sipMessage, peerUnavailableException);
} catch (ParseException parseException) {
logger.error("Unexpected exception while forwarding the response \n" + sipMessage, parseException);
} catch (NullPointerException e) {
logger.error("Unexpected exception while forwarding the response \n" + sipMessage, e);
}
}
}
use of javax.sip.header.RecordRouteHeader in project load-balancer by RestComm.
the class TestSipListener method processResponse.
public void processResponse(ResponseEvent responseReceivedEvent) {
if (abortProcessing) {
logger.error("Processing aborted");
return;
}
Response response = (Response) responseReceivedEvent.getResponse();
System.out.println("Process response : " + response);
eventListener.uacAfterResponse(response.getStatusCode(), appServer);
if (response.getStatusCode() == 491)
numberOf491s++;
RecordRouteHeader recordRouteHeader = (RecordRouteHeader) response.getHeader(RecordRouteHeader.NAME);
ContactHeader contactHeader = (ContactHeader) response.getHeader(ContactHeader.NAME);
if (contactHeader != null && "0.0.0.0".equals(((SipURI) contactHeader.getAddress().getURI()).getHost())) {
abortProcessing = true;
throw new IllegalArgumentException("we received a contact header with 0.0.0.0 in a response !");
}
if (response.getStatusCode() >= 400 && response.getStatusCode() < 999) {
this.serverErrorReceived = true;
}
if (response.getStatusCode() == 503) {
this.serviceUnavailableReceived = true;
}
if (response.toString().toLowerCase().contains("info")) {
lastInfoResponseTime = System.currentTimeMillis();
}
ClientTransaction tid = responseReceivedEvent.getClientTransaction();
CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
logger.info("Response received : Status Code = " + response.getStatusCode() + " " + cseq);
// not dropping in PRACK case on REINVITE the ClientTx can be null it seems
if (tid == null && !prackSent) {
if (countRetrans) {
nbRetrans++;
}
logger.info("Stray response -- dropping ");
return;
}
if (tid != null) {
logger.info("transaction state is " + tid.getState());
logger.info("Dialog = " + tid.getDialog());
if (tid.getDialog() != null) {
logger.info("Dialog State is " + tid.getDialog().getState());
}
}
try {
if (response.getStatusCode() > 100 && response.getStatusCode() < 200) {
informationalResponse = response;
}
if (response.getStatusCode() >= 200 && response.getStatusCode() < 700) {
logger.info("final response received : status code " + response.getStatusCode());
finalResponseReceived = true;
setFinalResponseStatus(response.getStatusCode());
setFinalResponse(response);
}
if (response.getStatusCode() == Response.OK) {
if (cseq.getMethod().equals(Request.INVITE) && sendAck) {
inviteOkResponse = response;
@SuppressWarnings("deprecation") Request ackRequest = responseReceivedEvent.getClientTransaction().createAck();
if (useToURIasRequestUri) {
ackRequest.setRequestURI(requestURI);
}
if (timeToWaitBeforeAck > 0) {
Thread.sleep(timeToWaitBeforeAck);
}
if (!sendSubsequentRequestsThroughSipProvider && tid.getDialog() != null) {
tid.getDialog().sendAck(ackRequest);
} else {
sipProvider.sendRequest(ackRequest);
}
ackSent = true;
// If the caller is supposed to send the bye
if (sendReinvite && !reinviteSent) {
List<Header> headers = new ArrayList<Header>();
Header reinviteHeader = protocolObjects.headerFactory.createHeader("ReInvite", "true");
headers.add(reinviteHeader);
if (prackSent) {
headers.add(protocolObjects.headerFactory.createHeader(RequireHeader.NAME, "100rel"));
}
sendInDialogSipRequest("INVITE", null, null, null, headers, null);
reinviteSent = true;
return;
}
if (sendBye) {
// Thread.sleep(30000);
sendBye();
}
if (sendByeAfterTerminatingNotify) {
tid.getDialog().terminateOnBye(false);
}
} else if (cseq.getMethod().equals(Request.BYE)) {
okToByeReceived = true;
} else if (cseq.getMethod().equals(Request.CANCEL)) {
this.cancelOkReceived = true;
// if (tid.getDialog().getState() == DialogState.CONFIRMED) {
// // oops cancel went in too late. Need to hang up the
// // dialog.
// logger.info("Sending BYE -- cancel went in too late !!");
// Request byeRequest = dialog.createRequest(Request.BYE);
// ClientTransaction ct = sipProvider
// .getNewClientTransaction(byeRequest);
// tid.getDialog().sendRequest(ct);
// }
} else if (cseq.getMethod().equals(Request.PUBLISH)) {
SIPETagHeader sipTagHeader = (SIPETagHeader) response.getHeader(SIPETag.NAME);
sipETag = sipTagHeader.getETag();
} else if (cseq.getMethod().equals(Request.PRACK)) {
okToPrackReceived = true;
}
} else if (response.getStatusCode() == Response.MOVED_TEMPORARILY) {
// Dialog dies as soon as you get an error response.
if (cseq.getMethod().equals(Request.INVITE)) {
// lookup the contact header
ContactHeader contHdr = (ContactHeader) response.getHeader(ContactHeader.NAME);
// we can re-use the from header
FromHeader from = ((FromHeader) response.getHeader(FromHeader.NAME));
// we use the to-address, but without the tag
ToHeader to = (ToHeader) (response.getHeader(ToHeader.NAME)).clone();
to.removeParameter("tag");
// the call-id can be re-used
CallIdHeader callID = ((CallIdHeader) response.getHeader(CallIdHeader.NAME));
// we take the next cseq
long seqNo = (((CSeqHeader) response.getHeader(CSeqHeader.NAME)).getSeqNumber());
logger.info("seqNo = " + seqNo);
CSeqHeader cseqNew = protocolObjects.headerFactory.createCSeqHeader(++seqNo, "INVITE");
// Create ViaHeaders (either use tcp or udp)
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = null;
if (!isIpv6)
viaHeader = protocolObjects.headerFactory.createViaHeader("127.0.0.1", sipProvider.getListeningPoint(protocolObjects.transport).getPort(), protocolObjects.transport, null);
else
viaHeader = protocolObjects.headerFactory.createViaHeader("::1", sipProvider.getListeningPoint(protocolObjects.transport).getPort(), protocolObjects.transport, null);
// add via headers
viaHeaders.add(viaHeader);
// create max forwards
MaxForwardsHeader maxForwardsHeader = protocolObjects.headerFactory.createMaxForwardsHeader(10);
// create invite Request
SipURI newUri = (SipURI) this.requestURI.clone();
newUri.setParameter("redirection", "true");
requestURI = newUri;
Request invRequest = protocolObjects.messageFactory.createRequest(newUri, "INVITE", callID, cseqNew, from, to, viaHeaders, maxForwardsHeader);
// we set the Request URI to the address given
SipURI contactURI = protocolObjects.addressFactory.createSipURI(null, this.listeningPoint.getIPAddress());
contactURI.setPort(this.listeningPoint.getPort());
contactURI.setTransportParam(protocolObjects.transport);
Address address = protocolObjects.addressFactory.createAddress(contactURI);
ContactHeader contact = protocolObjects.headerFactory.createContactHeader(address);
invRequest.addHeader(contact);
// the contacat header in the response contains where to redirect
// the request to -- which in this case happens to be back to the
// same location.
ContactHeader chdr = (ContactHeader) response.getHeader(ContactHeader.NAME);
SipURI sipUri = (SipURI) chdr.getAddress().getURI();
// sipUri.setLrParam();
RouteHeader routeHeader = protocolObjects.headerFactory.createRouteHeader(chdr.getAddress());
invRequest.addHeader(routeHeader);
invRequest.setRequestURI(sipUri);
logger.info("Sending INVITE to " + contHdr.getAddress().getURI().toString());
inviteClientTid = sipProvider.getNewClientTransaction(invRequest);
logger.info("New TID = " + inviteClientTid);
inviteClientTid.sendRequest();
logger.info("sendReqeust succeeded " + inviteClientTid);
Dialog dialog = inviteClientTid.getDialog();
this.dialogCount++;
this.dialog = dialog;
}
} else if (response.getStatusCode() == Response.REQUEST_TERMINATED) {
if (cseq.getMethod().equals(Request.INVITE)) {
this.requestTerminatedReceived = true;
}
} else if (response.getStatusCode() == Response.RINGING && sendUpdateOn180) {
Request updateRequest = dialog.createRequest(Request.UPDATE);
ClientTransaction ct = sipProvider.getNewClientTransaction(updateRequest);
dialog.sendRequest(ct);
} else if (response.getStatusCode() > Response.TRYING && response.getStatusCode() < Response.OK) {
RequireHeader requireHeader = (RequireHeader) response.getHeader(RequireHeader.NAME);
if (requireHeader != null && "100rel".equalsIgnoreCase(requireHeader.getOptionTag().trim())) {
Request prack = dialog.createPrack(response);
ClientTransaction ct = sipProvider.getNewClientTransaction(prack);
dialog.sendRequest(ct);
prackSent = true;
}
}
/**
* end of modified code
*/
} catch (Exception ex) {
logger.error("An unexpected exception occured while processing the response", ex);
}
}
Aggregations