// 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>
class Engine;
}
-namespace comm {
+namespace stack {
+class Dictionary;
+}
+namespace comm {
+class Response;
class Entity;
class Server;
class LocalServer;
public:
/**
- Logical name for this anna::app::Component.
- \return Logical name for this anna::app::Component.
- */
- static const char* getClassName() throw() { return "anna::diameter::comm::Engine"; }
-
- /**
- 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; }
/**
* Propagate auto recovery configuration to entities within engine. Recovery period is configured at
- * #anna::comm::Communicator::setRecoveryTime. All the client client-sessions created throught #createEntity,
- * will be created based on the engine auto-recovery value (enable by default). But you could access entities,
- * servers or client-sessions independently to change this behaviour.
+ * #anna::comm::Communicator::setRecoveryTime (5 seconds by default). All the client client-sessions
+ * created throught #createEntity, will be created based on the engine auto-recovery value (enabled
+ * by default).
+ * You could access entities, servers or client-sessions independently to use this method, but recovery
+ * time should be updated through communicator and will apply for new created connections.
*
* @param autoRecovery Auto recovery indicator. True by default.
*/
* @param cer Capabilities-Exchange-Request message (encoded) for the client-sessions bind.
* @param dwr Device-Watchdog-Request message (encoded) for the client-sessions keep-alive.
*/
- void setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException);
+ void setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException);
+ /**
+ * Sets CER and DWR diameter messages to be used over created client-sessions. If empty string is provided for CER and/or DWR, default version will be configured.
+ * Its recommended to set this global configuration although it is possible to configure each client-session separately.
+ *
+ * @param cer Capabilities-Exchange-Request xml message path file for the client-sessions bind. If empty string is provided (default), a default version for CER will be encoded.
+ * @param dwr Device-Watchdog-Request xml message path file for the client-sessions keep-alive. If empty string is provided (default), a default version for DWR will be encoded.
+ */
+ void setClientCERandDWR(const std::string & cer = "", const std::string & dwr = "") throw(anna::RuntimeException);
/**
* Sets the watchdog period (DWR) for client-sessions.
*/
void setNumberOfClientSessionsPerServer(int numberOfClientSessionsPerServer) throw() { a_numberOfClientSessionsPerServer = numberOfClientSessionsPerServer; }
- /**
- * Gets true when end-to-end sequence is freezed on requests sendings.
- * Engine starts with false value, sequencing end-to-end as hop-by-hop does.
- * \return Freeze end-to-end indicator.
- */
- bool getFreezeEndToEndOnSending() const throw() { return a_freezeEndToEndOnSending; }
-
- /**
- * Freeze end-to-end indicator on requests sendings.
- * \param freezeEndToEndOnSending Freeze end-to-end indicator.
- */
- void setFreezeEndToEndOnSending(bool freezeEndToEndOnSending = true) throw() { a_freezeEndToEndOnSending = freezeEndToEndOnSending; }
/**
* Returns client-session instance identified by (address, port, socketId) provided.
*/
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
*
*/
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.
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.
- */
- Engine();
+ @param className Component class name
+ @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, const stack::Dictionary *baseProtocolDictionary);
// INTERNAL CREATORS AND CLOSE METHODS
Server *createServer(Entity*, const socket_t&) throw(anna::RuntimeException);
*/
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:
- std::string a_realm;
- std::string a_host;
+ // Internal use: tracing and readCEA/DPA/DWA
+ codec::Engine a_baseProtocolCodecEngine;
+
+ std::string a_originRealm;
+ std::string a_originHost;
bool a_autoBind;
int a_numberOfClientSessionsPerServer;
- bool a_freezeEndToEndOnSending;
// ClientSessions messages:
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;
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
//////////////////////////
// CLIENT FUNCTIONALITY //
//////////////////////////
- //typedef int clientSession_key; // exclusiveHash('ADDR:PORT|id')
typedef std::string clientSession_key; // 'ADDR:PORT|id'
typedef std::map <clientSession_key, ClientSession*> clientSession_container;
typedef clientSession_container::value_type clientSession_value_type;
const_server_iterator server_end() const throw() { return a_servers.end(); }
static const Server* server(const_server_iterator ii) throw() { return ii->second; }
- //typedef int entity_key; // exclusiveHash('IP1:PORT1 IP2:PORT2 IP3:PORT3 ...')
typedef std::string entity_key; // 'ADDR1:PORT1 ADDR2:PORT2 ADDR3:PORT3 ...'
entity_key getEntityKey(const socket_v &) const throw();
entity_key getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw();
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;