Testing library separation: now not in launcher but isolated
[anna.git] / include / anna / diameter.comm / Engine.hpp
index 92a23e7..72e3ad9 100644 (file)
 
 // STL
 #include <map>
+#include <vector>
 #include <string>
 #include <algorithm>
 
 #include <anna/app/Component.hpp>
 #include <anna/core/util/Recycler.hpp>
 
+#include <anna/diameter/codec/Engine.hpp>
 #include <anna/diameter.comm/Server.hpp>
 #include <anna/diameter.comm/ServerSession.hpp>
 #include <anna/config/defines.hpp>
@@ -47,9 +49,13 @@ namespace codec {
 class Engine;
 }
 
-namespace comm {
+namespace stack {
+class Dictionary;
+}
 
+namespace comm {
 
+class Response;
 class Entity;
 class Server;
 class LocalServer;
@@ -95,58 +101,34 @@ class Engine : public anna::app::Component {
 public:
 
   /**
-   * Sets the base protocol codec engine used internally
-   *
-   * @param baseProtocolCodecEngine This will be used internally during invokation of @readCEA, @readDPA and @readDWA on servers,
-   * and also used during base protocol messages tracing (if debug traces are enabled). You could provide NULL but you must be
-   * sure that neither of the former situations are going to happen or an exception will be thrown. It is recommended to register
-   * a codec engine pointed to a base protocol stack (you can use the files 'avps_ietf.xml' and 'commands_baseProtocol.xml'
-   * located on ANNA suite project under 'source/diameter/stack/setups', or perhaps you can create your own dictionary from
-   * file or directly with the dictionay creation API. Even you can use a greater dictionary (application dictionary), the
-   * only condition is that must contain the resources to build base protocol messages. You could provide this in engine constructor,
-   * but don't forget it.
-  */
-  void setBaseProtocolCodecEngine(codec::Engine *baseProtocolCodecEngine) throw() { a_baseProtocolCodecEngine = baseProtocolCodecEngine; }
-
-  /**
-   * Gets the base protocol codec engine used internally
-   *
-   * @see setBaseProtocolCodecEngine
-   */
-  codec::Engine * getBaseProtocolCodecEngine() const throw() { return a_baseProtocolCodecEngine; }
-
-  /**
-     Diameter application node realm name (used to be the site domain name).
+     Diameter application node origin realm
 
-     @param name Diameter application node realm name. Used in order to configure the Origin-Realm for outgoing messages.
+     @param originRealmName Used to configure the Origin-Realm for outgoing messages.
      If not configured or empty string provided, host domainname will be set.
   */
-  void setRealm(const std::string & name) throw();
-
+  void setOriginRealmName(const std::string & originRealmName) throw();
 
   /**
-     Gets the configured diameter application node realm name.
+     Diameter application origin host
 
-     @return Diameter application node realm name.
+     @param originHostName Used to configure the Origin-Host for outgoing messages.
+     If not configured or empty string provided, hostname (system name) will be set.
   */
-  const std::string & getRealm() const throw() { return a_realm; }
-
+  void setOriginHostName(const std::string & originHostName) throw();
 
   /**
-     Diameter application host name as solved by #anna::functions::getHostname()
+     Gets the configured diameter application node origin realm
 
-     @param name Host name. Used in order to configure the Origin-Host for outgoing messages.
-     If not configured or empty string provided, hostname (system name) will be set.
+     @return Diameter application node origin realm
   */
-  void setHost(const std::string & name) throw();
-
+  const std::string & getOriginRealmName() const throw() { return a_originRealm; }
 
   /**
-     Gets the configured diameter application host name.
+     Gets the configured diameter application origin host
 
-     @return Diameter application host name.
+     @return Diameter application node origin host
   */
-  const std::string & getHost() const throw() { return a_host; }
+  const std::string & getOriginHostName() const throw() { return a_originHost; }
 
 
   /**
@@ -591,12 +573,20 @@ public:
   */
   virtual void readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw();
 
+  /**
+   * Sets optional CEA from file, when default is not enough
+   *
+   * @param &ceaPathfile Path file for the CEA xml message provided
+   */
+  void setCEA(const std::string &ceaPathfile) throw() { a_ceaPathfile = ceaPathfile; }
+
   /**
    * Class user should implement this method in order to define Capabilities-Exchange-Answer for received CER over server socket.
    * Origin-Host and Origin-Realm are configured at comm::Engine with hostname and FQDN (Fully Qualified Domain Name).
    * Default implementation imply CEA with DIAMETER_SUCCESS Result-Code, and own domain node parameters, but application should
    * analyze the CER message in order to accept it or not (with apropiate non-success Result-Code).
-   * Any other implementation is responsible to build a valid CEA diameter message:
+   * If @setCEA was invoked, a message from file is used instead of default implementation.
+   * Any other implementation is responsible to build a valid CEA diameter message, even ignoring a possible cea from file when @setCEA is used:
    *
    * If one peer sends a CER message to another Peer and receiver does not have support for
    *
@@ -632,6 +622,19 @@ public:
   */
   virtual void readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw();
 
+  /**
+   * DRA basics: CER information is gathered on every server session managed by the diameter comm engine. You could send the message to a
+   * specific realm, and optionally you could restrict a host inside it. This is common for requests (answers are normally sent through
+   * the same source server session where the request was received). Exception will be thrown if not found an available server session
+   * for the Destination-Realm and/or Destination-Host provided
+   *
+   * @param destinationRealm If empty, NULL is returned, because is nonsense to specify a host out of realm context
+   * @param destinationHost If empty, no restriction is applied within the target realm node. Random delivery is applied for the available server sessions
+   *
+   * @return transactional response reference, or NULL if answer is sent
+   */
+  const Response* sendRealmHost(const Message* message, const std::string &destinationRealm, const std::string &destinationHost = "") throw(anna::RuntimeException);
+
   /**
      Reset engine statistics.
      At the moment, only diameter servers processing time is observed.
@@ -639,22 +642,29 @@ public:
   void resetStatistics() throw();
 
 
+  /**
+   * Engine lazy initialization. Used if the engine is created when application is already running; for example
+   * on dynamic realms registration. At the moment is not actually needed (nothing is done at initialization),
+   * but it is recommended to start the component and set its state as 'running' from the point of view of the
+   * application.
+   */
+  void lazyInitialize() throw(RuntimeException);
+
+
 protected:
   /**
      Constructor.
 
      @param className Component class name
-     @param baseProtocolCodecEngine This will be used internally during invokation of @readCEA, @readDPA and @readDWA on servers,
-     and also used during base protocol messages tracing (if debug traces are enabled). You could provide NULL but you must be
-     sure that neither of the former situations are going to happen or an exception will be thrown. It is recommended to register
-     a codec engine pointed to a base protocol stack (you can use the files 'avps_ietf.xml' and 'commands_baseProtocol.xml'
-     located on ANNA suite project under 'source/diameter/stack/setups', or perhaps you can create your own dictionary from
-     file or directly with the dictionay creation API. Even you can use a greater dictionary (application dictionary), the
-     only condition is that must contain the resources to build base protocol messages. You could use @setBaseProtocolCodecEngine
-     to set this reference later; don't forget it.
+     @param baseProtocolDictionary This will be used internally when calling \@readCEA, \@readDPA and \@readDWA on
+     servers, and also used during base protocol messages tracing (if debug traces are enabled). You could provide
+     NULL, but you must be sure that neither of the former situations are going to happen or an exception will be
+     thrown (using setClientCERandDWR with DataBlock arguments, expects externally encoded messages and could help).
+     It is recommended to set a base protocol dictionary loading 'source/diameter/stack/setups' dictionaries (for
+     example 'avps_ietf.xml' plus 'commands_baseProtocol.xml'), or using the dictionary creation API. The dictionary
+     could also be an application stack, the only condition is containing the resources to build base protocol messages.
   */
-  Engine(const char *className, codec::Engine *baseProtocolCodecEngine);
-
+  Engine(const char *className, const stack::Dictionary *baseProtocolDictionary);
 
   // INTERNAL CREATORS AND CLOSE METHODS
   Server *createServer(Entity*, const socket_t&) throw(anna::RuntimeException);
@@ -702,15 +712,21 @@ protected:
   */
   virtual void releaseLocalServer(LocalServer*) throw() {;}
 
-
+  //  Gets the base protocol codec engine used internally.
+  //  This engine is initializaed on constructor with the base protocol dictionary.
+  //  The reason to not reuse any other codec engine from the application is to have this one isolated with no interference
+  //  regarding configuration changes (validation depth/mode, fix mode, etc.).
+  //
+  //  @return Pointer to the internal base protocol codec engine
+  codec::Engine *getBaseProtocolCodecEngine() const throw() { return const_cast<codec::Engine *>(&a_baseProtocolCodecEngine); }
 
 private:
 
   // Internal use: tracing and readCEA/DPA/DWA
-  codec::Engine *a_baseProtocolCodecEngine;
+  codec::Engine a_baseProtocolCodecEngine;
 
-  std::string a_realm;
-  std::string a_host;
+  std::string a_originRealm;
+  std::string a_originHost;
   bool a_autoBind;
   int a_numberOfClientSessionsPerServer;
 
@@ -721,6 +737,7 @@ private:
   anna::Millisecond a_watchdogPeriod;
 
 //   // ServerSessions messages:
+  std::string a_ceaPathfile; // path file to optional CEA (diameter local server configuration)
 //   anna::DataBlock a_cea;
 //   anna::DataBlock a_dwa;
 
@@ -742,11 +759,12 @@ private:
   void eraseDeprecatedIdleEntities() throw();
 
   // Component:
-  void do_initialize() throw() {;}
+  void do_initialize() throw(anna::RuntimeException);
   void do_stop() throw();
 
   // Integrity:
   void checkEntityCollision(const socket_v &) throw(anna::RuntimeException);
+  void assertBaseProtocolHealth() throw(anna::RuntimeException); // checks the dictionary
 
 
   //////////////////////////
@@ -821,10 +839,22 @@ private:
   const_localServer_iterator localServer_end() const throw() { return a_localServers.end(); }
   static const LocalServer* localServer(const_localServer_iterator ii) throw() { return ii->second; }
 
-  // Server sessions are managed within LocalServer (not at engine) due to dynamic cration nature
-
+  // Server sessions are managed within LocalServer (not at engine) due to dynamic creation nature
+  // Here we maintain the Destination-Realm / Destination-Host maps for DRA basics:
+  typedef std::vector<ServerSession*> server_sessions_vector_t;
+  typedef server_sessions_vector_t::const_iterator server_sessions_it_t;
+  typedef server_sessions_vector_t::iterator server_sessions_nc_it_t;
+  typedef std::map <std::string /* Destination-Host */, server_sessions_vector_t> dh_server_sessions_map_t;
+  typedef dh_server_sessions_map_t::const_iterator dh_server_sessions_it_t;
+  typedef dh_server_sessions_map_t::iterator dh_server_sessions_nc_it_t;
+  typedef std::map <std::string /* Destination-Realm */, dh_server_sessions_map_t> dr_dh_server_sessions_map_t;
+  typedef dr_dh_server_sessions_map_t::const_iterator dr_dh_server_sessions_it_t;
+  typedef dr_dh_server_sessions_map_t::iterator dr_dh_server_sessions_nc_it_t;
+  dr_dh_server_sessions_map_t a_dr_dh_server_sessions;
+  void manageDrDhServerSession(ServerSession *ss, bool register_or_desregister) throw();
 
   friend class Session;
+  friend class ClientSession;
   friend class ServerSession;
   friend class ServerSocket;
   friend class Server;