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