00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 package de.fhg.fokus.diameter.DiameterPeer;
00032
00033
00034 import java.io.IOException;
00035 import java.io.StringReader;
00036 import java.net.InetAddress;
00037 import java.net.UnknownHostException;
00038 import java.util.Iterator;
00039 import java.util.Vector;
00040 import java.util.concurrent.ArrayBlockingQueue;
00041
00042
00043 import javax.xml.parsers.DocumentBuilder;
00044 import javax.xml.parsers.DocumentBuilderFactory;
00045 import javax.xml.parsers.ParserConfigurationException;
00046
00047 import org.apache.log4j.Logger;
00048 import org.w3c.dom.Document;
00049 import org.w3c.dom.Node;
00050 import org.w3c.dom.NodeList;
00051 import org.xml.sax.InputSource;
00052 import org.xml.sax.SAXException;
00053
00054 import de.fhg.fokus.diameter.DiameterPeer.data.AVP;
00055 import de.fhg.fokus.diameter.DiameterPeer.data.DiameterMessage;
00056 import de.fhg.fokus.diameter.DiameterPeer.data.DiameterTask;
00057 import de.fhg.fokus.diameter.DiameterPeer.peer.Application;
00058 import de.fhg.fokus.diameter.DiameterPeer.peer.Peer;
00059 import de.fhg.fokus.diameter.DiameterPeer.peer.PeerManager;
00060 import de.fhg.fokus.diameter.DiameterPeer.peer.StateMachine;
00061 import de.fhg.fokus.diameter.DiameterPeer.routing.RoutingEngine;
00062 import de.fhg.fokus.diameter.DiameterPeer.transaction.TransactionListener;
00063 import de.fhg.fokus.diameter.DiameterPeer.transaction.TransactionWorker;
00064 import de.fhg.fokus.diameter.DiameterPeer.transport.Acceptor;
00090 public class DiameterPeer {
00091
00093 private static final Logger LOGGER = Logger.getLogger(DiameterPeer.class);
00094
00096 public String FQDN;
00097
00099 public String Realm;
00100
00102 public int Vendor_Id;
00103
00105 public String Product_Name;
00106
00108 public int Tc;
00109
00111 public Vector<Acceptor> acceptors;
00112
00114 public boolean AcceptUnknownPeers;
00115
00117 public boolean DropUnknownOnDisconnect;
00118
00120 public Vector<Application> AuthApp,AcctApp;
00121
00123 public RoutingEngine routingTable=null;
00124
00126 public PeerManager peerManager;
00127
00132 public Vector<EventListener> eventListeners;
00133
00135 public int queueLength;
00136
00138 public ArrayBlockingQueue<DiameterTask> queueTasks;
00139
00141 private DiameterWorker workers[];
00142
00144 public int workerCount=1;
00145
00147 private TransactionWorker transactionWorker=null;
00148
00150 Document config;
00151
00153 public int hopbyhop_id=0;
00154
00156 public int endtoend_id=0;
00157
00159 public synchronized int getNextHopByHopId()
00160 {
00161 return ++hopbyhop_id;
00162 }
00164 public synchronized int getNextEndToEndId()
00165 {
00166 return ++endtoend_id;
00167 }
00168
00172 public DiameterPeer()
00173 {
00174 LOGGER.info("Bean style constructor called, don't forget to configure!");
00175 }
00176
00182 public DiameterPeer(String xml)
00183 {
00184 configure(xml,false);
00185 }
00186
00194 public void configure(String xml, boolean isFile)
00195 {
00196 Acceptor acc;
00197 NodeList nl;
00198 Node n,nv;
00199 int port,app_id,vendor_id;
00200 InetAddress addr;
00201 String fqdn,realm;
00202 Application app;
00203
00204 eventListeners = new Vector<EventListener>();
00205
00206 java.util.Random rand = new java.util.Random();
00207 hopbyhop_id = rand.nextInt();
00208 endtoend_id = ((int) (System.currentTimeMillis()&0xFFF))<<20;
00209 endtoend_id |= rand.nextInt() & 0xFFFFF;
00210
00211 if (isFile){
00212
00213 if (!readConfigFile(xml)) {
00214 LOGGER.error("DiameterPeer: Error parsing config file");
00215 return;
00216 }
00217 }
00218 else {
00219
00220 if (!readConfigString(xml)) {
00221 LOGGER.error("DiameterPeer: Error parsing config String");
00222 return;
00223 }
00224 }
00225
00226 FQDN = config.getDocumentElement().getAttribute("FQDN");
00227 LOGGER.info("FQDN: " + config.getDocumentElement().getAttribute("FQDN"));
00228 Realm = config.getDocumentElement().getAttribute("Realm");
00229 LOGGER.info("Realm: " + config.getDocumentElement().getAttribute("Realm"));
00230 Vendor_Id = Integer.parseInt(config.getDocumentElement().getAttribute("Vendor_Id"));
00231 LOGGER.info("Vendor_ID : " + Integer.parseInt(config.getDocumentElement().getAttribute("Vendor_Id")));
00232 Product_Name = config.getDocumentElement().getAttribute("Product_Name");
00233 LOGGER.info("Product Name: " + config.getDocumentElement().getAttribute("Product_Name"));
00234 AcceptUnknownPeers = Integer.parseInt(config.getDocumentElement().getAttribute("AcceptUnknownPeers"))!=0;
00235 LOGGER.info("AcceptUnknwonPeers: " + AcceptUnknownPeers);
00236 DropUnknownOnDisconnect = Integer.parseInt(config.getDocumentElement().getAttribute("DropUnknownOnDisconnect"))!=0;
00237 LOGGER.info("DropUnknownOnDisconnect: " + DropUnknownOnDisconnect);
00238
00239 Tc = Integer.parseInt(config.getDocumentElement().getAttribute("Tc"));
00240 workerCount = Integer.parseInt(config.getDocumentElement().getAttribute("Workers"));
00241 queueLength = Integer.parseInt(config.getDocumentElement().getAttribute("QueueLength"));
00242
00243 queueTasks = new ArrayBlockingQueue<DiameterTask>(queueLength,true);
00244
00245 startWorkers();
00246
00247
00248 this.AuthApp = new Vector<Application>();
00249 this.AcctApp = new Vector<Application>();
00250 nl = config.getDocumentElement().getElementsByTagName("Auth");
00251 for(int i=0;i<nl.getLength();i++){
00252 n = nl.item(i);
00253 app_id = 0;
00254 app_id = Integer.parseInt(n.getAttributes().getNamedItem("id").getNodeValue());
00255 vendor_id=0;
00256 if (n.getAttributes().getNamedItem("vendor")!=null)
00257 vendor_id = Integer.parseInt(n.getAttributes().getNamedItem("vendor").getNodeValue());
00258
00259 app = new Application(app_id,vendor_id,Application.Auth);
00260 this.AuthApp.add(app);
00261 }
00262 nl = config.getDocumentElement().getElementsByTagName("Acct");
00263 for(int i=0;i<nl.getLength();i++){
00264 n = nl.item(i);
00265 app_id = 0;
00266 app_id = Integer.parseInt(n.getAttributes().getNamedItem("id").getNodeValue());
00267 vendor_id=0;
00268 if (n.getAttributes().getNamedItem("vendor")!=null)
00269 vendor_id = Integer.parseInt(n.getAttributes().getNamedItem("vendor").getNodeValue());
00270
00271 app = new Application(app_id,vendor_id,Application.Acct);
00272 this.AcctApp.add(app);
00273 }
00274
00275 peerManager = new PeerManager(this);
00276
00277
00278 nl = config.getDocumentElement().getElementsByTagName("Peer");
00279 for(int i=0;i<nl.getLength();i++){
00280 n = nl.item(i);
00281
00282 fqdn = n.getAttributes().getNamedItem("FQDN").getNodeValue();
00283
00284 realm = n.getAttributes().getNamedItem("Realm").getNodeValue();
00285
00286 port = 3868;
00287 nv = n.getAttributes().getNamedItem("port");
00288 if (nv==null) port = 3868;
00289 else port = Integer.parseInt(nv.getNodeValue());
00290
00291 peerManager.configurePeer(fqdn,realm,port);
00292 }
00293
00294
00295 acceptors = new Vector<Acceptor>();
00296 nl = config.getDocumentElement().getElementsByTagName("Acceptor");
00297 for(int i=0;i<nl.getLength();i++){
00298 n = nl.item(i);
00299
00300 port = 3868;
00301 nv = n.getAttributes().getNamedItem("port");
00302 if (nv==null) port = 3868;
00303 else port = Integer.parseInt(nv.getNodeValue());
00304
00305 addr = null;
00306 nv = n.getAttributes().getNamedItem("bind");
00307 if (nv !=null && nv.getNodeValue().length()!=0 )
00308 try {
00309 addr = InetAddress.getByName(nv.getNodeValue());
00310 } catch (UnknownHostException e) {
00311 LOGGER.error("DiameterPeer: Can not resolve "+nv.getNodeValue());
00312 e.printStackTrace();
00313 continue;
00314 }
00315 acc = new Acceptor(port,addr,this);
00316 acc.startAccepting();
00317 acceptors.add(acc);
00318 }
00319
00320 initRoutingTable(config);
00321
00322 peerManager.start();
00323
00324 }
00325
00326 private boolean readConfigFile(String cfgFile)
00327 {
00328 DocumentBuilderFactory factory =
00329 DocumentBuilderFactory.newInstance();
00330
00331
00332 try {
00333 DocumentBuilder builder = factory.newDocumentBuilder();
00334 config = builder.parse( cfgFile );
00335 } catch (SAXException sxe) {
00336
00337 Exception x = sxe;
00338 if (sxe.getException() != null)
00339 x = sxe.getException();
00340 x.printStackTrace();
00341 return false;
00342 } catch (ParserConfigurationException pce) {
00343
00344 pce.printStackTrace();
00345 return false;
00346 } catch (IOException ioe) {
00347
00348 ioe.printStackTrace();
00349 return false;
00350 }
00351 return true;
00352 }
00353
00354 private boolean readConfigString(String cfgString)
00355 {
00356 DocumentBuilderFactory factory =
00357 DocumentBuilderFactory.newInstance();
00358
00359
00360 try {
00361 DocumentBuilder builder = factory.newDocumentBuilder();
00362 config = builder.parse( new InputSource(new StringReader(cfgString)) );
00363 } catch (SAXException sxe) {
00364
00365 Exception x = sxe;
00366 if (sxe.getException() != null)
00367 x = sxe.getException();
00368 x.printStackTrace();
00369 return false;
00370 } catch (ParserConfigurationException pce) {
00371
00372 pce.printStackTrace();
00373 return false;
00374 } catch (IOException ioe) {
00375
00376 ioe.printStackTrace();
00377 return false;
00378 }
00379 return true;
00380 }
00381
00382
00383 private void initRoutingTable(Document config) {
00384 NodeList nl, nlc;
00385 String fqdn,realm;
00386 int metric;
00387
00388 this.routingTable = new RoutingEngine();
00389 nl = config.getDocumentElement().getElementsByTagName("DefaultRoute");
00390 for(int i=0;i<nl.getLength();i++){
00391 fqdn = nl.item(i).getAttributes().getNamedItem("FQDN").getNodeValue();
00392 metric = Integer.valueOf(nl.item(i).getAttributes().getNamedItem("metric").getNodeValue());
00393 routingTable.addDefaultRoute(fqdn, metric);
00394 }
00395 nl = config.getDocumentElement().getElementsByTagName("Realm");
00396 for(int i=0;i<nl.getLength();i++){
00397 realm = nl.item(i).getAttributes().getNamedItem("name").getNodeValue();
00398 nlc = nl.item(i).getChildNodes();
00399 for(int j=0;j<nlc.getLength();j++)
00400 if (nlc.item(j).getNodeName().equalsIgnoreCase("Route")){
00401 fqdn = nlc.item(j).getAttributes().getNamedItem("FQDN").getNodeValue();
00402 metric = Integer.valueOf(nlc.item(j).getAttributes().getNamedItem("metric").getNodeValue());
00403 routingTable.addRealmRoute(realm, fqdn, metric);
00404 }
00405 }
00406
00407 }
00408
00409
00410 private void startWorkers()
00411 {
00412 workers = new DiameterWorker[workerCount];
00413 for(int i=0;i<workerCount;i++)
00414 workers[i] = new DiameterWorker(i,this.queueTasks);
00415 }
00416
00423 public void enableTransactions(long timeout,long checkInterval)
00424 {
00425 if (this.transactionWorker == null)
00426 this.transactionWorker = new TransactionWorker(this,timeout,checkInterval);
00427 }
00428
00429
00430
00438 public DiameterMessage newRequest(int command_code, int application_id)
00439 {
00440 return newRequest(command_code, true, application_id);
00441 }
00442
00443
00444
00453 public DiameterMessage newRequest(int command_code, boolean Proxiable,
00454 int application_id)
00455 {
00456 DiameterMessage msg = new DiameterMessage(command_code,
00457 true,
00458 Proxiable,
00459 application_id,
00460 this.getNextHopByHopId(),
00461 this.getNextEndToEndId());
00462 AVP avp;
00463
00464 avp = new AVP(AVP.Origin_Host,true,0);
00465 avp.setData(this.FQDN);
00466 msg.addAVP(avp);
00467
00468 avp = new AVP(AVP.Origin_Realm,true,0);
00469 avp.setData(this.Realm);
00470 msg.addAVP(avp);
00471
00472 return msg;
00473 }
00474
00475
00476
00483 public DiameterMessage newResponse(DiameterMessage request)
00484 {
00485 DiameterMessage msg = new DiameterMessage(request.commandCode,false,request.applicationID);
00486 AVP avp;
00487
00488 msg.endToEndID = request.endToEndID;
00489 msg.hopByHopID = request.hopByHopID;
00490
00491 if (request.getSessionId() != null) {
00492 avp = request.getSessionId();
00493 msg.addAVP(avp);
00494 }
00495
00496 avp = new AVP(AVP.Origin_Host,true,0);
00497 avp.setData(this.FQDN);
00498 msg.addAVP(avp);
00499
00500 avp = new AVP(AVP.Origin_Realm,true,0);
00501 avp.setData(this.Realm);
00502 msg.addAVP(avp);
00503
00504
00505 return msg;
00506 }
00507
00515 public boolean sendMessage(String peerFQDN,DiameterMessage msg)
00516 {
00517 Peer p;
00518 p = peerManager.getPeerByFQDN(peerFQDN);
00519 if (p==null){
00520 LOGGER.error("DiameterPeer: Peer "+peerFQDN+" not found in peer list.");
00521 return false;
00522 }
00523 if (p.state!=StateMachine.I_Open &&
00524 p.state!=StateMachine.R_Open){
00525 LOGGER.error("DiameterPeer: Peer "+peerFQDN+" not connected.");
00526 return false;
00527 }
00528 return p.sendMessage(msg);
00529 }
00530
00537 public boolean sendMessage(DiameterMessage msg)
00538 {
00539 Peer p;
00540 if (routingTable==null){
00541 LOGGER.error("DiameterPeer: RoutingTable not initialized!");
00542 return false;
00543 }
00544 p = routingTable.getRoute(msg,peerManager);
00545 if (p==null){
00546 LOGGER.error("DiameterPeer: No suitable peer to route to could be found.");
00547 return false;
00548 }
00549 return p.sendMessage(msg);
00550 }
00551
00560 public boolean sendRequestTransactional(String peerFQDN,DiameterMessage req,TransactionListener tl)
00561 {
00562 if (this.transactionWorker!=null) return transactionWorker.sendRequestTransactional(peerFQDN,req,tl);
00563 else {
00564 LOGGER.error("DiameterPeer:sendRequestTransactional(): Transactions are not enabled on this peer!");
00565 return false;
00566 }
00567 }
00568
00576 public boolean sendRequestTransactional(DiameterMessage req,TransactionListener tl)
00577 {
00578 if (this.transactionWorker!=null) return transactionWorker.sendRequestTransactional(req,tl);
00579 else {
00580 LOGGER.error("DiameterPeer:sendRequestTransactional(): Transactions are not enabled on this peer!");
00581 return false;
00582 }
00583 }
00584
00593 public DiameterMessage sendRequestBlocking(String peerFQDN,DiameterMessage req)
00594 {
00595 if (this.transactionWorker!=null) return transactionWorker.sendRequestBlocking(peerFQDN,req);
00596 else {
00597 LOGGER.error("DiameterPeer:sendRequestBlocking(): Transactions are not enabled on this peer!");
00598 return null;
00599 }
00600 }
00601
00609 public DiameterMessage sendRequestBlocking(DiameterMessage req)
00610 {
00611 if (this.transactionWorker!=null) return transactionWorker.sendRequestBlocking(req);
00612 else {
00613 LOGGER.error("DiameterPeer:sendRequestBlocking(): Transactions are not enabled on this peer!");
00614 return null;
00615 }
00616 }
00617
00618
00624 public void addEventListener(EventListener l)
00625 {
00626 eventListeners.add(l);
00627 }
00628
00629
00635 public void removeEventListener(EventListener l)
00636 {
00637 eventListeners.remove(l);
00638 }
00639
00643 public void shutdown()
00644 {
00645 Acceptor acc;
00646 Iterator<Acceptor> i = acceptors.iterator();
00647 while(i.hasNext()){
00648 acc = i.next();
00649 acc.stopAccepting();
00650 }
00651 peerManager.shutdown();
00652 for(int j=0;j<workerCount;j++)
00653 workers[j].shutdown();
00654 if (transactionWorker!=null) transactionWorker.shutdown();
00655 }
00656 }