Search in sources :

Example 6 with Node

use of org.mobicents.tools.heartbeat.api.Node in project load-balancer by RestComm.

the class SIPBalancerForwarder method processRequest.

/*
     * (non-Javadoc)
     * @see javax.sip.SipListener#processRequest(javax.sip.RequestEvent)
     */
public void processRequest(RequestEvent requestEvent) {
    // This will be invoked only by external endpoint
    BalancerAppContent content = (BalancerAppContent) requestEvent.getSource();
    boolean isIpv6 = content.isIpv6();
    final SipProvider sipProvider = content.getProvider();
    final Request request = requestEvent.getRequest();
    final String requestMethod = request.getMethod();
    if (logger.isDebugEnabled()) {
        logger.debug("got request:\n" + request);
    }
    if ((requestMethod.equals(Request.OPTIONS) || requestMethod.equals(Request.INFO)) && request.getHeader("Mobicents-Heartbeat") != null && sipProvider == balancerRunner.balancerContext.internalSipProvider) {
        byte[] bytes = (byte[]) request.getContent();
        Properties prop = new Properties();
        try {
            prop.load(new ByteArrayInputStream(bytes, 0, bytes.length));
            Node node = new Node(prop.getProperty("hostname"), prop.getProperty("ip"));
            for (String id : prop.stringPropertyNames()) {
                node.getProperties().put(id, prop.getProperty(id));
            }
            ArrayList<Node> list = new ArrayList<Node>();
            list.add(node);
            this.register.handlePingInRegister(list);
            Response response = balancerRunner.balancerContext.messageFactory.createResponse(Response.OK, request);
            sipProvider.sendResponse(response);
            return;
        } catch (Exception e) {
            logger.error("Failure parsing heartbeat properties from this request " + request, e);
        }
    }
    // Issue 10: https://telestax.atlassian.net/browse/LB-10
    if (request.getContent() != null || (requestMethod.equals(Request.REGISTER) && sipProvider != balancerRunner.balancerContext.internalSipProvider)) {
        SIPMessage message = (SIPMessage) request;
        String initialRemoteAddr = message.getPeerPacketSourceAddress().getHostAddress();
        String initialRemotePort = String.valueOf(message.getPeerPacketSourcePort());
        Header remoteAddrHeader = null;
        Header remotePortHeader = null;
        try {
            remoteAddrHeader = SipFactory.getInstance().createHeaderFactory().createHeader("X-Sip-Balancer-InitialRemoteAddr", initialRemoteAddr);
            remotePortHeader = SipFactory.getInstance().createHeaderFactory().createHeader("X-Sip-Balancer-InitialRemotePort", initialRemotePort);
        } catch (PeerUnavailableException e) {
            logger.error("Unexpected exception while creating custom headers for REGISTER message ", e);
        } catch (ParseException e) {
            logger.error("Unexpected exception while creating custom headers for REGISTER message ", e);
        }
        if (remoteAddrHeader != null)
            request.addHeader(remoteAddrHeader);
        if (remotePortHeader != null)
            request.addHeader(remotePortHeader);
    }
    try {
        updateStats(request);
        forwardRequest(sipProvider, request, isIpv6);
    } catch (Throwable throwable) {
        logger.error("Unexpected exception while forwarding the request " + request, throwable);
        if (!Request.ACK.equalsIgnoreCase(requestMethod)) {
            try {
                Response response = balancerRunner.balancerContext.messageFactory.createResponse(Response.SERVER_INTERNAL_ERROR, request);
                sipProvider.sendResponse(response);
            } catch (Exception e) {
                logger.error("Unexpected exception while trying to send the error response for this " + request, e);
            }
        }
    }
}
Also used : PeerUnavailableException(javax.sip.PeerUnavailableException) Node(org.mobicents.tools.heartbeat.api.Node) Request(javax.sip.message.Request) ArrayList(java.util.ArrayList) Properties(java.util.Properties) InvalidArgumentException(javax.sip.InvalidArgumentException) ParseException(java.text.ParseException) TransportNotSupportedException(javax.sip.TransportNotSupportedException) TransportAlreadySupportedException(javax.sip.TransportAlreadySupportedException) ObjectInUseException(javax.sip.ObjectInUseException) PeerUnavailableException(javax.sip.PeerUnavailableException) TooManyListenersException(java.util.TooManyListenersException) SipException(javax.sip.SipException) UnknownHostException(java.net.UnknownHostException) TransactionUnavailableException(javax.sip.TransactionUnavailableException) Response(javax.sip.message.Response) SIPResponse(gov.nist.javax.sip.message.SIPResponse) ReasonHeader(javax.sip.header.ReasonHeader) ContactHeader(javax.sip.header.ContactHeader) ViaHeader(javax.sip.header.ViaHeader) CallIdHeader(javax.sip.header.CallIdHeader) Header(javax.sip.header.Header) MaxForwardsHeader(javax.sip.header.MaxForwardsHeader) ToHeader(javax.sip.header.ToHeader) RouteHeader(javax.sip.header.RouteHeader) FromHeader(javax.sip.header.FromHeader) RecordRouteHeader(javax.sip.header.RecordRouteHeader) ByteArrayInputStream(java.io.ByteArrayInputStream) SIPMessage(gov.nist.javax.sip.message.SIPMessage) ParseException(java.text.ParseException) SipProvider(javax.sip.SipProvider)

