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