Package org.cipango.diameter.node

Source Code of org.cipango.diameter.node.Node$WatchdogTimeout

// ========================================================================
// Copyright 2008-2009 NEXCOM Systems
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================

package org.cipango.diameter.node;

import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import org.cipango.diameter.ApplicationId;
import org.cipango.diameter.Dictionary;
import org.cipango.diameter.app.DiameterContext;
import org.cipango.diameter.base.Common;
import org.cipango.diameter.bio.DiameterSocketConnector;
import org.cipango.diameter.log.BasicMessageLog;
import org.cipango.diameter.router.DefaultRouter;
import org.cipango.diameter.router.DiameterRouter;
import org.cipango.server.Server;
import org.cipango.server.session.SessionManager.SessionScope;
import org.eclipse.jetty.util.LazyList;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.component.AggregateLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;


/**
* A Diameter node is a host process that implements the Diameter protocol,
* and acts either as a Client, Agent or Server.
* Can be used standalone or linked to a {@link Server}.
*/
public class Node extends AbstractLifeCycle implements DiameterHandler, Dumpable
{
  public static String[] __dictionaryClasses =
  {
    "org.cipango.diameter.base.Common",
    "org.cipango.diameter.base.Accounting",
    "org.cipango.diameter.ims.IMS",
    "org.cipango.diameter.ims.Cx",
    "org.cipango.diameter.ims.Sh",
    "org.cipango.diameter.ims.Zh"
  };
 
  public static final String DEFAULT_REALM = "cipango.org";
  public static final String DEFAULT_PRODUCT_NAME = "cipango";
  public static final int NEXCOM_OID = 26588;
 
  public static final long DEFAULT_TW = 30000;
  public static final long DEFAULT_TC = 30000;
  public static final long DEFAULT_REQUEST_TIMEOUT = 10000;
 
  private Server _server;
 
  private String _realm = DEFAULT_REALM;
  private String _identity;
  private int _vendorId = NEXCOM_OID;
  private String _productName = DEFAULT_PRODUCT_NAME;
 
  private long _tw = DEFAULT_TW;
  private long _tc = DEFAULT_TC;
  private long _requestTimeout = DEFAULT_REQUEST_TIMEOUT;
 
  private DiameterConnector[] _connectors;
 
  private Peer[] _peers;
   
  private DiameterHandler _handler;
  private SessionManager _sessionManager;
 
  private ScheduledExecutorService _scheduler;

  private Set<ApplicationId> _supportedApplications = new HashSet<ApplicationId>();
 
  private DiameterRouter _router;
 
  protected final AtomicLong _statsStartedAt = new AtomicLong(-1L);
   
  public Node()
  {
    setHandler(new DiameterContext());
  }
 
  public Node(int port) throws IOException
  {
    setHandler(new DiameterContext());
    DiameterSocketConnector connector = new DiameterSocketConnector();
    connector.setHost(InetAddress.getLocalHost().getHostAddress());
    connector.setMessageListener(new BasicMessageLog());
    connector.setPort(port);
    setConnectors(new DiameterConnector[] {connector});
  }
 
  public void setServer(Server server)
  {
    _server = server;
  }
 
  public Server getServer()
  {
    return _server;
  }
 
  public void setConnectors(DiameterConnector[] connectors)
  {
    if (connectors != null)
    {
      for (int i = 0; i < connectors.length; i++)
        connectors[i].setNode(this);
    }
    if (_server != null)
      _server.getContainer().update(this, _connectors, connectors, "connectors", true);
    _connectors = connectors;
  }
 
  public DiameterConnector[] getConnectors()
    {
        return _connectors;
    }
 
  public void addConnector(DiameterConnector connector)
    {
        setConnectors((DiameterConnector[])LazyList.addToArray(getConnectors(), connector, DiameterConnector.class));
    }
 
  public synchronized void addPeer(Peer peer)
  {
    peer.setNode(this);
   
    Peer[] peers = (Peer[]) LazyList.addToArray(_peers, peer, Peer.class);
   
    if (_server != null)
      _server.getContainer().update(this, _peers, peers, "peers", true);
   
    _peers = peers;
   
    if( isStarted())
      _router.peerAdded(peer);
   
  }
 