Example 7 with Node

use of org.mobicents.tools.heartbeat.api.Node in project load-balancer by RestComm.

the class SIPBalancerForwarder method setExtraServerNodes.

private void setExtraServerNodes(String extraServerNodesString) {
    ArrayList<Node> extraServerNodes = new ArrayList<Node>();
    extraServerAddresses = extraServerNodesString.split(",");
    extraServerPorts = new int[extraServerAddresses.length];
    for (int q = 0; q < extraServerAddresses.length; q++) {
        int indexOfPort = extraServerAddresses[q].indexOf(':');
        if (indexOfPort > 0) {
            extraServerPorts[q] = Integer.parseInt(extraServerAddresses[q].substring(indexOfPort + 1, extraServerAddresses[q].length()));
            extraServerAddresses[q] = extraServerAddresses[q].substring(0, indexOfPort);
        } else {
            extraServerPorts[q] = 5060;
        }
        ExtraServerNode extraServerNode = new ExtraServerNode("ExtraServerNode" + q + "-" + extraServerAddresses[q] + ":" + extraServerPorts[q], extraServerAddresses[q]);
        HashMap<String, String> properties = new HashMap<String, String>();
        properties.put("udpPort", "" + extraServerPorts[q]);
        properties.put("tcpPort", "" + extraServerPorts[q]);
        properties.put("httpPort", "808" + q);
        properties.put("version", "0");
        extraServerNode.setProperties(properties);
        extraServerNodes.add(extraServerNode);
        logger.info("Extra Server: " + extraServerAddresses[q] + ":" + extraServerPorts[q]);
    }
    if (balancerRunner.balancerContext.lbConfig.getSipConfiguration().isPerformanceTestingMode()) {
        register.handlePingInRegister(extraServerNodes);
        logger.info("Extra Servers registered as active nodes!");
    }
}
Also used : HashMap(java.util.HashMap) Node(org.mobicents.tools.heartbeat.api.Node) ArrayList(java.util.ArrayList) ListeningPoint(javax.sip.ListeningPoint)

Example 8 with Node

use of org.mobicents.tools.heartbeat.api.Node in project load-balancer by RestComm.

the class SIPBalancerForwarder method removeRouteHeadersMeantForLB.

/**
 * Remove the different route headers that are meant for the Load balancer.
 * There is two cases here :
 * <ul>
 * <li>* Requests coming from external and going to the cluster : dialog creating requests can have route header so that they go through the LB and subsequent requests
 * will have route headers since the LB record routed</li>
 * <li>* Requests coming from the cluster and going to external : dialog creating requests can have route header so that they go through the LB - those requests will define in the route header
 * the originating node of the request so that that subsequent requests are routed to the originating node if still alive</li>
 * </ul>
 *
 * @param request
 */
