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