  public synchronized void removePeer(Peer peer)
  {   
    Peer[] peers = (Peer[]) LazyList.removeFromArray(_peers, peer);
    peers = peers.clone();
   
    if (_server != null)
      _server.getContainer().update(this, _peers, peers, "peers", true);
   
    _peers = peers;
   
    peer.stop();
   
    if( isStarted())
      _router.peerRemoved(peer);
  }
 

  public Peer[] getPeers()
  {
    return _peers;
  }
 
  @Override
  protected void doStart() throws Exception
  {
    for (int i = 0; i < __dictionaryClasses.length; i++)
    {
      Dictionary.getInstance().load(Loader.loadClass(getClass(), __dictionaryClasses[i]));
    }
     
    if (_identity == null)
      _identity = InetAddress.getLocalHost().getHostName();
   
    _sessionManager = new SessionManager();
   
    if (_server != null)
      _server.getContainer().update(this, null, _sessionManager, "sessionManager");
   
    _sessionManager.setNode(this);
   
    if (_connectors != null)
    {
      for (int i = 0; i < _connectors.length; i++)
      {
        _connectors[i].start();
      }
    }
   
    _scheduler = new ScheduledThreadPoolExecutor(1);
   
    if (_router == null)
      _router = new DefaultRouter();
   
    if (_router instanceof LifeCycle)
      ((LifeCycle) _router).start();
   
    if (_server != null)
      _server.getContainer().update(this, null, _router, "diameterRouter");
   
    synchronized (this)
    {
      if (_peers != null)
      {
        for (Peer peer : _peers)
        {
          try
          {
            peer.start();
            _router.peerAdded(peer);
          }
          catch (Exception e)
          {
            Log.warn("failed to start peer: " + peer, e);
          }
        }
      }
    } 
   
    _scheduler.scheduleAtFixedRate(new WatchdogTimeout(), 5000, 5000, TimeUnit.MILLISECONDS);
    Log.info("Started {}", this);
  }
 
  @Override
  protected void doStop() throws Exception
 
    MultiException mex = new MultiException();
   
    synchronized (this)
    {
      if (_peers != null)
      {
        for (Peer peer : _peers)
        {
          try
          {
            peer.stop();
          }
          catch (Exception e)
          {
            Log.warn("failed to stop peer: " + peer, e);
          }
        }
       
        // Wait at most 1 seconds for DPA reception
        try
        {
          boolean allClosed = false;
          int iter = 20;
          while (iter-- > 0 && allClosed)
          {
            allClosed = true;
            for (Peer peer : _peers)
            {
              if (!peer.isClosed())
              {
                allClosed = false;
                Log.info("Wait 50ms for " + peer + " closing");
                Thread.sleep(50);
                break;
              }
            }
          }
        }
        catch (Exception e)
        {
          Log.ignore(e);
        }
      }
    } 
   
    if (_scheduler != null)
      _scheduler.shutdown();
   
    for (int i = 0; _connectors != null && i < _connectors.length; i++)
    {
      if (_connectors[i] instanceof LifeCycle)  
      {
        try
        {
          ((LifeCycle) _connectors[i]).stop();
        }
        catch (Exception e)
        {
          mex.add(e);
        }
      }
    }
       
    if (_router != null && _router instanceof LifeCycle)
      ((LifeCycle) _router).stop();
   
