Fixes and improvs. Basic DRA feature.
[anna.git] / include / anna / diameter.comm / Engine.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_Engine_hpp
10 #define anna_diameter_comm_Engine_hpp
11
12
13 // STL
14 #include <map>
15 #include <vector>
16 #include <string>
17 #include <algorithm>
18
19 #include <anna/app/Component.hpp>
20 #include <anna/core/util/Recycler.hpp>
21
22 #include <anna/diameter/codec/Engine.hpp>
23 #include <anna/diameter.comm/Server.hpp>
24 #include <anna/diameter.comm/ServerSession.hpp>
25 #include <anna/config/defines.hpp>
26 #include <anna/diameter.comm/ClientSession.hpp>
27 #include <anna/diameter.comm/ServerSession.hpp>
28
29 // Standard
30 #include <time.h>
31
32
33 //------------------------------------------------------------------------------
34 //---------------------------------------------------------------------- #define
35 //------------------------------------------------------------------------------
36
37 namespace anna {
38 class DataBlock;
39 class Millisecond;
40 }
41
42
43
44 namespace anna {
45
46 namespace diameter {
47
48 namespace codec {
49 class Engine;
50 }
51
52 namespace stack {
53 class Dictionary;
54 }
55
56 namespace comm {
57
58 class Response;
59 class Entity;
60 class Server;
61 class LocalServer;
62
63 /**
64  *  General manager for connections to several diameter servers and from diameter clients.
65  *
66  *  Optimizes creation, finding and releasing of established client-sessions to a certain number of
67  *  diameter servers through entities.
68  *  Optimizes creation, finding and releasing of established server-sessions from a certain number of
69  *  diameter clients through local servers.
70  *
71  *  Implementation example:
72  *
73  *  \code
74  *
75  *     class MyEngine : public diameter::comm::Engine {
76  *     public:
77  *        MyEngine () {;}
78  *
79  *     private:
80  *        anna::Recycler<MyEntity> a_entities;
81  *
82  *        anna::diameter::comm::Entity* allocateEntity () throw () { return a_entities.create (); }
83  *
84  *        void releaseEntity (anna::diameter::comm::Entity* entity) throw () {
85  *           MyEntity* aux = static_cast <MyEntity*> (entity);
86  *           a_entities.release (aux);
87  *        }
88  *
89  *
90  *        anna::diameter::comm::LocalServer* allocateLocalServer () throw () { return a_localServers.create (); }
91  *
92  *        void releaseLocalServer (anna::diameter::comm::LocalServer* localServer) throw () {
93  *           MyLocalServer* aux = static_cast <MyLocalServer*> (localServer);
94  *           a_localServers.release (aux);
95  *        }
96  *     };
97  *
98  *  \endcode
99  */
100 class Engine : public anna::app::Component {
101 public:
102
103   /**
104      Diameter application node realm name (used to be the site domain name).
105
106      @param name Diameter application node realm name. Used in order to configure the Origin-Realm for outgoing messages.
107      If not configured or empty string provided, host domainname will be set.
108   */
109   void setRealm(const std::string & name) throw();
110
111
112   /**
113      Gets the configured diameter application node realm name.
114
115      @return Diameter application node realm name.
116   */
117   const std::string & getRealm() const throw() { return a_realm; }
118
119
120   /**
121      Diameter application host name as solved by #anna::functions::getHostname()
122
123      @param name Host name. Used in order to configure the Origin-Host for outgoing messages.
124      If not configured or empty string provided, hostname (system name) will be set.
125   */
126   void setHost(const std::string & name) throw();
127
128
129   /**
130      Gets the configured diameter application host name.
131
132      @return Diameter application host name.
133   */
134   const std::string & getHost() const throw() { return a_host; }
135
136
137   /**
138    * Propagate auto recovery configuration to entities within engine. Recovery period is configured at
139    * #anna::comm::Communicator::setRecoveryTime. All the client client-sessions created throught #createEntity,
140    * will be created based on the engine auto-recovery value (enable by default). But you could access entities,
141    * servers or client-sessions independently to change this behaviour.
142    *
143    * @param autoRecovery Auto recovery indicator. True by default.
144    */
145   void raiseAutoRecovery(bool autoRecovery = true) throw(anna::RuntimeException);
146
147   /**
148    * Returns automatic bind indicator for client-sessions. By default \em true will be used.
149    * \return Value for automatic connection bind.
150    */
151   bool getAutoBind() const throw() { return a_autoBind; }
152
153   /**
154    * Sets automatic connection bind indicator for client-sessions. If not asigned, it will be \em true.
155    * \param autoBind Value for automatic connection bind.
156    *
157    * In order to change bind timer, first client-session must be created without autobind, modify time
158    * parameter and then invoking bind.
159    */
160   void setAutoBind(const bool autoBind) throw() { a_autoBind = autoBind; }
161
162   /**
163      Sets the milliseconds wait to achieve a client connection to server by mean connect primitive.
164      This is a general value for born client-sessions over engine. Particular configuration could be done
165      through #ClientSession::setMaxConnectionDelay.
166
167      \param maxConnectionDelay Milliseconds wait to get connection
168   */
169   void setMaxConnectionDelay(const anna::Millisecond & maxConnectionDelay) throw() { a_maxConnectionDelay = maxConnectionDelay; }
170
171   /**
172      Gets the milliseconds wait to achieve a client connection to server by mean connect primitive.
173      Returns the global engine value, but it could be overwritten through each client session (#ClientSession::setMaxConnectionDelay).
174      Default value is 'anna::comm::ClientSocket::DefaultMaxConnectionDelay'.
175
176      \return Milliseconds wait to get connection
177   */
178   const anna::Millisecond & getMaxConnectionDelay() throw() { return a_maxConnectionDelay; }
179
180   /**
181    * Binds engine entities.
182    *
183    * @return Returns true if all client-session were successfully bound
184    */
185   bool bind() throw(anna::RuntimeException);
186
187   /**
188    * Sets CER and DWR diameter messages to be used over created client-sessions.
189    * Its recommended to set this global configuration although it is possible to configure each client-session separately.
190    *
191    * @param cer Capabilities-Exchange-Request message (encoded) for the client-sessions bind.
192    * @param dwr Device-Watchdog-Request message (encoded) for the client-sessions keep-alive.
193    */
194   void setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException);
195
196   /**
197    * 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.
198    * Its recommended to set this global configuration although it is possible to configure each client-session separately.
199    *
200    * @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.
201    * @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.
202    */
203   void setClientCERandDWR(const std::string & cer = "", const std::string & dwr = "") throw(anna::RuntimeException);
204
205   /**
206    * Sets the watchdog period (DWR) for client-sessions.
207    * Its recommended to set this global configuration although it is possible to configure each client-session separately.
208    *
209    * @param wp Watchdog period.
210    */
211   void setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException);
212
213   /**
214    * Gets the number of client-sessions per server.
215    * \return numberOfClientSessionsPerServer Number of client-sessions per server.
216    */
217   int getNumberOfClientSessionsPerServer() const throw() { return a_numberOfClientSessionsPerServer; }
218
219   /**
220    * Sets the number of client-sessions per server.
221    * Its recommended to set this global configuration although it is possible to configure each client-session separately.
222    * \param numberOfClientSessionsPerServer Number of client-sessions per server.
223    */
224   void setNumberOfClientSessionsPerServer(int numberOfClientSessionsPerServer) throw() { a_numberOfClientSessionsPerServer = numberOfClientSessionsPerServer; }
225
226
227   /**
228    * Returns client-session instance identified by (address, port, socketId) provided.
229    *
230    * \param addr Diameter server address (ip or hostname).
231    * \param port Diameter server port.
232    * @param socketId Diameter server socket id.
233    * \param emode Action when no client-session is found with provided parameters (Throw/Ignore).
234    *
235    * \return The client-session instance identified by (address, port, socketId) provided.
236    *
237    * \warning If no client-session found, an exception is launched by default.
238    */
239   ClientSession* findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException);
240
241
242   /**
243    * Same as #findClientSession, but providing client session key (<address>:<port>|<socket id>)
244    */
245   ClientSession* findClientSession(const std::string & key, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException);
246
247
248   /**
249    * Returns server instance identified by pair (address, port) provided.
250    *
251    * \param addr Diameter server address (ip or hostname).
252    * \param port Diameter server port.
253    * \param emode Action when no client-session is found with provided parameters (Throw/Ignore).
254    *
255    * \return The server instance identified by pair (address, port) provided.
256    *
257    * \warning If no server found, an exception is launched by default.
258    */
259   Server* findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException);
260
261   /**
262    * Returns entity instance identified by internal index.
263    *
264    * \param socketList Diameter entity servers list.
265    * \param emode Action when no client-session is found with provided parameters (Throw/Ignore).
266    *
267    * \return The entity instance identified by id provided.
268    *
269    * \warning If no entity found, an exception is launched by default.
270    */
271   Entity* findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException);
272
273   /**
274    * Returns entity instance identified by internal index.
275    *
276    * \param addr1 Diameter primary server address (ip or hostname).
277    * \param port1 Diameter primary server port.
278    * \param addr2 Diameter secondary server address (ip or hostname).
279    * \param port2 Diameter secondary server port.
280    * \param emode Action when no client-session is found with provided parameters (Throw/Ignore).
281    *
282    * \return The entity instance identified by id provided.
283    *
284    * \warning If no entity found, an exception is launched by default.
285    */
286   Entity* findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException);
287
288   /**
289    * Creates a diameter entity with provided parameters.
290    *
291    * Depending on auto-bind configuration, capabilities exchange request will be or won't be performed over the entity client-sessions.
292    *
293    * \param socketList Diameter server priority list (priority-ordered) in order to define whole entity.
294    * @param description Optional entity description (empty by default)
295    *
296    * \return The entity created or exception when any server (address/port) already exists for another entity.
297    *
298    * \warning The entity won't be almost operative until a notification by mean 'ClientSession::eventResponse'
299    * indicates that 'ClassCode::Bind' has been correctly performed for any included client-session.
300    */
301   Entity* createEntity(const socket_v & socketList, const std::string & description = "")
302   throw(anna::RuntimeException);
303
304   /**
305    * Creates a standard (dual) diameter entity with provided parameters.
306    *
307    * Depending on auto-bind configuration, capabilities exchange request will be or won't be performed over the entity client-sessions.
308    *
309    * \param addr1 Diameter primary server address (ip or hostname).
310    * \param port1 Diameter primary server port.
311    * \param addr2 Diameter secondary server address (ip or hostname).
312    * \param port2 Diameter secondary server port.
313    * @param description Optional entity description (empty by default)
314    *
315    * \return The standard entity created or exception when any server (address/port) already exists for another entity.
316    *
317    * \warning The entity won't be almost operative until a notification by mean 'ClientSession::eventResponse'
318    * indicates that 'ClassCode::Bind' has been correctly performed for any included client-session.
319    */
320   Entity* createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string & description = "")
321   throw(anna::RuntimeException);
322
323
324   /**
325    * Returns local server instance identified by pair (address, port) provided.
326    *
327    * @param addr Diameter server socket address (ip or hostname).
328    * @param port Diameter server socket port.
329    * \param emode Action when no local server is found with provided parameters (Throw/Ignore).
330    *
331    * \return The local server instance identified by pair (address, port) provided.
332    *
333    * \warning If no local server found, an exception is launched by default.
334    */
335   LocalServer* findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException);
336
337   /**
338    * Returns server-session instance identified by INetAddress serialization provided.
339    *
340    * @param socketId Hash for Client Socket INetAddress serialization
341    * \param emode Action when no server-session is found with provided parameters (Throw/Ignore).
342    *
343    * \return The server-session instance identified by global unique socketId provided.
344    *
345    * \warning If no server-session found, an exception is launched by default.
346    */
347   ServerSession* findServerSession(int socketId, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException);
348
349   /**
350    * Creates a diameter local server with provided parameters.
351    *
352    * Server socket address could be an IPv4 or hostname. Default port will be standard 3868 for diameter agents,
353    * but any other could be configured. Socket server could be created with any max accepted connections: zero
354    * value means temporarily disabled and negative values assume no limit (shared bind) for incomming connections.
355    *
356    * @param addr Diameter server socket address (ip or hostname).
357    * @param port Diameter server socket port (standard 3868 by default).
358    * @param maxConnections Diameter server max sessions allowed (no limit by default).
359    * @param allowedInactivityTime Max inactivity time for server sessions over the local server before being reset.
360    * @param category Optional socket server category (1 by default).
361    * @param description Optional socket server description (empty by default).
362    *
363    * \return The local server created or exception when is already created.
364    */
365   LocalServer *createLocalServer(const std::string & addr, int port = Session::DefaultPort, int maxConnections = -1, const anna::Millisecond & allowedInactivityTime = ServerSession::DefaultAllowedInactivityTime, int category = 1, const std::string & description = "")
366   throw(anna::RuntimeException);
367
368
369   /**
370      Close all the engine resources (entities and local servers)
371      Optionally all resources may be freed passing true
372
373      @param destroy Free all engine entity resources
374   */
375   void close(bool destroy = false) throw(anna::RuntimeException) { closeEntities(destroy); closeLocalServers(destroy); }
376
377
378   /**
379      Close all the engine entities (close servers, then close client-sessions within them). Depending on client-session configuration
380      ('OnDisconnect' behaviour), pending answers will be wait (graceful) or ignored (immediate-abrupt close).
381      Optionally all entities resources may be freed passing true; in this case, close is immediately performed:
382      @param destroy Free all engine entity resources
383   */
384   void closeEntities(bool destroy = false) throw(anna::RuntimeException);
385
386
387   /**
388    * Close entity servers (then, client-sessions included) and optionally free resources including entity itself.
389    * If entity is null, this operation has no effect.
390    *
391    * \param entity Diameter entity to be closed.
392    * \param destroy Deletes entity over the engine and all its resources.
393    */
394   void closeEntity(Entity* entity, bool destroy = false) throw(anna::RuntimeException);
395
396
397   /**
398      Close all the engine local server sockets including their children server sessions.
399      Optionally all local server resources may be freed passing true.
400
401      @param destroy Free all engine local servers resources and server sessions within them.
402   */
403   void closeLocalServers(bool destroy = false) throw(anna::RuntimeException);
404
405   /**
406    * Close local server socket and its children server sessions.
407    * This is useful when detecting service lost. When service is ready to handle traffic, a new server socket would
408    * be created by mean #LocalServer::enable() and new connections could be accepted.
409    * Optionally local server resources may be freed passing true.
410    *
411    * \param localServer Local server to be closed.
412    * \param destroy Deletes local server over engine and all its resources (server sessions within it).
413    */
414   void closeLocalServer(LocalServer * localServer, bool destroy = false) throw(anna::RuntimeException);
415
416   /**
417      Gets the number of requests messages over-the-air for entities.
418
419      @return OTA messages.
420   */
421   int getOTARequestsForEntities() const throw();
422
423   /**
424      Gets the number of requests messages over-the-air for local servers.
425
426      @return OTA messages.
427   */
428   int getOTARequestsForLocalServers() const throw();
429
430   /**
431      Gets the number of requests messages over-the-air for entities plus local servers.
432
433      @return OTA messages.
434   */
435   int getOTARequests() const throw() { return (getOTARequestsForEntities() + getOTARequestsForLocalServers()); }
436
437   /**
438      Returns idle state (no pending answers) for entities.
439
440      @return Idle state.
441   */
442   bool idleForEntities() const throw() { return (getOTARequestsForEntities() == 0); }
443
444   /**
445      Returns idle state (no pending answers).
446
447      @return Idle state.
448   */
449   bool idleForLocalServers() const throw() { return (getOTARequestsForLocalServers() == 0); }
450
451   /**
452      Returns idle state (no pending answers for entities or local servers).
453
454      @return Idle state.
455   */
456   bool idle() const throw() { return (getOTARequests() == 0); }
457
458   /**
459      Sent a message to all the engine entities.
460      It is used, i.e., in Disconnect-Peer-Request procedure over the engine.
461
462      \param message Message which is being sent.
463
464      @return Returns true (success) only when broadcast is success over all the engine entities. If any entity fails,
465      then false is returned. Broadcast try to send all over the resources in spite of any fail.
466   */
467   bool broadcastEntities(const Message*message) throw(anna::RuntimeException);
468   bool broadcastEntities(const Message& message) throw(anna::RuntimeException) { return broadcastEntities(&message); }
469
470   /**
471      Sent a message through all the engine local servers.
472      It is used, i.e., in Disconnect-Peer-Request procedure over the engine.
473
474      \param message Message which is being sent.
475
476      @return Returns true (success) only when broadcast is success over all the engine local servers. If any local server fails,
477      then false is returned. Broadcast try to send all over the resources in spite of any fail.
478   */
479   bool broadcastLocalServers(const Message*message) throw(anna::RuntimeException);
480   bool broadcastLocalServers(const Message& message) throw(anna::RuntimeException) { return broadcastLocalServers(&message); }
481
482   /**
483   * Class string representation
484   *
485   * @return String with class content
486   */
487   virtual std::string asString(void) const throw();
488
489   /**
490      Class XML representation.
491      \param parent XML node over which we will put instance information.
492      \return XML documentcon with class content.
493   */
494   virtual anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
495
496
497   /**
498      When there is not bound server session over the engine, this virtual method will be invoked.
499      Applications must decide to do any other tasks at this idle/isolated situation.
500      Default implementation do nothing.
501   */
502   virtual void availabilityLostForLocalServers(Engine *) const throw() {;}
503
504   /**
505      When there is any bound server session over the engine, this virtual method will be invoked.
506      Applications must decide to do be ready for incoming traffic.
507      Default implementation do nothing.
508   */
509   virtual void availabilityRecoveredForLocalServers(Engine *) const throw() {;}
510
511   /**
512      When there is not bound entity over the engine, this virtual method will be invoked.
513      Many applications must change communicator status to Unavailable when no engines are available.
514      Default implementation do nothing.
515   */
516   virtual void availabilityLostForEntities(Engine *) const throw() {;}
517
518   /**
519      When there is any bound entity over the engine, this virtual method will be invoked.
520      Many applications must recover communicator status to Available when any engine are available.
521      Default implementation do nothing.
522   */
523   virtual void availabilityRecoveredForEntities(Engine *) const throw() {;}
524
525   /**
526      When there is not bound server-session over the local server, this virtual method will be invoked.
527      Default implementation do nothing.
528   */
529   virtual void availabilityLost(LocalServer *) const throw() {;}
530
531   /**
532      When there is any bound server-session over the local server, this virtual method will be invoked.
533      Default implementation do nothing.
534   */
535   virtual void availabilityRecovered(LocalServer *) const throw() {;}
536
537   /**
538      When there is not bound server over the entity, this virtual method will be invoked.
539      Default implementation do nothing.
540   */
541   virtual void availabilityLost(Entity *) const throw() {;}
542
543   /**
544      When there is any bound server over the entity, this virtual method will be invoked.
545      Default implementation do nothing.
546   */
547   virtual void availabilityRecovered(Entity *) const throw() {;}
548
549   /**
550      When there is not bound client-session over the server, this virtual method will be invoked.
551      Default implementation do nothing.
552   */
553   virtual void availabilityLost(Server *) const throw() {;}
554
555   /**
556      When there is any bound client-session over the server, this virtual method will be invoked.
557      Default implementation do nothing.
558   */
559   virtual void availabilityRecovered(Server *) const throw() {;}
560
561   /**
562      When a subyacent client session is going to be bound, this method is invoked before.
563      Default implementation do nothing.
564   */
565   virtual void bindingClientSession(const ClientSession *) const throw() {;}
566
567   /**
568    * Class user should implement this method in order to define Disconnect-Peer-Answer for last received DPR.
569    * Origin-Host and Origin-Realm are configured at comm::Engine with hostname and FQDN (Fully Qualified Domain Name).
570    * Default implementation imply DPA with DIAMETER_SUCCESS Result-Code, allowing remote disconnection.
571    * Any other implementation is responsible to build a valid DPA diameter message.
572    * DPR/DPA procedure is disabled with empty definition of this method: no DPA will be sent when DPR is received.
573    *
574    * @param dpa DPA datablock passed as reference
575    * @param dpr Corresponding DPR received (sequence values must be taken into account in order to build DPA)
576   */
577   virtual void readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw();
578
579   /**
580    * Class user should implement this method in order to define Capabilities-Exchange-Answer for received CER over server socket.
581    * Origin-Host and Origin-Realm are configured at comm::Engine with hostname and FQDN (Fully Qualified Domain Name).
582    * Default implementation imply CEA with DIAMETER_SUCCESS Result-Code, and own domain node parameters, but application should
583    * analyze the CER message in order to accept it or not (with apropiate non-success Result-Code).
584    * Any other implementation is responsible to build a valid CEA diameter message:
585    *
586    * If one peer sends a CER message to another Peer and receiver does not have support for
587    *
588    *  1) any common application then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_APPLICATION
589    *     and should disconnect the transport layer connection (automatically done by diameter::comm module).
590    *  2) no common security mechanism then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_SECURITY
591    *     and should disconnect the transport layer connection (automatically done by diameter::comm module).
592    *  3) if CER is received from any unknown peer then receiver should discard the message, or send the CEA with the
593    *     Result-Code Avp set to DIAMETER_UNKNOWN_PEER.
594    *
595    *  If the local implementation policy permits to receive CER from unknown hosts, a successful CEA MAY be returned,
596    *  and the life time of the peer entry in PEER-Table is equal to the lifetime of the transport connection.
597    *  If in any case transport connection fails then all the pending transactions destined to the unknown peer can be discarded.
598    *
599    *  The CER and CEA messages MUST NOT be proxied, redirected or relayed. Since CER/CEA messages can not be proxied, but still
600    *  it is possible that proxy will receive a CER message and proxy does not have any peer to handle the application requested
601    *  in CER, in this case proxy set the E bit in CEA and set the Result-Code Avp to DIAMETER_UNABLE_TO_DELIVER, sends back to
602    *  CER generator peer.
603    *
604    * @param cea CEA datablock passed as reference. Empty cea implies to discard CER received.
605    * @param cer Corresponding CER received (sequence values must be taken into account in order to build CEA)
606   */
607   virtual void readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw();
608
609   /**
610    * Class user should implement this method in order to define Device-Watchdog-Answer for received DWR over server socket.
611    * Origin-Host and Origin-Realm are configured at comm::Engine with hostname and FQDN (Fully Qualified Domain Name).
612    * Default implementation imply DWA with DIAMETER_SUCCESS Result-Code, and own domain node parameters.
613    * Any other implementation is responsible to build a valid DWA diameter message.
614    *
615    * @param dwa DWA datablock passed as reference
616    * @param dwr Corresponding DWR received (sequence values must be taken into account in order to build DWA)
617   */
618   virtual void readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw();
619
620   /**
621    * DRA basics: CER information is gathered on every server session managed by the diameter comm engine. You could send the message to a
622    * specific realm, and optionally you could restrict a host inside it. This is common for requests (answers are normally sent through
623    * the same source server session where the request was received). Exception will be thrown if not found an available server session
624    * for the Destination-Realm and/or Destination-Host provided
625    *
626    * @param destinationRealm If empty, NULL is returned, because is nonsense to specify a host out of realm context
627    * @param destinationHost If empty, no restriction is applied within the target realm node. Random delivery is applied for the available server sessions
628    *
629    * @return transactional response reference, or NULL if answer is sent
630    */
631   const Response* sendRealmHost(const Message* message, const std::string &destinationRealm, const std::string &destinationHost = "") throw(anna::RuntimeException);
632
633   /**
634      Reset engine statistics.
635      At the moment, only diameter servers processing time is observed.
636   */
637   void resetStatistics() throw();
638
639
640   /**
641    * Engine lazy initialization. Used if the engine is created when application is already running; for example
642    * on dynamic realms registration. At the moment is not actually needed (nothing is done at initialization),
643    * but it is recommended to start the component and set its state as 'running' from the point of view of the
644    * application.
645    */
646   void lazyInitialize() throw(RuntimeException);
647
648
649 protected:
650   /**
651      Constructor.
652
653      @param className Component class name
654      @param baseProtocolDictionary This will be used internally when calling \@readCEA, \@readDPA and \@readDWA on
655      servers, and also used during base protocol messages tracing (if debug traces are enabled). You could provide
656      NULL, but you must be sure that neither of the former situations are going to happen or an exception will be
657      thrown (using setClientCERandDWR with DataBlock arguments, expects externally encoded messages and could help).
658      It is recommended to set a base protocol dictionary loading 'source/diameter/stack/setups' dictionaries (for
659      example 'avps_ietf.xml' plus 'commands_baseProtocol.xml'), or using the dictionary creation API. The dictionary
660      could also be an application stack, the only condition is containing the resources to build base protocol messages.
661   */
662   Engine(const char *className, const stack::Dictionary *baseProtocolDictionary);
663
664   // INTERNAL CREATORS AND CLOSE METHODS
665   Server *createServer(Entity*, const socket_t&) throw(anna::RuntimeException);
666   void closeServer(Server*, bool) throw(anna::RuntimeException);
667   ClientSession *createClientSession(Server*, int) throw(anna::RuntimeException);
668   void closeClientSession(ClientSession*, bool) throw(anna::RuntimeException);
669
670   // INTERNAL ALLOCATORS
671   Server* allocateServer() throw();
672   void releaseServer(Server*) throw();
673   ClientSession* allocateClientSession() throw();
674   void releaseClientSession(ClientSession*) throw();
675
676
677   /**
678      Entity allocator method.
679
680      It is recommended to use anna::Recycler for entities creation/releasing.
681
682      \see anna::Recycler
683   */
684   virtual Entity* allocateEntity() throw() { return NULL; }
685
686
687   /**
688      Invoked to free entities.
689      \see anna::Recycler
690   */
691   virtual void releaseEntity(Entity*) throw() {;}
692
693
694   /**
695      Local server allocator method.
696
697      It is recommended to use anna::Recycler for entities creation/releasing.
698
699      \see anna::Recycler
700   */
701   virtual LocalServer* allocateLocalServer() throw() { return NULL; }
702
703
704   /**
705      Invoked to free local servers.
706      \see anna::Recycler
707   */
708   virtual void releaseLocalServer(LocalServer*) throw() {;}
709
710
711 private:
712
713   // Internal use: tracing and readCEA/DPA/DWA
714   codec::Engine a_baseProtocolCodecEngine;
715
716   std::string a_realm;
717   std::string a_host;
718   bool a_autoBind;
719   int a_numberOfClientSessionsPerServer;
720
721
722   // ClientSessions messages:
723   anna::DataBlock a_cer;
724   anna::DataBlock a_dwr;
725   anna::Millisecond a_watchdogPeriod;
726
727 //   // ServerSessions messages:
728 //   anna::DataBlock a_cea;
729 //   anna::DataBlock a_dwa;
730
731   // Client connectivity
732   anna::Millisecond a_maxConnectionDelay;
733
734
735   // Availability
736   bool a_availableForEntities; // any of the entities must be bound
737   void availabilityLostForEntities() throw();
738   void availabilityRecoveredForEntities() throw();
739   bool refreshAvailabilityForEntities() throw(); // return true if change
740
741   bool a_availableForLocalServers; // any of the local servers must be bound
742   void availabilityLostForLocalServers() throw();
743   void availabilityRecoveredForLocalServers() throw();
744   bool refreshAvailabilityForLocalServers() throw(); // return true if change
745
746   void eraseDeprecatedIdleEntities() throw();
747
748   // Component:
749   void do_initialize() throw(anna::RuntimeException);
750   void do_stop() throw();
751
752   // Integrity:
753   void checkEntityCollision(const socket_v &) throw(anna::RuntimeException);
754   void assertBaseProtocolHealth() throw(anna::RuntimeException); // checks the dictionary
755
756
757   //  Gets the base protocol codec engine used internally.
758   //  This engine is initializaed on constructor with the base protocol dictionary.
759   //  The reason to not reuse any other codec engine from the application is to have this one isolated with no interference
760   //  regarding configuration changes (validation depth/mode, fix mode, etc.).
761   //
762   //  @return Pointer to the internal base protocol codec engine
763   codec::Engine *getBaseProtocolCodecEngine() const throw() { return const_cast<codec::Engine *>(&a_baseProtocolCodecEngine); }
764
765   //////////////////////////
766   // CLIENT FUNCTIONALITY //
767   //////////////////////////
768
769   //typedef int clientSession_key; // exclusiveHash('ADDR:PORT|id')
770   typedef std::string clientSession_key; // 'ADDR:PORT|id'
771   typedef std::map <clientSession_key, ClientSession*> clientSession_container;
772   typedef clientSession_container::value_type clientSession_value_type;
773   typedef clientSession_container::iterator clientSession_iterator;
774   typedef clientSession_container::const_iterator const_clientSession_iterator;
775   clientSession_container a_clientSessions;
776   anna::Recycler<ClientSession> a_clientSessionsRecycler;
777   clientSession_iterator clientSession_find(const clientSession_key&) throw();
778   clientSession_iterator clientSession_begin() throw() { return a_clientSessions.begin(); }
779   clientSession_iterator clientSession_end() throw() { return a_clientSessions.end(); }
780   static ClientSession* clientSession(clientSession_iterator ii) throw() { return ii->second; }
781   const_clientSession_iterator clientSession_begin() const throw() { return a_clientSessions.begin(); }
782   const_clientSession_iterator clientSession_end() const throw() { return a_clientSessions.end(); }
783   static const ClientSession* clientSession(const_clientSession_iterator ii) throw() { return ii->second; }
784
785   typedef socket_t server_key;
786   server_key getServerKey(const std::string & addr, int port) const throw();
787   typedef std::map <server_key, Server*> server_container;
788   typedef server_container::value_type server_value_type;
789   typedef server_container::iterator server_iterator;
790   typedef server_container::const_iterator const_server_iterator;
791   server_container a_servers;
792   anna::Recycler<Server> a_serversRecycler;
793   server_iterator server_find(const server_key&) throw();
794   server_iterator server_begin() throw() { return a_servers.begin(); }
795   server_iterator server_end() throw() { return a_servers.end(); }
796   static Server* server(server_iterator ii) throw() { return ii->second; }
797   const_server_iterator server_begin() const throw() { return a_servers.begin(); }
798   const_server_iterator server_end() const throw() { return a_servers.end(); }
799   static const Server* server(const_server_iterator ii) throw() { return ii->second; }
800
801   //typedef int entity_key; // exclusiveHash('IP1:PORT1 IP2:PORT2 IP3:PORT3 ...')
802   typedef std::string entity_key; // 'ADDR1:PORT1 ADDR2:PORT2 ADDR3:PORT3 ...'
803   entity_key getEntityKey(const socket_v &) const throw();
804   entity_key getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw();
805   typedef std::map <entity_key, Entity*> entity_container;
806   typedef entity_container::value_type entity_value_type;
807   typedef entity_container::iterator entity_iterator;
808   typedef entity_container::const_iterator const_entity_iterator;
809   entity_container a_entities;
810   entity_iterator entity_find(const entity_key&) throw();
811   entity_iterator entity_begin() throw() { return a_entities.begin(); }
812   entity_iterator entity_end() throw() { return a_entities.end(); }
813   static Entity* entity(entity_iterator ii) throw() { return ii->second; }
814   const_entity_iterator entity_begin() const throw() { return a_entities.begin(); }
815   const_entity_iterator entity_end() const throw() { return a_entities.end(); }
816   static const Entity* entity(const_entity_iterator ii) throw() { return ii->second; }
817
818
819   //////////////////////////
820   // SERVER FUNCTIONALITY //
821   //////////////////////////
822
823   // Local servers
824   typedef std::map <socket_t, LocalServer*> localServer_container;
825   typedef localServer_container::value_type localServer_value_type;
826   typedef localServer_container::iterator localServer_iterator;
827   typedef localServer_container::const_iterator const_localServer_iterator;
828   localServer_container a_localServers;
829   localServer_iterator localServer_find(const socket_t&) throw();
830   localServer_iterator localServer_begin() throw() { return a_localServers.begin(); }
831   localServer_iterator localServer_end() throw() { return a_localServers.end(); }
832   static LocalServer* localServer(localServer_iterator ii) throw() { return ii->second; }
833   const_localServer_iterator localServer_begin() const throw() { return a_localServers.begin(); }
834   const_localServer_iterator localServer_end() const throw() { return a_localServers.end(); }
835   static const LocalServer* localServer(const_localServer_iterator ii) throw() { return ii->second; }
836
837   // Server sessions are managed within LocalServer (not at engine) due to dynamic creation nature
838   // Here we maintain the Destination-Realm / Destination-Host maps for DRA basics:
839   typedef std::vector<ServerSession*> server_sessions_vector_t;
840   typedef server_sessions_vector_t::const_iterator server_sessions_it_t;
841   typedef server_sessions_vector_t::iterator server_sessions_nc_it_t;
842   typedef std::map <std::string /* Destination-Host */, server_sessions_vector_t> dh_server_sessions_map_t;
843   typedef dh_server_sessions_map_t::const_iterator dh_server_sessions_it_t;
844   typedef dh_server_sessions_map_t::iterator dh_server_sessions_nc_it_t;
845   typedef std::map <std::string /* Destination-Realm */, dh_server_sessions_map_t> dr_dh_server_sessions_map_t;
846   typedef dr_dh_server_sessions_map_t::const_iterator dr_dh_server_sessions_it_t;
847   typedef dr_dh_server_sessions_map_t::iterator dr_dh_server_sessions_nc_it_t;
848   dr_dh_server_sessions_map_t a_dr_dh_server_sessions;
849   void manageDrDhServerSession(ServerSession *ss, bool register_or_desregister) throw();
850
851   friend class Session;
852   friend class ClientSession;
853   friend class ServerSession;
854   friend class ServerSocket;
855   friend class Server;
856   friend class Entity;
857   friend class LocalServer;
858   //friend class Message;
859 };
860
861 }
862 }
863 }
864
865 #endif
866