StateMachine.java

Go to the documentation of this file.
00001 /*
00002  * $Id: StateMachine.java 27 2006-11-27 09:43:28Z shenny $
00003  *
00004  * Copyright (C) 2004-2006 FhG Fokus
00005  *
00006  * This file is part of Open IMS Core - an open source IMS CSCFs & HSS
00007  * implementation
00008  *
00009  * Open IMS Core is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * For a license to use the Open IMS Core software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact Fraunhofer FOKUS by e-mail at the following
00017  * addresses:
00018  *     info@open-ims.org
00019  *
00020  * Open IMS Core is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  *
00025  * You should have received a copy of the GNU General Public License
00026  * along with this program; if not, write to the Free Software
00027  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00028  *
00029  */
00030 
00031 package de.fhg.fokus.diameter.DiameterPeer.peer;
00032 
00033 import java.io.IOException;
00034 import java.net.Socket;
00035 import java.net.UnknownHostException;
00036 import java.util.Iterator;
00037 import java.util.concurrent.TimeUnit;
00038 
00039 import org.apache.log4j.Logger;
00040 
00041 import de.fhg.fokus.diameter.DiameterPeer.data.AVP;
00042 import de.fhg.fokus.diameter.DiameterPeer.data.AVPDecodeException;
00043 import de.fhg.fokus.diameter.DiameterPeer.data.DiameterCEA;
00044 import de.fhg.fokus.diameter.DiameterPeer.data.DiameterCER;
00045 import de.fhg.fokus.diameter.DiameterPeer.data.DiameterDPA;
00046 import de.fhg.fokus.diameter.DiameterPeer.data.DiameterDPR;
00047 import de.fhg.fokus.diameter.DiameterPeer.data.DiameterDWA;
00048 import de.fhg.fokus.diameter.DiameterPeer.data.DiameterDWR;
00049 import de.fhg.fokus.diameter.DiameterPeer.data.DiameterMessage;
00050 import de.fhg.fokus.diameter.DiameterPeer.data.DiameterTask;
00051 import de.fhg.fokus.diameter.DiameterPeer.transport.Communicator;
00052 
00059 public class StateMachine {
00060     
00062     private static final Logger LOGGER = Logger.getLogger(StateMachine.class);
00063 
00064     /* State definitions */
00066     public static final int Closed              = 0; 
00067     
00069     public static final int Wait_Conn_Ack       = 1;
00070     
00072     public static final int Wait_I_CEA          = 2;
00073     
00075     public static final int Wait_Conn_Ack_Elect = 3;
00076     
00078     public static final int Wait_Returns        = 4;
00079     
00081     public static final int R_Open              = 5;
00082     
00084     public static final int I_Open              = 6;
00085     
00087     public static final int Closing             = 7;
00088     
00089     
00090     
00091     
00092     /* Event definitions */
00094     public static final int Start           = 101;
00095 
00097     public static final int Stop            = 102;
00098     
00100     public static final int Timeout         = 103;
00101     
00103     public static final int Win_Election    = 104;
00104     
00106     public static final int R_Conn_CER      = 105;
00107     
00109     public static final int I_Rcv_Conn_Ack  = 106;
00110     
00112     public static final int I_Rcv_Conn_NAck = 107;
00113     
00115     public static final int I_Rcv_CER       = 108;
00116 
00118     public static final int I_Rcv_CEA       = 109;
00119     
00121     public static final int R_Rcv_CER       = 110;
00122     
00124     public static final int R_Rcv_CEA       = 111;
00125     
00127     public static final int I_Rcv_Non_CEA   = 112;
00128     
00130     public static final int I_Rcv_DPR       = 113;
00131     
00133     public static final int I_Rcv_DPA       = 114;
00134     
00136     public static final int R_Rcv_DPR       = 115;
00137     
00139     public static final int R_Rcv_DPA       = 116;
00140     
00142     public static final int I_Rcv_DWR       = 117;
00143     
00145     public static final int I_Rcv_DWA       = 118;
00146     
00148     public static final int R_Rcv_DWR       = 119;
00149     
00151     public static final int R_Rcv_DWA       = 120;
00152     
00154     public static final int Send_Message    = 121;
00155     
00157     public static final int I_Rcv_Message   = 122;
00158     
00160     public static final int R_Rcv_Message   = 123;
00161     
00163     public static final int I_Peer_Disc     = 124;
00164     
00166     public static final int R_Peer_Disc     = 125;
00167     
00175     public static int process(Peer p, int event)
00176     {
00177         return process(p,event,null,null);
00178     }
00179     
00180     
00181     
00190     public static int process(Peer p, int event, DiameterMessage msg)
00191     {
00192         return process(p,event,msg,null);
00193     }
00194     
00195     
00205     public static int process(Peer p, int event, DiameterMessage msg,Communicator comm)
00206     {
00207         int next_event,result_code;
00208         boolean msg_received=false;
00209         //LOGGER.debug("Peer Old State: "+p.state+" FQDN:"+p.FQDN);
00210 
00211     synchronized(p){
00212         switch (p.state){
00213             case Closed:
00214                 switch (event){
00215                     case Start:
00216                         p.state = Wait_Conn_Ack;
00217                         next_event = I_Snd_Conn_Req(p);
00218                         StateMachine.process(p,next_event,null,p.I_comm);
00219                         break;
00220                     case R_Conn_CER:
00221                         R_Accept(p,comm);
00222                         result_code = Process_CER(p,msg);
00223                         Snd_CEA(p,msg,result_code,p.R_comm);
00224                         if (result_code>=2000 && result_code<3000)
00225                             p.state = R_Open;
00226                         else {
00227                             R_Disc(p);
00228                             p.state = Closed;
00229                         }
00230                         break;
00231                     case Stop:
00232                         /* just ignore this state */
00233                         p.state = Closed;
00234                         break;
00235                     default:
00236                         LOGGER.error("StateMachine: Invalid event "+event+" for state "+p.state);
00237                         return 0;
00238                 }
00239                 break;
00240             case Wait_Conn_Ack:
00241                 switch(event){
00242                     case I_Rcv_Conn_Ack:
00243                         I_Snd_CER(p);
00244                         p.state = Wait_I_CEA;
00245                         break;  
00246                     case I_Rcv_Conn_NAck:
00247                         Cleanup(p,comm);
00248                         p.state = Closed;
00249                         break;
00250 /* Commented as not reachable*/                     
00251 //                  case R_Conn_CER:
00252 //                      R_Accept(p,comm);
00253 //                      result_code = Process_CER(p,msg);
00254 //                      if (result_code>=2000 && result_code<3000)
00255 //                          p.state = Wait_Conn_Ack_Elect;
00256 //                      else {
00257 //                          p.state = Wait_Conn_Ack;
00258 //                          comm.shutdown();
00259 //                      }
00260 //                      break;
00261                     case Timeout:
00262                         Error(p,p.I_comm);
00263                         p.state = Closed;
00264                     default:
00265                         LOGGER.error("StateMachine: Invalid event "+event+" for state "+p.state);
00266                         return 0;
00267                 }
00268                 break;
00269             case Wait_I_CEA:
00270                 switch(event){
00271                     case I_Rcv_CEA:
00272                         result_code = Process_CEA(p,msg);
00273                         //if (result_code>=2000 && result_code<3000)
00274                             p.state = I_Open; 
00275                         //else {
00276                         //  Cleanup(p,p.I_comm);
00277                         //  p.state = Closed;
00278                         //}
00279                         break;
00280                     case R_Conn_CER:
00281                         R_Accept(p,comm);
00282                         result_code = Process_CER(p,msg);
00283                         p.state = Wait_Returns;
00284                         if (Elect(p,msg))
00285                             StateMachine.process(p,Win_Election,msg,comm);
00286                         break;
00287                     case I_Peer_Disc:
00288                         I_Disc(p);
00289                         p.state = Closed;
00290                         break;
00291                     case I_Rcv_Non_CEA:
00292                         Error(p,p.I_comm);
00293                         p.state = Closed;
00294                         break;
00295                     case Timeout:
00296                         Error(p,p.I_comm);
00297                         p.state = Closed;
00298                         break;
00299                     default:
00300                         LOGGER.error("StateMachine: Invalid event "+event+" for state "+p.state);
00301                         return 0;
00302                 }
00303                 break;
00304 /* commented as not reachable */
00305 //          case Wait_Conn_Ack_Elect:
00306 //              switch(event){
00307 //                  default:
00308 //                      LOGGER.error("StateMachine: Invalid event "+event+" for state "+p.state);
00309 //                      return 0;
00310 //              }
00311 //              break;
00312             case Wait_Returns:
00313                 switch(event){
00314                     case Win_Election:
00315                         I_Disc(p);
00316                         result_code = Process_CER(p,msg);
00317                         Snd_CEA(p,msg,result_code,p.R_comm);
00318                         if (result_code>=2000 && result_code<3000){
00319                             p.state = R_Open;
00320                         }else{
00321                             R_Disc(p);
00322                             p.state = Closed;
00323                         }
00324                         break;
00325                     case I_Peer_Disc:
00326                         I_Disc(p);
00327                         result_code = Process_CER(p,msg);
00328                         Snd_CEA(p,msg,result_code,p.R_comm);
00329                         if (result_code>=2000 && result_code<3000){
00330                             p.state = R_Open;
00331                         }else{
00332                             R_Disc(p);
00333                             p.state = Closed;
00334                         }
00335                         break;
00336                     case I_Rcv_CEA:
00337                         R_Disc(p);
00338                         //result_code = Process_CEA(p,msg);
00339                         //if (result_code>=2000 && result_code<3000)
00340                             p.state = I_Open; 
00341                         //else {
00342                         //  Cleanup(p,p.I_comm);
00343                         //  p.state = Closed;
00344                         //}
00345                         break;
00346                     case R_Peer_Disc:
00347                         R_Disc(p);
00348                         p.state = Wait_I_CEA;
00349                         break;
00350                     case R_Conn_CER:
00351                         R_Reject(p,comm);
00352                         p.state = Wait_Returns;
00353                         break;
00354                     case Timeout:
00355                         Error(p,comm);
00356                         p.state = Closed;
00357                     default:
00358                         LOGGER.error("StateMachine: Invalid event "+event+" for state "+p.state);
00359                         return 0;
00360                 }
00361                 break;
00362             case R_Open:
00363                 switch (event){
00364                     case Send_Message:
00365                         Snd_Message(p,msg);
00366                         p.state = R_Open;
00367                         break;
00368                     case R_Rcv_Message:
00369                         // delayed processing until out of the critical zone
00370                         //Rcv_Process(p,msg);
00371                         msg_received = true;
00372                         p.state = R_Open;
00373                         break;
00374                     case R_Rcv_DWR:
00375                         result_code = Process_DWR(p,msg);
00376                         Snd_DWA(p,msg,result_code,p.R_comm);
00377                         p.state = R_Open;
00378                         break;
00379                     case R_Rcv_DWA:
00380                         Process_DWA(p,msg);
00381                         p.state = R_Open;
00382                         break;
00383                     case R_Conn_CER:
00384                         R_Reject(p,comm);
00385                         p.state = R_Open;
00386                         break;
00387                     case Stop:
00388                         Snd_DPR(p);
00389                         p.state = Closing;
00390                         break;
00391                     case R_Rcv_DPR:
00392                         Snd_DPA(p,msg,DiameterMessage.DIAMETER_SUCCESS,p.R_comm);
00393                         R_Disc(p);
00394                         p.state = Closed;
00395                         break;
00396                     case R_Peer_Disc:
00397                         R_Disc(p);
00398                         p.state = Closed;
00399                         break;
00400                     case R_Rcv_CER:
00401                         result_code = Process_CER(p,msg);
00402                         Snd_CEA(p,msg,result_code,p.R_comm);
00403                         if (result_code>=2000 && result_code<3000)
00404                             p.state = R_Open;
00405                         else {
00406                             /*R_Disc(p);p.state = Closed;*/
00407                             p.state = R_Open; /* Or maybe I should disconnect it?*/
00408                         }
00409                         break;
00410                     case R_Rcv_CEA:
00411                         result_code = Process_CEA(p,msg);
00412                         if (result_code>=2000 && result_code<3000)
00413                             p.state = R_Open;
00414                         else {
00415                             /*R_Disc(p);p.state = Closed;*/
00416                             p.state = R_Open; /* Or maybe I should disconnect it?*/
00417                         }
00418                         break;
00419                     default:
00420                         LOGGER.error("StateMachine: Invalid event "+event+" for state "+p.state);
00421                         return 0;
00422                 }
00423                 break;
00424             case I_Open:
00425                 switch (event){
00426                     case Send_Message:
00427                         Snd_Message(p,msg);
00428                         p.state = I_Open;
00429                         break;
00430                     case I_Rcv_Message:
00431                         // delayed processing until out of the critical zone
00432                         //Rcv_Process(p,msg);
00433                         msg_received = true;
00434                         p.state = I_Open;
00435                         break;
00436                     case I_Rcv_DWR:
00437                         result_code = Process_DWR(p,msg);
00438                         Snd_DWA(p,msg,result_code,p.I_comm);                        
00439                         p.state =I_Open;
00440                         break;
00441                     case I_Rcv_DWA:
00442                         Process_DWA(p,msg);
00443                         p.state =I_Open;
00444                         break;
00445                     case R_Conn_CER:
00446                         R_Reject(p,comm);
00447                         p.state = I_Open;
00448                         break;
00449                     case Stop:
00450                         Snd_DPR(p);
00451                         p.state = Closing;
00452                         break;
00453                     case I_Rcv_DPR:
00454                         Snd_DPA(p,msg,2001,p.I_comm);
00455                         R_Disc(p);
00456                         p.state = Closed;
00457                         break;
00458                     case I_Peer_Disc:
00459                         I_Disc(p);
00460                         p.state = Closed;
00461                         break;
00462                     case I_Rcv_CER:
00463                         result_code = Process_CER(p,msg);
00464                         Snd_CEA(p,msg,result_code,p.I_comm);
00465                         if (result_code>=2000 && result_code<3000)
00466                             p.state = I_Open;
00467                         else {
00468                             /*I_Disc(p);p.state = Closed;*/
00469                             p.state = I_Open; /* Or maybe I should disconnect it?*/
00470                         }
00471                         break;
00472                     case I_Rcv_CEA:
00473                         result_code = Process_CEA(p,msg);
00474                         if (result_code>=2000 && result_code<3000)
00475                             p.state = I_Open;
00476                         else {
00477                             /*I_Disc(p);p.state = Closed;*/
00478                             p.state = I_Open; /* Or maybe I should disconnect it?*/
00479                         }
00480                         break;
00481                     default:
00482                         LOGGER.error("StateMachine: Invalid event "+event+" for state "+p.state);
00483                         return 0;
00484                 }
00485                 break;              
00486             case Closing:
00487                 switch(event){
00488                     case I_Rcv_DPA:
00489                         I_Disc(p);
00490                         p.state = Closed;
00491                         break;
00492                     case R_Rcv_DPA:
00493                         R_Disc(p);
00494                         p.state = Closed;
00495                         break;
00496                     case Timeout:
00497                         if (p.I_comm!=null) Error(p,p.I_comm);
00498                         if (p.R_comm!=null) Error(p,p.R_comm);
00499                         p.state = Closed;
00500                         break;
00501                     case I_Peer_Disc:
00502                         I_Disc(p);
00503                         p.state = Closed;
00504                         break;
00505                     case R_Peer_Disc:
00506                         R_Disc(p);
00507                         p.state = Closed;
00508                         break;
00509                     default:
00510                         LOGGER.error("StateMachine: Invalid event "+event+" for state "+p.state);
00511                         return 0;
00512                 }
00513                 break;
00514             default:
00515                 LOGGER.error("StateMachine: Invalid state "+p.state);
00516                 return 0;
00517                 
00518         }
00519         //LOGGER.debug("Peer New State: "+p.state+" FQDN:"+p.FQDN);
00520     }
00521         if (msg_received){
00522             // delayed processing until out of the critical zone
00523             Rcv_Process(p,msg);
00524         }
00525         
00526         return 1;
00527     }
00528     
00529     private static int I_Snd_Conn_Req(Peer p)
00530     {
00531         Socket s;
00532         if (p.I_comm!=null) p.I_comm.shutdown();
00533         p.I_comm = null;
00534         try {
00535             s = new Socket(p.FQDN,p.port);
00536         } catch (UnknownHostException e1) {
00537             LOGGER.error("StateMachine: Peer "+p.FQDN+" can not be resolved.");
00538             return StateMachine.I_Rcv_Conn_NAck;
00539         } catch (IOException e1) {
00540             LOGGER.error("StateMachine: Peer "+p.FQDN+" not responding to connection attempt ");
00541             return StateMachine.I_Rcv_Conn_NAck;
00542         }
00543         Communicator r = new Communicator(s,p,Communicator.Initiator);
00544         p.I_comm = r;
00545         return StateMachine.I_Rcv_Conn_Ack;
00546     }
00547 
00548     private static void R_Accept(Peer p,Communicator comm)
00549     {
00550         p.R_comm = comm;
00551         p.refreshTimer();
00552     }
00553 
00554     private static void R_Reject(Peer p,Communicator comm)
00555     {
00556         comm.shutdown();
00557     }
00558     
00559     private static void I_Snd_CER(Peer p)
00560     {
00561         DiameterCER cer = new DiameterCER();
00562         
00563         cer.hopByHopID = p.diameterPeer.getNextHopByHopId();
00564         cer.endToEndID = p.diameterPeer.getNextEndToEndId();
00565         cer.origin_host.setData(p.diameterPeer.FQDN);
00566         cer.origin_realm.setData(p.diameterPeer.Realm);
00567         byte addr[] ,laddr[] = p.I_comm.socket.getLocalAddress().getAddress();
00568         switch (laddr.length) {
00569             case 16:
00570                 addr = new byte[18];            
00571                 addr[0]=(byte)0;
00572                 addr[1]=(byte)2;
00573                 System.arraycopy(laddr,0,addr,2,laddr.length);
00574                 break;          
00575             default:
00576             case 4:
00577                 addr = new byte[6];         
00578                 addr[0]=(byte)0;
00579                 addr[1]=(byte)1;
00580                 System.arraycopy(laddr,0,addr,2,laddr.length);
00581                 break;          
00582         }
00583         cer.host_ip_address.setData(addr);
00584         cer.vendor_id.setData(p.diameterPeer.Vendor_Id);
00585         cer.product_name.setData(p.diameterPeer.Product_Name);
00586         
00587         Snd_CE_add_applications(cer,p);
00588         
00589         //LOGGER.debug(cer.toString());
00590         p.I_comm.sendDirect(cer);
00591     }
00592     
00593     
00594     private static void Cleanup(Peer p,Communicator comm)
00595     {
00596         if (comm==null) return;
00597         comm.shutdown();
00598         if (p.I_comm == comm) p.I_comm = null;
00599         if (p.R_comm == comm) p.R_comm = null;
00600     }
00601 
00602     private static void Error(Peer p, Communicator comm)
00603     {
00604         Cleanup(p,comm);
00605     }
00606 
00607     private static boolean Elect(Peer p,DiameterMessage cer)
00608     {
00609         /* returns if we win the election */
00610         AVP avp;
00611         byte[] remote,local;
00612         int x,i;
00613         local = p.diameterPeer.FQDN.getBytes();
00614         avp = cer.findAVP(AVP.Origin_Host,true,0);
00615         if (avp==null) {
00616             return true;
00617         }else{
00618             remote = avp.data;
00619             for(i=0;i<remote.length&&i<local.length;i++){
00620                 x = ((int) local[i]&0xFF)-((int) remote[i]&0xFF);
00621                 if (x>0) return true;
00622                 if (x<0) return false;
00623             }
00624             if (local.length>remote.length) return true;
00625             return false;
00626         }
00627     }
00628 
00629     private static int Process_CER(Peer p,DiameterMessage cer)
00630     {
00631         int common_app=0;
00632         Iterator<AVP> i = cer.avps.iterator();
00633         Iterator<Application> i2;
00634         Application app;
00635         AVP avp,avp_vendor,avp2;
00636         p.AuthApp.clear();
00637         p.AcctApp.clear();
00638         while(i.hasNext()&& common_app==0){
00639             avp = (AVP) i.next();
00640             switch (avp.code){
00641                 case AVP.Auth_Application_Id:
00642                     p.AuthApp.add(new Application(avp.int_data,0,Application.Auth));
00643                     i2 = p.diameterPeer.AuthApp.iterator();
00644                     while(i2.hasNext()){
00645                         app = i2.next();
00646                         if (avp.int_data==Application.Relay ||
00647                             (app.id==avp.int_data && app.vendor==0)){
00648                             common_app++;
00649                             break;
00650                         }
00651                     }
00652                     break;
00653                 case AVP.Acct_Application_Id:
00654                     p.AcctApp.add(new Application(avp.int_data,0,Application.Acct));
00655                     i2 = p.diameterPeer.AcctApp.iterator();
00656                     while(i2.hasNext()){
00657                         app = i2.next();
00658                         if (avp.int_data==Application.Relay ||
00659                             (app.id==avp.int_data && app.vendor==0)){
00660                             common_app++;
00661                             break;
00662                         }
00663                     }
00664                     break;
00665                 case AVP.Vendor_Specific_Application_Id:
00666                     try {
00667                         avp.ungroup();
00668                     } catch (AVPDecodeException e) {
00669                         e.printStackTrace();
00670                     }
00671                     avp_vendor = avp.findChildAVP(AVP.Vendor_Id,true,0);
00672                     if (avp_vendor==null) break;
00673                     avp2 = avp.findChildAVP(AVP.Auth_Application_Id,true,0);
00674                     if (avp2!=null) {
00675                         p.AuthApp.add(new Application(avp2.int_data,avp_vendor.int_data,Application.Auth));
00676                         i2 = p.diameterPeer.AuthApp.iterator();
00677                         while(i2.hasNext()){
00678                             app = i2.next();
00679                             if (avp2.int_data==Application.Relay ||
00680                                 (app.id==avp2.int_data && app.vendor==avp_vendor.int_data)){
00681                                 common_app++;
00682                                 break;
00683                             }
00684                         }
00685                     }
00686                     avp2 = avp.findChildAVP(AVP.Acct_Application_Id,true,0);
00687                     if (avp2!=null) {
00688                         p.AcctApp.add(new Application(avp2.int_data,avp_vendor.int_data,Application.Acct));
00689                         i2 = p.diameterPeer.AcctApp.iterator();
00690                         while(i2.hasNext()){
00691                             app = (Application) i2.next();
00692                             if (avp2.int_data==Application.Relay ||
00693                                 (app.id==avp2.int_data && app.vendor==avp_vendor.int_data)){
00694                                 common_app++;
00695                                 break;
00696                             }
00697                         }
00698                     }
00699                     break;
00700                     
00701             }
00702         }
00703         
00704         if (common_app!=0)
00705             return