private RouteHeaderHints removeRouteHeadersMeantForLB(Request request, boolean isIpv6) {
    if (logger.isDebugEnabled()) {
        logger.debug("Checking if there is any route headers meant for the LB to remove...");
    }
    Node node = null;
    String callVersion = null;
    int numberOfRemovedRouteHeaders = 0;
    if (balancerRunner.balancerContext.matchingHostnameForRoute != null) {
        RouteHeader routeHeader = (RouteHeader) request.getHeader(RouteHeader.NAME);
        if (routeHeader != null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Matching host name for route is : " + balancerRunner.balancerContext.matchingHostnameForRoute);
                logger.debug("Matching host name and subdomain: " + balancerRunner.balancerContext.isFilterSubdomain);
            }
            if (!balancerRunner.balancerContext.isFilterSubdomain) {
                if (((SipURI) routeHeader.getAddress().getURI()).getHost().equals(balancerRunner.balancerContext.matchingHostnameForRoute))
                    request.removeFirst(RouteHeader.NAME);
            } else {
                if (((SipURI) routeHeader.getAddress().getURI()).getHost().endsWith("." + balancerRunner.balancerContext.matchingHostnameForRoute))
                    request.removeFirst(RouteHeader.NAME);
            }
        }
    }
    // Removing first routeHeader if it is for the sip balancer
    RouteHeader routeHeader = (RouteHeader) request.getHeader(RouteHeader.NAME);
    if (routeHeader != null) {
        SipURI routeUri = (SipURI) routeHeader.getAddress().getURI();
        callVersion = routeUri.getParameter(ROUTE_PARAM_NODE_VERSION);
        String transport = ((ViaHeader) request.getHeader("Via")).getTransport();
        if (routeUri.getTransportParam() != null)
            transport = routeUri.getTransportParam();
        if (!isHeaderExternal(routeUri.getHost(), routeUri.getPort(), transport, isIpv6)) {
            if (logger.isDebugEnabled()) {
                logger.debug("this route header is for the LB removing it " + routeUri);
            }
            numberOfRemovedRouteHeaders++;
            request.removeFirst(RouteHeader.NAME);
            routeHeader = (RouteHeader) request.getHeader(RouteHeader.NAME);
            // since we used double record routing we may have 2 routes corresponding to us here
            // for ACK and BYE from caller for example
            node = checkRouteHeaderForSipNode(routeUri);
            if (routeHeader != null) {
                routeUri = (SipURI) routeHeader.getAddress().getURI();
                transport = ((ViaHeader) request.getHeader("Via")).getTransport();
                if (routeUri.getTransportParam() != null)
                    transport = routeUri.getTransportParam();
                if (!isHeaderExternal(routeUri.getHost(), routeUri.getPort(), transport, isIpv6)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("this route header is for the LB removing it " + routeUri);
                    }
                    numberOfRemovedRouteHeaders++;
                    request.removeFirst(RouteHeader.NAME);
                    if (node == null) {
                        node = checkRouteHeaderForSipNode(routeUri);
                    }
                    // SIPP sometimes appends more headers and lets remove them here. There is no legitimate reason
                    // more than two SIP LB headers to be place next to each-other, so this cleanup is SAFE!
                    boolean moreHeaders = true;
                    while (moreHeaders) {
                        RouteHeader extraHeader = (RouteHeader) request.getHeader(RouteHeader.NAME);
                        if (extraHeader != null) {
                            SipURI u = (SipURI) extraHeader.getAddress().getURI();
                            transport = ((ViaHeader) request.getHeader("Via")).getTransport();
                            if (u.getTransportParam() != null)
                                transport = u.getTransportParam();
                            if (!isHeaderExternal(u.getHost(), u.getPort(), transport, isIpv6)) {
                                numberOfRemovedRouteHeaders++;
                                request.removeFirst(RouteHeader.NAME);
                            } else {
                                moreHeaders = false;
                            }
                        } else {
                            moreHeaders = false;
                        }
                    }
                }
            }
        }
    }
    if (node == null) {
        if (request.getRequestURI().isSipURI()) {
            node = checkRouteHeaderForSipNode((SipURI) request.getRequestURI());
        }
    }
    // logger.info(request.ge + " has this hint " + node);
    ToHeader to = (ToHeader) (request.getHeader(ToHeader.NAME));
    /*
         * We determine if this is subsequent based on To tag instead of checking route header metadata.
         */
    boolean subsequent = to.getTag() != null;
    if (logger.isDebugEnabled()) {
        logger.debug("Number of removed Route headers is " + numberOfRemovedRouteHeaders);
    }
    // https://github.com/RestComm/load-balancer/issues/128
    if (numberOfRemovedRouteHeaders != 2 && subsequent && !request.getMethod().equalsIgnoreCase(Request.ACK)) {
        logger.warn("A subsequent request should have two Route headers. Number of removed Route headers is " + numberOfRemovedRouteHeaders + ". This indicates a client is removing important headers.");
    }
    return new RouteHeaderHints(node, subsequent, callVersion);
}
Also used : RouteHeader(javax.sip.header.RouteHeader) RecordRouteHeader(javax.sip.header.RecordRouteHeader) ViaHeader(javax.sip.header.ViaHeader) Node(org.mobicents.tools.heartbeat.api.Node) ToHeader(javax.sip.header.ToHeader) SipURI(javax.sip.address.SipURI) ListeningPoint(javax.sip.ListeningPoint)

