Fix local server for multiple applications
[anna.git] / include / anna / diameter.comm / Entity.hpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #ifndef anna_diameter_comm_Entity_hpp
10 #define anna_diameter_comm_Entity_hpp
11
12
13 // STL
14 #include <string>
15 #include <vector>
16
17 #include <anna/config/defines.hpp>
18
19 #include <anna/core/RuntimeException.hpp>
20 #include <anna/core/util/Millisecond.hpp>
21
22 #include <anna/diameter.comm/ClassCode.hpp>
23
24
25 namespace anna {
26 class DataBlock;
27 namespace xml {
28 class Node;
29 }
30 }
31
32
33
34 namespace anna {
35
36 namespace diameter {
37
38 namespace comm {
39
40 class Engine;
41 class Server;
42 class Response;
43 class Message;
44 class ClientSession;
45
46
47 /**
48    Generic diameter server list (N-servers entity)
49 */
50 class Entity {
51
52 public:
53
54   /**
55    * Sessions based models type
56    */
57   struct SessionBasedModelsType { enum _v { RoundRobin, SessionIdOptionalPart, SessionIdHighPart, SessionIdLowPart /* default */ }; };
58
59 private:
60
61
62   std::vector<Server*> a_servers;
63   int a_maxServers; // -1 means "no limit to add servers"
64   std::string a_description;
65   int a_category;
66   std::vector<Server*>::iterator a_deliveryIterator;
67   Server *a_lastUsedResource;
68
69   // Engine
70   Engine *a_engine;
71
72   // Balance and socket selection:
73   bool a_balance;
74   SessionBasedModelsType::_v a_sessionBasedModelsType;
75
76   // Availability
77   bool a_available; // any of the servers must be bound
78   void availabilityLost() ;
79   void availabilityRecovered() ;
80   bool refreshAvailability() ; // return true if change
81   void assertReady() noexcept(false);
82   void initialize() ;
83   void childIdle() const ;
84
85   // Selected for remove
86   bool a_deprecated; // entity has been selected as deprecated (will be removed when idle)
87
88   // internal helpers
89   std::string a_socketListLiteral; // ADDRESS:PORT space-separated list
90   std::string a_primarySocketLiteral; // ADDRESS:PORT for primary (used on standard entities)
91   std::string a_secondarySocketLiteral; // ADDRESS:PORT for primary (used on standard entities)
92
93
94   // Activity
95   anna::Millisecond a_lastIncomingActivityTime;   // last unix timestamp (in milliseconds) when message reception was managed over this entity
96   anna::Millisecond a_lastOutgoingActivityTime;   // last unix timestamp (in milliseconds) when message sending was managed over this entity
97   void updateIncomingActivityTime() ;
98   void updateOutgoingActivityTime() ;
99
100   // Private close/destroy method
101   void close(bool destroy) noexcept(false);
102
103   // helpers
104   static const char* asText(const SessionBasedModelsType::_v) ;
105
106 public:
107
108
109   /**
110    * Default constructor. Entities should be create through diameter::comm::Engine
111    * @param maxServers Maximum number of servers managed by the entity. Default is 2 (standard/dual entity).
112    * The value -1, means no limit to add servers.
113    */
114   Entity(int maxServers = 2) : a_maxServers(maxServers) { initialize(); }
115
116
117   /**
118    * Sets the maximum number of servers managed by the entity.
119    *
120    * @param maxServers Maximum number of servers managed by the entity.
121    */
122   void setMaxServers(int maxServers) { a_maxServers = maxServers; }
123
124   /**
125    * Gets the maximum number of servers managed by the entity.
126    *
127    * @return Maximum number of servers managed by the entity.
128    */
129   int getMaxServers() const { return a_maxServers; }
130
131
132   /**
133    * Sets the entity description.
134    *
135    * @param description Entity description. Empty by default.
136    */
137   void setDescription(const std::string &description) { a_description = description; }
138
139   /**
140    * Gets the entity description.
141    *
142    * @return Entity description.
143    */
144   const std::string & getDescription() const { return a_description; }
145
146
147   /**
148   * Sets the diameter::comm::Engine
149   * @param e Diameter::comm::Engine
150   */
151   void setEngine(Engine *e) { a_engine = e; }
152
153   /**
154   * Gets the diameter::comm::Engine
155   * @return Diameter::comm::Engine
156   */
157   Engine *getEngine() const { return a_engine; }
158
159   /**
160   * Add a server to the entity and create all the servers configured at #setSocketsPerDiameterServer within that server.
161   *
162   * \param serverId Diameter server ip/port.
163   *
164   * @return Returns success on send operation over any server within the entity
165   */
166   void addServer(const socket_t & serverId) noexcept(false);
167
168   /**
169    * Binds entity servers.
170    *
171    * @return Returns true if all client-session were successfully bound
172    */
173   bool bind() noexcept(false);
174
175   /**
176    * Propagate auto recovery configuration to servers within entity
177    *
178    * @param autoRecovery Auto recovery indicator. True by default.
179    */
180   void raiseAutoRecovery(bool autoRecovery = true) noexcept(false);
181
182   /**
183      Sets timeout for wait responses for any class code request for all entity servers
184
185      \param v Diameter request type.
186      \param millisecond Milliseconds for timeout
187   */
188   void setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) ;
189
190   /**
191      Sets entity category. Used by application in order to categorize or clasify.
192
193      @param category Entity category
194   */
195   void setCategory(int category) { a_category = category; }
196
197   /**
198      Gets entity category. Used by application in order to categorize or clasify.
199
200      @return Entity category
201   */
202   int getCategory() const { return a_category; }
203
204   /**
205      Gets the last used resource (server) during sending.
206      Broadcast doesn't updates this information.
207   */
208   Server *getLastUsedResource() const { return (a_lastUsedResource); }
209
210
211   /**
212    * Balance over entity servers or use standard behaviour (first primary, secondary if fails, etc.).
213    * New created entities have balance disabled.
214    *
215    * @param balance True or false to enable or disable.
216    */
217    void setBalance (bool balance) { a_balance = balance; }
218
219   /**
220    * Gets the balance mode
221    *
222    * @return True if balance over entity servers is enabled, false if standard behaviour is configured (default).
223    */
224    bool getBalance() const { return a_balance; }
225
226
227 // SIMPLE BALANCE or STANDARD documentation version
228 //   /**
229 //      Sent a message to the entity. First uses primary server, secondary if fails and so on to the
230 //      last defined resource (server) within entity. Another sending algorithm (non standard) could
231 //      be enabled (balance boolean parameter): it consist in round-robin server selection without
232 //      trying any one if fails (standard behaviour tries all servers from FIRST defined).
233 //      Anyway, last used delivery resource could be known through #getLastUsedResource().
234 //
235 //      When the message is a request, a timer will be set automatically to control the response time.
236 //      If expires, the ResultCode Timeout will be finally notified on #Entity::eventResponse. This
237 //      timeout value will be configured at #setClassCodeTimeout.
238 //
239 //      \param message Message sent.
240 //      \param balance False by default (standard beaviour), but useful to balance over servers within entity.
241 //
242 //      @return Boolean about success in send operation. Standard behaviour (no balance) implies true result when any
243 //      of the entity servers could send the message, and false when neither of the servers was available or fail to
244 //      send the message. Broadcast try to send all over the resources in spite of any fail, and balanced sendings
245 //      fails when next selected resource fail to send the message (and no alarm or error counter is generated in
246 //      this case because it can't be understood/ensured as entity-sending fail.
247 //   */
248
249 // OJO: en el caso estandard, no se prueban todas las sessiones de un servidor si tiene mas de una, luego la alarma
250 //      generada en caso de error, presupone que las sessiones no usadas, tambi�n dar�an error, lo cual no tiene porque
251 //      ser cierto. En condiciones normales, los servidores tienen una session, con lo que lo anterior es cierto y el
252 //      la practica es lo mas normal.
253
254   /**
255      Sent a message to the entity. First uses primary server, secondary if fails and so on to the
256      last defined resource (server) within entity. Another sending algorithm (non standard) could
257      be enabled (@setBalance): it consist in round-robin server selection to set the first resource
258      in a complete cycle (standard behaviour tries all servers from FIRST defined).
259      Anyway, last used delivery resource could be known through #getLastUsedResource().
260
261      When the message is a request, a timer will be set automatically to control the response time.
262      If expires, the ResultCode Timeout will be finally notified on #Entity::eventResponse. This
263      timeout value will be configured at #setClassCodeTimeout.
264
265      \param message Message sent.
266
267      @return Boolean about success in send operation. Implies true result when any of the entity servers could
268      send the message, and false when neither of the servers was available or fail to send the message (an alarm
269      and error counter will be generated in this case). Broadcast try to send all over the resources in spite of
270      any fail.
271   */
272   bool send(const Message *message) noexcept(false);
273   bool send(const Message &message) noexcept(false) { return send(&message); }
274
275   /**
276    * Sets sessions based models type.
277    * \param sessionBasedModelsType Session based models type: RoundRobin, SessionIdLowPart (default), SessionIdHighPart or SessionIdOptionalPart.
278    */
279   void setSessionBasedModelsType(const SessionBasedModelsType::_v sessionBasedModelsType)  { a_sessionBasedModelsType = sessionBasedModelsType; }
280
281   /**
282    * Returns sessions based models type.
283    * \return Session based models type: RoundRobin, SessionIdLowPart, SessionIdHighPart or SessionIdOptionalPart.
284    */
285   SessionBasedModelsType::_v getSessionBasedModelsType() const { return a_sessionBasedModelsType; }
286
287
288   /**
289      Before sending a message over each entity server, socketId could be specified to select
290      which client session within such server will manage the message.
291
292      Default implementation has been focused on charging applications but any other kind of
293      application could re-implement this method and change the behaviour:
294
295      <pre>
296      Charging involves two peers:
297
298         Charging Trigger Function (CTF): Makes decisions on how to charge the user for specific
299                                          services, issues requests to the server (OCF).
300         Online Charging Function (OCF):  Performs actual charging based on received message type,
301                                          service logic and user profile information.
302
303      There are three main scenarios:
304
305         Immediate Event Charging (IEC): The CTF sends a one time request. This request contains
306                                         a predefined set of AVPs indicating which service has
307                                         been activated or how many units have been consumed
308                                         (this depends on application logic).
309
310         Event Charging with Unit Reservation (ECUR): The CTF issues a request which indicates the
311                                                      desired unit count for reservation. On service
312                                                      delivery, the CTF issues another request which
313                                                      indicates how many units were actually consumed.
314                                                      Units can be of any type, as they are application
315                                                      specific.
316
317         Session Charging with Unit Reservation(SCUR): As above, however reservation can happen more than once.
318
319      In order to minimize race conditions within trasactions, default implementation will select the connection
320      fixed by an stickiness value (Session-Id will be used) for ECUR and SCUR models (Data, Voice and Content
321      traffic). IEC model, represented by SMS ans MMS traffic will use round-robin between sockets. The type
322      of traffic will be analyzed by mean Service-Context-Id AVP. If traffic type is not reconized, value of
323      '-1' will be returned doing round-robin socket selection within active server.
324
325      Diameter session-oriented load balancing enables to distribute Diameter signaling traffic across
326      multiple client sessions for the selected entity server. Application could re-implement different
327      load balancing policies, including support for session stickiness and business decisions, and
328      subscriber and service aware contextual load balancing strategies. By default, Session-Id avp
329      is used to select the resource. Session-Id is split into 4 sections: diameter identity, high
330      part, low part and optional part. Default implementation analizes 'low' part, returning its
331      value as reference for socket selection. Use @setSessionBasedModelsType to change this behaviour.
332      </pre>
333
334      When server is configured as single client session (max client sessions equal to 1), entity will ignore
335      this method being more efficient, because former algorithms would not affect the session selection.
336
337      \param message Message which is being sent.
338      \param maxClientSessions Number of client-sessions on specific server prepared for send.
339
340      @return Socket-id used within range [0,maxClientSessions-1]. Value '-1' if round-robin is desired.
341      If socket-id is return out of range, send procedure will throw an exception.
342   */
343   virtual int readSocketId(const Message *message, int maxClientSessions) const ;
344
345
346   /**
347      Sent a message to all the entity servers.
348      It is used, i.e., in Disconnect-Peer-Request procedure over a certain entity.
349
350      \param message Message which is being sent.
351
352      @return Returns true (success) only when broadcast is success over all the entity servers. If any server fails,
353      then false is returned.
354   */
355   bool broadcast(const Message *message) noexcept(false);
356   bool broadcast(const Message &message) noexcept(false) { return broadcast(&message); }
357
358
359   /**
360      Returns true when any of the entity servers is Bound. False when all not-bound.
361   */
362   bool isAvailable() const { return a_available; }
363
364   /**
365      Returns true when the entity has been selected as deprecated
366   */
367   bool isDeprecated() const { return a_deprecated; }
368
369   /**
370      Sets the entity deprecated state
371   */
372   void setDeprecated(bool deprecated = true) { a_deprecated = deprecated; }
373
374
375   /**
376      Gets the number of requests messages over-the-air.
377
378      @return OTA messages.
379   */
380   int getOTARequests() const ;
381
382   /**
383      Returns idle state (no pending answers).
384
385      @return Idle state.
386   */
387   bool idle() const { return (getOTARequests() == 0); }
388
389
390   std::vector<Server*>::iterator begin() { return a_servers.begin(); }
391   std::vector<Server*>::iterator end() { return a_servers.end(); }
392   std::vector<Server*>::const_iterator begin() const { return a_servers.begin(); }
393   std::vector<Server*>::const_iterator end() const { return a_servers.end(); }
394
395   /**
396      Close all the entity servers (close client-sessions within them). Depending on client-session configuration ('OnDisconnect' behaviour),
397      pending answers will be wait (graceful) or ignored (immediate-abrupt close).
398      Resources are not destroyed.
399   */
400   void close() noexcept(false) { close(false /* no destroy */); }
401
402   // helpers
403
404   /**
405      Number of currently configured servers
406   */
407   int getNumberOfServers() const { return a_servers.size(); }
408
409   /**
410      Number of maximum allowed servers
411   */
412   int getMaxServerss() const { return a_maxServers; }
413
414   /**
415      List of (address,port) pairs defining entity servers
416   */
417   socket_v getAddressPortList() const ;
418
419
420   /**
421      Deny resources for delivery restriction.
422      Deny all its servers
423   */
424   void hide() ;
425
426   /**
427      Allow resource for delivery permission.
428      Allow all its servers
429   */
430   void show() ;
431
432   /**
433      Returns true when all its servers resources are hidden for application messages delivery
434   */
435   bool hidden() const ;
436
437   /**
438      Returns true when all its servers resources are shown for application messages delivery
439   */
440   bool shown() const ;
441
442
443   /**
444      Class string representation
445      \return String with relevant information for this instance.
446   */
447   std::string asString() const ;
448
449   /**
450      Class xml representation
451      \param parent Parent XML node on which hold this instance information.
452      \return XML document with relevant information for this instance.
453   */
454   anna::xml::Node* asXML(anna::xml::Node* parent) const ;
455
456 protected:
457
458   /**
459      Handler about event break connection from diameter server (server) over this entity.
460      When notified, ANNA.diameter.comm generates an diameter::comm::Entity::eventResponse for every request with pending answers.
461      Default implementation traces warning event
462      \param clientSession ClientSession from which shutdown has been received
463   */
464   virtual void eventPeerShutdown(const ClientSession* clientSession) ;
465
466   /**
467      Handler about a request retransmission over the session.
468      Default implementation traces warning event
469      \param clientSession ClientSession from which retransmission happened
470      \param request Retransmitted request message
471   */
472   virtual void eventRequestRetransmission(const ClientSession* clientSession, Message *request) ;
473
474   /**
475      Handler for diameter server (server) responses
476
477      \param response Answer container object for corresponding diameter request
478      \param myNode Own origin host
479   */
480   virtual void eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
481
482   /**
483      Handler for diameter server (server) requests
484
485      \param clientSession ClientSession from which request has been received
486      \param request Diameter request message received
487      \param myNode Own origin host
488   */
489   virtual void eventRequest(ClientSession* clientSession, const anna::DataBlock &request, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
490   //virtual void eventRequest(ClientSession* clientSession, const Message& request) noexcept(false) = 0;
491
492   /**
493      Handler for diameter session responses out of context
494
495      \param clientSession ClientSession from which request has been received
496      \param response Answer data block object without context match
497      \param myNode Own origin host
498   */
499   virtual void eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
500
501   /**
502      Handler for diameter session Disconnect-Peer-Answer messages
503
504      \param clientSession ClientSession from which request has been received
505      \param response Answer data block object without context match
506      \param myNode Own origin host
507   */
508   virtual void eventDPA(ClientSession *clientSession, const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
509
510
511
512
513   friend class Engine;
514   friend class Server;
515 };
516
517 }
518 }
519 }
520
521 #endif
522