    mex.ifExceptionThrow();
  }
 
  public void setIdentity(String identity)
  {
    _identity = identity;
  }
 
  public String getIdentity()
  {
    return _identity;
  }
 
  public void setRealm(String realm)
  {
    _realm = realm;
  }
 
  public String getRealm()
  {
    return _realm;
  }
 
  public int getVendorId()
  {
    return _vendorId;
  }
 
  public String getProductName()
  {
    return _productName;
  }

  public void setProductName(String productName)
  {
    _productName = productName;
  }
 
  public SessionManager getSessionManager()
  {
    return _sessionManager;
  }
 
  public DiameterConnection getConnection(Peer peer) throws IOException
  {
    return _connectors[0].getConnection(peer);
  }
 
  public Peer getPeer(String host)
  {
    synchronized (this)
    {
      if (_peers != null)
      {
        for (Peer peer : _peers)
        {
          if (peer.getHost().equals(host))
            return peer;
        }
      }
    }
    return null;
  }
 
  public DiameterRouter getDiameterRouter()
  {
    return _router;
  }

  public void setDiameterRouter(DiameterRouter router)
  {
    _router = router;
  }
 
  public void send(DiameterRequest request) throws IOException
  {
    Peer peer = _router.getRoute(request);
   
    if (peer == null && request.getDestinationHost() != null)
    {
      peer = new Peer(request.getDestinationHost());
      peer.start();
      addPeer(peer);
    }
     
    if (peer != null)
      peer.send(request);
    else
      throw new IOException("Router found no peer and no destination host set");
  }
 
  public void receive(DiameterMessage message) throws IOException
  {
    Peer peer = message.getConnection().getPeer();
   
    if (peer == null)
    {
      if (message.getCommand() != Common.CER)
      {
        Log.debug("non CER as first message: " + message.getCommand());
        message.getConnection().stop();
        return;
      }
      if (message.getCommand() == Common.CER)
      {
        String originHost = message.getOriginHost();
       
        if (originHost == null)
        {
          Log.debug("No Origin-Host in CER");
          message.getConnection().stop();
          return;
        }
        String realm = message.getOriginRealm();
        if (realm == null)
        {
          Log.debug("No Origin-Realm in CER");
          message.getConnection().stop();
          return;
        }
       
        peer = getPeer(originHost);
       
        if (peer == null)
        {
          Log.warn("Unknown peer " + originHost);
          peer = new Peer(originHost);
          peer.setNode(this);
          addPeer(peer);
        }
        message.getConnection().setPeer(peer);
        peer.rConnCER((DiameterRequest) message);
      }
    }
    else
    {
      peer.receive(message);
    }
  }
 
  public DiameterHandler getHandler()
  {
    return _handler;
  }
 
  public void setHandler(DiameterHandler handler)
  {
    _handler = handler;
  }
 
  public void handle(DiameterMessage message) throws IOException
  {
   
    // System.out.println("Node.handle(): Got message: " + message);
    String sessionId = message.getSessionId();   
    if (sessionId != null)     
      message.setSession(_sessionManager.get(sessionId));
       
    if (message instanceof DiameterAnswer)
    {
      DiameterAnswer answer = (DiameterAnswer) message;
      if (Common.DIAMETER_REDIRECT_INDICATION.equals(answer.getResultCode()))
      {
        try
                {
                    String redirectHost = answer.get(Common.REDIRECT_HOST);
                    Peer peer = getPeer(redirectHost);
                    if (peer != null)
                    {
                        Log.debug("Redirecting request to: " + peer);
                        peer.send(answer.getRequest());
                    }
                    else
                      Log.warn("Unknown peer {} indicating in redirect-host AVP", redirectHost);
                    return;
                }
                catch (Exception e)
                {
                    Log.warn("Failed to redirect request", e);
                    return;
                }
      }
    }
   
    SessionScope scope = null;
    try
    {
      scope = _sessionManager.openScope(message.getApplicationSession());
      if (_handler != null)
        _handler.handle(message);
    }
    finally
    {
      if (scope != null)
        scope.close();
    }
  }
 
  public void addSupportedApplication(ApplicationId id)
  {
    _supportedApplications.add(id);
  }
 
  public void addCapabilities(DiameterMessage message)
  { 
    for (DiameterConnector connector : _connectors)
    {
      message.add(Common.HOST_IP_ADDRESS, connector.getLocalAddress());
    }
   
    message.add(Common.VENDOR_ID, getVendorId());
    message.add(Common.PRODUCT_NAME, getProductName());
       
    for (ApplicationId id : _supportedApplications)
    {
      if (id.isVendorSpecific())
      {
        for (Integer i : id.getVendors())
        {
          message.add(Common.SUPPORTED_VENDOR_ID, i);
        }
      }
    }
   
    for (ApplicationId id : _supportedApplications)
    {
      message.getAVPs().add(id.getAVP());
    }
   
    message.add(Common.FIRMWARE_REVISION, 1);
  }
 
  public String toString()
  {
    return _identity + "(" + _supportedApplications + ")";
  }
 
  public long getTw()
  {
    return _tw;
  }

  public void setTw(long tw)
  {
    if (tw < 6000)
      throw new IllegalArgumentException("Tw MUST NOT be set lower than 6 seconds");
    _tw = tw;
  }

  public long getTc()
  {
    return _tc;
  }

  public void setTc(long tc)
  {
    _tc = tc;
  }
 
  public ScheduledFuture<?> schedule(Runnable runnable, long ms)
  {
    if (isRunning())
      return _scheduler.schedule(runnable, ms, TimeUnit.MILLISECONDS);
    return null;
  }
 
  public void scheduleReconnect(Peer peer)
  {
    schedule(new ConnectPeerTimeout(peer), _tc);
  }
 
  public void allStatsReset()
  {
    getSessionManager().statsReset();
    for (int i = 0; _connectors != null && i < _connectors.length; i++)
      if (_connectors[i] instanceof AbstractDiameterConnector)
        ((AbstractDiameterConnector) _connectors[i]).statsReset();
   
    synchronized (this)
    {
      for (int i = 0; _peers != null && i < _peers.length; i++)
        _peers[i].statsReset();
    }
  }
   
  public void statsReset()
    {
        updateNotEqual(_statsStartedAt,-1,System.currentTimeMillis());

        if (getSessionManager() != null)
          getSessionManager().statsReset();
       
    for (int i = 0; _connectors != null && i < _connectors.length; i++)
      if (_connectors[i] instanceof AbstractDiameterConnector)
        ((AbstractDiameterConnector) _connectors[i]).statsReset();
   
    synchronized (this)
    {
      for (int i = 0; _peers != null && i < _peers.length; i++)
        _peers[i].statsReset();
    }
    }
 
  private void updateNotEqual(AtomicLong valueHolder, long compare, long value)
    {
        long oldValue = valueHolder.get();
        while (compare != oldValue)
        {
            if (valueHolder.compareAndSet(oldValue,value))
                break;
            oldValue = valueHolder.get();
        }
    }
 
  public void setStatsOn(boolean on)
    {
        if (on && _statsStartedAt.get() != -1)
            return;

        Log.debug("Statistics on = " + on + " for " + this);

        statsReset();
        _statsStartedAt.set(on?System.currentTimeMillis():-1);
    }
 
  public boolean isStatsOn()
    {
        return _statsStartedAt.get() != -1;
    }
 
  public long getStatsStartedAt()
  {
    return _statsStartedAt.get();
  }
 
  public long getRequestTimeout()
  {
    return _requestTimeout;
  }

  public void setRequestTimeout(long requestTimeout)
  {
    _requestTimeout = requestTimeout;
  }
 
  public String dump()
  {
    return AggregateLifeCycle.dump(this);
  }

  public void dump(Appendable out, String indent) throws IOException
  {
    out.append("Node ").append(_identity).append(' ').append(getState()).append('\n');
    List<Object> l = new ArrayList<Object>();
    l.add("Realm=" + _realm);
    l.add("ProductName=" + _productName);
    l.add(_router);
    l.add(_sessionManager);
   
    AggregateLifeCycle.dump(out,indent,l, Arrays.asList(_peers), Arrays.asList(_connectors), _supportedApplications);
  }
 
  class ConnectPeerTimeout implements Runnable
  {
    private Peer _peer;
   
    public ConnectPeerTimeout(Peer peer)
    {
      _peer = peer;
    }
   
    public void run()
    {
      try
      {
        if (isStarted())
        {
          if (!_peer.isStopped() && !_peer.isOpen())
          {
            Log.debug("restarting peer: " + _peer);
            _peer.start();
          }
        }
      }
      catch (Exception e)
      {
        Log.warn("failed to reconnect to peer {} : {}", _peer, e);
      }
    }
  }
 
  class WatchdogTimeout implements Runnable
  {
    public void run()
    {
      if (_peers != null)
      {
        for (Peer peer: _peers)
          peer.watchdog();
      }
    }
  }
}
TOP

Related Classes of org.cipango.diameter.node.Node$WatchdogTimeout

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.