Example 9 with Node

use of org.mobicents.tools.heartbeat.api.Node in project load-balancer by RestComm.

the class HttpResponseHandler method handleHttpResponse.

private void handleHttpResponse(ChannelHandlerContext ctx, final MessageEvent e) throws Exception {
    if (e.getMessage() instanceof HttpChunkTrailer) {
        HttpChunkTrailer chunk = (HttpChunkTrailer) e.getMessage();
        balancerRunner.balancerContext.httpBytesToClient.addAndGet(chunk.getContent().capacity());
        if (chunk.isLast())
            readingChunks = false;
        AdvancedChannel ac = HttpChannelAssociations.channels.get(new AdvancedChannel(e.getChannel()));
        Channel channel = null;
        if (ac != null)
            channel = ac.getChannel();
        if (channel != null) {
            if (logger.isDebugEnabled())
                logger.debug("Send chunked response from : " + e.getChannel().getRemoteAddress() + " to : " + channel.getRemoteAddress() + " capacity : " + chunk.getContent().capacity());
            channel.write(chunk);
        }
    } else if (!readingChunks || !(e.getMessage() instanceof DefaultHttpChunk)) {
        response = (HttpResponse) e.getMessage();
        int stsusCode = response.getStatus().getCode();
        if (stsusCode > 399 && stsusCode < 600) {
            AdvancedChannel ac = HttpChannelAssociations.channels.get(new AdvancedChannel(e.getChannel()));
            if (ac != null && ac.isCheckNeed()) {
                InetSocketAddress address = (InetSocketAddress) e.getChannel().getRemoteAddress();
                InvocationContext invocationContext = balancerRunner.getLatestInvocationContext();
                KeySip keySip = new KeySip(address.getHostString(), address.getPort(), false);
                Node currNode = invocationContext.sipNodeMap(false).get(keySip);
                if (currNode != null) {
                    currNode.setBad(true);
                    String instanseId = currNode.getProperties().get(Protocol.RESTCOMM_INSTANCE_ID);
                    if (instanseId != null)
                        invocationContext.httpNodeMap.get(new KeyHttp(currNode.getProperties().get(Protocol.RESTCOMM_INSTANCE_ID))).setBad(true);
                    logger.error("Error code [" + stsusCode + "] detected in HTTP response. From  node : " + currNode + ". This node will marked as bad.");
                    String currInstanceId = (String) currNode.getProperties().get("Restcomm-Instance-Id");
                    if (currInstanceId != null)
                        logger.warn("Node : " + invocationContext.httpNodeMap.remove(new KeyHttp(currInstanceId)) + " from httpNodeMap");
                    // invocationContext.badSipNodeMap(false).put(keySip, currNode);
                    invocationContext.balancerAlgorithm.nodeRemoved(currNode);
                }
            // TODO CHECK REQUEST AND REMOVE NODE
            }
        }
        updateStatistic(response);
        balancerRunner.balancerContext.httpBytesToClient.addAndGet(response.getContent().capacity());
        if (response.isChunked()) {
            readingChunks = true;
        }
        AdvancedChannel ac = HttpChannelAssociations.channels.get(new AdvancedChannel(e.getChannel()));
        Channel channel = null;
        if (ac != null)
            channel = ac.getChannel();
        if (channel != null) {
            if (logger.isDebugEnabled())
                logger.debug("Send response from : " + e.getChannel().getRemoteAddress() + " to : " + channel.getRemoteAddress() + " capacity : " + response.getContent().capacity());
            channel.write(response);
        }
        Set<String> headers = response.getHeaderNames();
        if (headers.contains("Sec-WebSocket-Protocol")) {
            if (response.getHeader("Sec-WebSocket-Protocol").equalsIgnoreCase("sip")) {
                if (logger.isDebugEnabled()) {
                    logger.debug("WebSocket response");
                }
                wsVersion = response.getHeader(Names.SEC_WEBSOCKET_VERSION);
                // Modify the Server pipeline
                ChannelPipeline p = channel.getPipeline();
                websocketModifyServerPipelineFactory = new WebsocketModifyServerPipelineFactory();
                websocketModifyServerPipelineFactory.upgradeServerPipelineFactory(p, wsVersion);
            }
        }
    } else {
        HttpChunk chunk = (HttpChunk) e.getMessage();
        balancerRunner.balancerContext.httpBytesToClient.addAndGet(chunk.getContent().capacity());
        if (chunk.isLast())
            readingChunks = false;
        AdvancedChannel ac = HttpChannelAssociations.channels.get(new AdvancedChannel(e.getChannel()));
        Channel channel = null;
        if (ac != null)
            channel = ac.getChannel();
        if (channel != null) {
            if (logger.isDebugEnabled())
                logger.debug("Send chunked response from : " + e.getChannel().getRemoteAddress() + " to : " + channel.getRemoteAddress() + " capacity : " + chunk.getContent().capacity());
            channel.write(chunk);
        }
    }
}
Also used : Set(java.util.Set) DefaultHttpChunk(org.jboss.netty.handler.codec.http.DefaultHttpChunk) InetSocketAddress(java.net.InetSocketAddress) Channel(org.jboss.netty.channel.Channel) Node(org.mobicents.tools.heartbeat.api.Node) HttpResponse(org.jboss.netty.handler.codec.http.HttpResponse) ChannelPipeline(org.jboss.netty.channel.ChannelPipeline) HttpChunkTrailer(org.jboss.netty.handler.codec.http.HttpChunkTrailer) KeySip(org.mobicents.tools.sip.balancer.KeySip) InvocationContext(org.mobicents.tools.sip.balancer.InvocationContext) KeyHttp(org.mobicents.tools.sip.balancer.KeyHttp) DefaultHttpChunk(org.jboss.netty.handler.codec.http.DefaultHttpChunk) HttpChunk(org.jboss.netty.handler.codec.http.HttpChunk)

