Testing library separation: now not in launcher but isolated
[anna.git] / include / anna / diameter.comm / Entity.hpp
index e69de29..b372497 100644 (file)
@@ -0,0 +1,518 @@
+// ANNA - Anna is Not Nothingness Anymore                                                         //
+//                                                                                                //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
+//                                                                                                //
+// See project site at http://redmine.teslayout.com/projects/anna-suite                           //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_diameter_comm_Entity_hpp
+#define anna_diameter_comm_Entity_hpp
+
+
+// STL
+#include <string>
+#include <vector>
+
+#include <anna/config/defines.hpp>
+
+#include <anna/core/RuntimeException.hpp>
+#include <anna/core/util/Millisecond.hpp>
+
+#include <anna/diameter.comm/ClassCode.hpp>
+
+
+namespace anna {
+class DataBlock;
+namespace xml {
+class Node;
+}
+}
+
+
+
+namespace anna {
+
+namespace diameter {
+
+namespace comm {
+
+class Engine;
+class Server;
+class Response;
+class Message;
+class ClientSession;
+
+
+/**
+   Generic diameter server list (N-servers entity)
+*/
+class Entity {
+
+public:
+
+  /**
+   * Defines behaviour on validation procedure: complete analysis or stop at first validation error over the message (by default)
+   */
+  struct SessionBasedModelsType { enum _v { RoundRobin, SessionIdOptionalPart, SessionIdHighPart, SessionIdLowPart /* default */ }; };
+
+private:
+
+
+  std::vector<Server*> a_servers;
+  int a_maxServers; // -1 means "no limit to add servers"
+  std::string a_description;
+  int a_category;
+  std::vector<Server*>::iterator a_deliveryIterator;
+  Server *a_lastUsedResource;
+
+  // Engine
+  Engine *a_engine;
+
+  // Balance and socket selection:
+  bool a_balance;
+  SessionBasedModelsType::_v a_sessionBasedModelsType;
+
+  // Availability
+  bool a_available; // any of the servers must be bound
+  void availabilityLost() throw();
+  void availabilityRecovered() throw();
+  bool refreshAvailability() throw(); // return true if change
+  void assertReady() throw(anna::RuntimeException);
+  void initialize() throw();
+  void childIdle() const throw();
+
+  // Selected for remove
+  bool a_deprecated; // entity has been selected as deprecated (will be removed when idle)
+
+  // internal helpers
+  std::string a_socketListLiteral; // ADDRESS:PORT space-separated list
+  std::string a_primarySocketLiteral; // ADDRESS:PORT for primary (used on standard entities)
+  std::string a_secondarySocketLiteral; // ADDRESS:PORT for primary (used on standard entities)
+
+
+  // Activity
+  anna::Millisecond a_lastIncomingActivityTime;   // last unix timestamp (in milliseconds) when message reception was managed over this entity
+  anna::Millisecond a_lastOutgoingActivityTime;   // last unix timestamp (in milliseconds) when message sending was managed over this entity
+  void updateIncomingActivityTime() throw();
+  void updateOutgoingActivityTime() throw();
+
+  // Private close/destroy method
+  void close(bool destroy) throw(anna::RuntimeException);
+
+  // helpers
+  static const char* asText(const SessionBasedModelsType::_v) throw();
+
+public:
+
+
+  /**
+   * Default constructor. Entities should be create through diameter::comm::Engine
+   * @param maxServers Maximum number of servers managed by the entity. Default is 2 (standard/dual entity).
+   * The value -1, means no limit to add servers.
+   */
+  Entity(int maxServers = 2) : a_maxServers(maxServers) { initialize(); }
+
+
+  /**
+   * Sets the maximum number of servers managed by the entity.
+   *
+   * @param maxServers Maximum number of servers managed by the entity.
+   */
+  void setMaxServers(int maxServers) throw() { a_maxServers = maxServers; }
+
+  /**
+   * Gets the maximum number of servers managed by the entity.
+   *
+   * @return Maximum number of servers managed by the entity.
+   */
+  int getMaxServers() const throw() { return a_maxServers; }
+
+
+  /**
+   * Sets the entity description.
+   *
+   * @param description Entity description. Empty by default.
+   */
+  void setDescription(const std::string &description) throw() { a_description = description; }
+
+  /**
+   * Gets the entity description.
+   *
+   * @return Entity description.
+   */
+  const std::string & getDescription() const throw() { return a_description; }
+
+
+  /**
+  * Sets the diameter::comm::Engine
+  * @param e Diameter::comm::Engine
+  */
+  void setEngine(Engine *e) throw() { a_engine = e; }
+
+  /**
+  * Gets the diameter::comm::Engine
+  * @return Diameter::comm::Engine
+  */
+  Engine *getEngine() const throw() { return a_engine; }
+
+  /**
+  * Add a server to the entity and create all the servers configured at #setSocketsPerDiameterServer within that server.
+  *
+  * \param serverId Diameter server ip/port.
+  *
+  * @return Returns success on send operation over any server within the entity
+  */
+  void addServer(const socket_t & serverId) throw(anna::RuntimeException);
+
+  /**
+   * Binds entity servers.
+   *
+   * @return Returns true if all client-session were successfully bound
+   */
+  bool bind() throw(anna::RuntimeException);
+
+  /**
+   * Propagate auto recovery configuration to servers within entity
+   *
+   * @param autoRecovery Auto recovery indicator. True by default.
+   */
+  void raiseAutoRecovery(bool autoRecovery = true) throw(anna::RuntimeException);
+
+  /**
+     Sets timeout for wait responses for any class code request for all entity servers
+
+     \param v Diameter request type.
+     \param millisecond Milliseconds for timeout
+  */
+  void setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) throw();
+
+  /**
+     Sets entity category. Used by application in order to categorize or clasify.
+
+     @param category Entity category
+  */
+  void setCategory(int category) throw() { a_category = category; }
+
+  /**
+     Gets entity category. Used by application in order to categorize or clasify.
+
+     @return Entity category
+  */
+  int getCategory() const throw() { return a_category; }
+
+  /**
+     Gets the last used resource (server) during sending.
+     Broadcast doesn't updates this information.
+  */
+  Server *getLastUsedResource() const throw() { return (a_lastUsedResource); }
+
+
+  /**
+   * Balance over entity servers or use standard behaviour (first primary, secondary if fails, etc.).
+   * New created entities have balance disabled.
+   *
+   * @param balance True or false to enable or disable.
+   */
+   void setBalance (bool balance) throw() { a_balance = balance; }
+
+  /**
+   * Gets the balance mode
+   *
+   * @return True if balance over entity servers is enabled, false if standard behaviour is configured (default).
+   */
+   bool getBalance() const throw() { return a_balance; }
+
+
+// SIMPLE BALANCE or STANDARD documentation version
+//   /**
+//      Sent a message to the entity. First uses primary server, secondary if fails and so on to the
+//      last defined resource (server) within entity. Another sending algorithm (non standard) could
+//      be enabled (balance boolean parameter): it consist in round-robin server selection without
+//      trying any one if fails (standard behaviour tries all servers from FIRST defined).
+//      Anyway, last used delivery resource could be known through #getLastUsedResource().
+//
+//      When the message is a request, a timer will be set automatically to control the response time.
+//      If expires, the ResultCode Timeout will be finally notified on #Entity::eventResponse. This
+//      timeout value will be configured at #setClassCodeTimeout.
+//
+//      \param message Message sent.
+//      \param balance False by default (standard beaviour), but useful to balance over servers within entity.
+//
+//      @return Boolean about success in send operation. Standard behaviour (no balance) implies true result when any
+//      of the entity servers could send the message, and false when neither of the servers was available or fail to
+//      send the message. Broadcast try to send all over the resources in spite of any fail, and balanced sendings
+//      fails when next selected resource fail to send the message (and no alarm or error counter is generated in
+//      this case because it can't be understood/ensured as entity-sending fail.
+//   */
+
+// OJO: en el caso estandard, no se prueban todas las sessiones de un servidor si tiene mas de una, luego la alarma
+//      generada en caso de error, presupone que las sessiones no usadas, tambi�n dar�an error, lo cual no tiene porque
+//      ser cierto. En condiciones normales, los servidores tienen una session, con lo que lo anterior es cierto y el
+//      la practica es lo mas normal.
+
+  /**
+     Sent a message to the entity. First uses primary server, secondary if fails and so on to the
+     last defined resource (server) within entity. Another sending algorithm (non standard) could
+     be enabled (@setBalance): it consist in round-robin server selection to set the first resource
+     in a complete cycle (standard behaviour tries all servers from FIRST defined).
+     Anyway, last used delivery resource could be known through #getLastUsedResource().
+
+     When the message is a request, a timer will be set automatically to control the response time.
+     If expires, the ResultCode Timeout will be finally notified on #Entity::eventResponse. This
+     timeout value will be configured at #setClassCodeTimeout.
+
+     \param message Message sent.
+
+     @return Boolean about success in send operation. Implies true result when any of the entity servers could
+     send the message, and false when neither of the servers was available or fail to send the message (an alarm
+     and error counter will be generated in this case). Broadcast try to send all over the resources in spite of
+     any fail.
+  */
+  bool send(const Message *message) throw(anna::RuntimeException);
+  bool send(const Message &message) throw(anna::RuntimeException) { return send(&message); }
+
+  /**
+   * Sets sessions based models type.
+   * \param sessionBasedModelsType Session based models type: RoundRobin, SessionIdLowPart (default), SessionIdHighPart or SessionIdOptionalPart.
+   */
+  void setSessionBasedModelsType(const SessionBasedModelsType::_v sessionBasedModelsType)  throw() { a_sessionBasedModelsType = sessionBasedModelsType; }
+
+  /**
+   * Returns sessions based models type.
+   * \return Session based models type: RoundRobin, SessionIdLowPart, SessionIdHighPart or SessionIdOptionalPart.
+   */
+  SessionBasedModelsType::_v getSessionBasedModelsType() const throw() { return a_sessionBasedModelsType; }
+
+
+  /**
+     Before sending a message over each entity server, socketId could be specified to select
+     which client session within such server will manage the message.
+
+     Default implementation has been focused on charging applications but any other kind of
+     application could re-implement this method and change the behaviour:
+
+     <pre>
+     Charging involves two peers:
+
+        Charging Trigger Function (CTF): Makes decisions on how to charge the user for specific
+                                         services, issues requests to the server (OCF).
+        Online Charging Function (OCF):  Performs actual charging based on received message type,
+                                         service logic and user profile information.
+
+     There are three main scenarios:
+
+        Immediate Event Charging (IEC): The CTF sends a one time request. This request contains
+                                        a predefined set of AVPs indicating which service has
+                                        been activated or how many units have been consumed
+                                        (this depends on application logic).
+
+        Event Charging with Unit Reservation (ECUR): The CTF issues a request which indicates the
+                                                     desired unit count for reservation. On service
+                                                     delivery, the CTF issues another request which
+                                                     indicates how many units were actually consumed.
+                                                     Units can be of any type, as they are application
+                                                     specific.
+
+        Session Charging with Unit Reservation(SCUR): As above, however reservation can happen more than once.
+
+     In order to minimize race conditions within trasactions, default implementation will select the connection
+     fixed by an stickiness value (Session-Id will be used) for ECUR and SCUR models (Data, Voice and Content
+     traffic). IEC model, represented by SMS ans MMS traffic will use round-robin between sockets. The type
+     of traffic will be analyzed by mean Service-Context-Id AVP. If traffic type is not reconized, value of
+     '-1' will be returned doing round-robin socket selection within active server.
+
+     Diameter session-oriented load balancing enables to distribute Diameter signaling traffic across
+     multiple client sessions for the selected entity server. Application could re-implement different
+     load balancing policies, including support for session stickiness and business decisions, and
+     subscriber and service aware contextual load balancing strategies. By default, Session-Id avp
+     is used to select the resource. Session-Id is split into 4 sections: diameter identity, high
+     part, low part and optional part. Default implementation analizes 'low' part, returning its
+     value as reference for socket selection. Use @setSessionBasedModelsType to change this behaviour.
+     </pre>
+
+     When server is configured as single client session (max client sessions equal to 1), entity will ignore
+     this method being more efficient, because former algorithms would not affect the session selection.
+
+     \param message Message which is being sent.
+     \param maxClientSessions Number of client-sessions on specific server prepared for send.
+
+     @return Socket-id used within range [0,maxClientSessions-1]. Value '-1' if round-robin is desired.
+     If socket-id is return out of range, send procedure will throw an exception.
+  */
+  virtual int readSocketId(const Message *message, int maxClientSessions) const throw();
+
+
+  /**
+     Sent a message to all the entity servers.
+     It is used, i.e., in Disconnect-Peer-Request procedure over a certain entity.
+
+     \param message Message which is being sent.
+
+     @return Returns true (success) only when broadcast is success over all the entity servers. If any server fails,
+     then false is returned.
+  */
+  bool broadcast(const Message *message) throw(anna::RuntimeException);
+  bool broadcast(const Message &message) throw(anna::RuntimeException) { return broadcast(&message); }
+
+
+  /**
+     Returns true when any of the entity servers is Bound. False when all not-bound.
+  */
+  bool isAvailable() const throw() { return a_available; }
+
+  /**
+     Returns true when the entity has been selected as deprecated
+  */
+  bool isDeprecated() const throw() { return a_deprecated; }
+
+  /**
+     Sets the entity deprecated state
+  */
+  void setDeprecated(bool deprecated = true) throw() { a_deprecated = deprecated; }
+
+
+  /**
+     Gets the number of requests messages over-the-air.
+
+     @return OTA messages.
+  */
+  int getOTARequests() const throw();
+
+  /**
+     Returns idle state (no pending answers).
+
+     @return Idle state.
+  */
+  bool idle() const throw() { return (getOTARequests() == 0); }
+
+
+  std::vector<Server*>::iterator begin() throw() { return a_servers.begin(); }
+  std::vector<Server*>::iterator end() throw() { return a_servers.end(); }
+  std::vector<Server*>::const_iterator begin() const throw() { return a_servers.begin(); }
+  std::vector<Server*>::const_iterator end() const throw() { return a_servers.end(); }
+
+  /**
+     Close all the entity servers (close client-sessions within them). Depending on client-session configuration ('OnDisconnect' behaviour),
+     pending answers will be wait (graceful) or ignored (immediate-abrupt close).
+     Resources are not destroyed.
+  */
+  void close() throw(anna::RuntimeException) { close(false /* no destroy */); }
+
+  // helpers
+
+  /**
+     Number of currently configured servers
+  */
+  int getNumberOfServers() const throw() { return a_servers.size(); }
+
+  /**
+     Number of maximum allowed servers
+  */
+  int getMaxServerss() const throw() { return a_maxServers; }
+
+  /**
+     List of (address,port) pairs defining entity servers
+  */
+  socket_v getAddressPortList() const throw();
+
+
+  /**
+     Deny resources for delivery restriction.
+     Deny all its servers
+  */
+  void hide() throw();
+
+  /**
+     Allow resource for delivery permission.
+     Allow all its servers
+  */
+  void show() throw();
+
+  /**
+     Returns true when all its servers resources are hidden for application messages delivery
+  */
+  bool hidden() const throw();
+
+  /**
+     Returns true when all its servers resources are shown for application messages delivery
+  */
+  bool shown() const throw();
+
+
+  /**
+     Class string representation
+     \return String with relevant information for this instance.
+  */
+  std::string asString() const throw();
+
+  /**
+     Class xml representation
+     \param parent Parent XML node on which hold this instance information.
+     \return XML document with relevant information for this instance.
+  */
+  anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
+
+protected:
+
+  /**
+     Handler about event break connection from diameter server (server) over this entity.
+     When notified, ANNA.diameter.comm generates an diameter::comm::Entity::eventResponse for every request with pending answers.
+     Default implementation traces warning event
+     \param clientSession ClientSession from which shutdown has been received
+  */
+  virtual void eventPeerShutdown(const ClientSession* clientSession) throw();
+
+  /**
+     Handler about a request retransmission over the session.
+     Default implementation traces warning event
+     \param clientSession ClientSession from which retransmission happened
+     \param request Retransmitted request message
+  */
+  virtual void eventRequestRetransmission(const ClientSession* clientSession, Message *request) throw();
+
+  /**
+     Handler for diameter server (server) responses
+
+     \param response Answer container object for corresponding diameter request
+  */
+  virtual void eventResponse(const Response& response) throw(anna::RuntimeException) = 0;
+
+  /**
+     Handler for diameter server (server) requests
+
+     \param clientSession ClientSession from which request has been received
+     \param request Diameter request message received
+  */
+  virtual void eventRequest(ClientSession* clientSession, const anna::DataBlock &request) throw(anna::RuntimeException) = 0;
+  //virtual void eventRequest(ClientSession* clientSession, const Message& request) throw(anna::RuntimeException) = 0;
+
+  /**
+     Handler for diameter session responses out of context
+
+     \param clientSession ClientSession from which request has been received
+     \param response Answer data block object without context match
+  */
+  virtual void eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock& response) throw(anna::RuntimeException) = 0;
+
+  /**
+     Handler for diameter session Disconnect-Peer-Answer messages
+
+     \param clientSession ClientSession from which request has been received
+     \param response Answer data block object without context match
+  */
+  virtual void eventDPA(ClientSession *clientSession, const anna::DataBlock& response) throw(anna::RuntimeException) = 0;
+
+
+
+
+  friend class Engine;
+  friend class Server;
+};
+
+}
+}
+}
+
+#endif
+