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