Example 10 with Node

use of org.mobicents.tools.heartbeat.api.Node in project load-balancer by RestComm.

the class NodeRegisterImpl method shutdownRequestReceived.

@Override
public synchronized void shutdownRequestReceived(MessageEvent e, JsonObject json) {
    boolean was = false;
    logger.info("LB got graceful shutdown from Node : " + json);
    KeySession keySession = new KeySession(json.get(Protocol.SESSION_ID).toString());
    for (Entry<String, InvocationContext> ctxEntry : balancerRunner.contexts.entrySet()) {
        InvocationContext ctx = ctxEntry.getValue();
        Node nodePresentIPv4 = ctx.sessionNodeMap(false).get(keySession);
        Node nodePresentIPv6 = null;
        if (nodePresentIPv4 != null) {
            logger.info("LB will exclude node " + nodePresentIPv4 + "for new calls because of shutdown request");
            nodePresentIPv4.setGracefulShutdown(true);
            String instanseId = nodePresentIPv4.getProperties().get(Protocol.RESTCOMM_INSTANCE_ID);
            if (instanseId != null)
                ctx.httpNodeMap.get(new KeyHttp(instanseId)).setGracefulShutdown(true);
            was = true;
        } else if ((nodePresentIPv6 = balancerRunner.getLatestInvocationContext().sessionNodeMap(true).get(keySession)) != null) {
            logger.info("LB will exclude node " + nodePresentIPv6 + "for new calls because of shutdown request");
            nodePresentIPv6.setGracefulShutdown(true);
            was = true;
        }
    }
    if (!was) {
        logger.error("LB got shutdown request ( " + json + " ) from node which not pesent in maps");
    }
    if (e != null)
        writeResponse(e, HttpResponseStatus.OK, Protocol.SHUTDOWN, Protocol.OK);
}
Also used : Node(org.mobicents.tools.heartbeat.api.Node)

Aggregations

Node (org.mobicents.tools.heartbeat.api.Node)70 ListeningPoint (javax.sip.ListeningPoint)19 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)11 Via (gov.nist.javax.sip.header.Via)7 HashMap (java.util.HashMap)7 SIPHeader (gov.nist.javax.sip.header.SIPHeader)6 ParseException (java.text.ParseException)6 ArrayList (java.util.ArrayList)6 ViaHeader (javax.sip.header.ViaHeader)6 RouteHeader (javax.sip.header.RouteHeader)5 SIPResponse (gov.nist.javax.sip.message.SIPResponse)4 UnknownHostException (java.net.UnknownHostException)4 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)4 InvalidArgumentException (javax.sip.InvalidArgumentException)4 SipException (javax.sip.SipException)4 SipURI (javax.sip.address.SipURI)4 RecordRouteHeader (javax.sip.header.RecordRouteHeader)4 ToHeader (javax.sip.header.ToHeader)4 Response (javax.sip.message.Response)4 Test (org.junit.Test)4