Fix local server for multiple applications
[anna.git] / include / anna / diameter.comm / LocalServer.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_LocalServer_hpp
10 #define anna_diameter_comm_LocalServer_hpp
11
12
13 #include <anna/core/RuntimeException.hpp>
14 #include <anna/core/util/Millisecond.hpp>
15 #include <anna/core/util/Recycler.hpp>
16
17 // STL
18 #include <string>
19 #include <vector>
20 #include <map>
21
22 // Project
23 #include <anna/config/defines.hpp>
24 #include <anna/diameter.comm/ServerSession.hpp>
25 #include <anna/diameter/defines.hpp>
26 #include <anna/diameter.comm/MessageStatistics.hpp>
27
28
29 namespace anna {
30 namespace xml {
31 class Node;
32 }
33 namespace comm {
34 class ClientSocket;
35 //class LocalConnection;
36 }
37 class DataBlock;
38 }
39
40 namespace anna {
41
42 namespace diameter {
43
44 namespace comm {
45
46 class Response;
47 class ServerSocket;
48 class Message;
49 class Engine;
50
51
52 /**
53    Diameter server socket
54 */
55 class LocalServer {
56
57   // main
58   socket_t a_key;
59   std::string a_description;
60   int a_maxConnections;
61   int a_currentConnections; // deberia coincidir en todo momento con el numero de local connections del server socket
62   anna::Millisecond a_allowedInactivityTime;
63   ServerSocket *a_serverSocket;
64   int a_category;
65   bool a_lock;
66
67   // Engine
68   Engine *a_engine; // only for refresh availability
69
70   // Statistics
71   MessageStatistics a_messageStatistics;
72   void initializeStatisticResources() ;
73   void resetStatistics() ;
74
75 //   void eraseServerSession(const anna::comm::ClientSocket& clientSocket) ;
76 //   void eraseServerSession(const serverSession_iterator &it) ;
77   void lostConnection() ;
78   void newConnection() noexcept(false);
79
80   // Activity
81   anna::Millisecond a_lastIncomingActivityTime;   // last unix timestamp (in milliseconds) when message reception was managed over this entity
82   anna::Millisecond a_lastOutgoingActivityTime;   // last unix timestamp (in milliseconds) when message sending was managed over this entity
83   void updateIncomingActivityTime() ;
84   void updateOutgoingActivityTime() ;
85
86   // Availability
87   bool a_available; // any of the server-sessions must be bound
88   void availabilityLost() ;
89   void availabilityRecovered() ;
90   bool refreshAvailability() ; // return true if change
91
92   void attach() ; // attach server socket to the communicator
93   void attachPlanning() ; // used when attach fails (socket already in use, etc.)
94
95   typedef int serverSession_key;
96   serverSession_key getServerSessionKey(const anna::comm::ClientSocket&) const ; // hash for Client Socket INetAddress serialization
97   typedef std::map <serverSession_key, ServerSession*> serverSession_container;
98   typedef serverSession_container::value_type serverSession_value_type;
99   typedef serverSession_container::iterator serverSession_iterator;
100   typedef serverSession_container::const_iterator const_serverSession_iterator;
101   serverSession_container a_serverSessions;
102   anna::Recycler<ServerSession> a_serverSessionsRecycler;
103   serverSession_iterator serverSession_find(const serverSession_key&) ;
104   serverSession_iterator serverSession_begin() { return a_serverSessions.begin(); }
105   serverSession_iterator serverSession_end() { return a_serverSessions.end(); }
106   static ServerSession* serverSession(serverSession_iterator ii) { return ii->second; }
107   const_serverSession_iterator serverSession_begin() const { return a_serverSessions.begin(); }
108   const_serverSession_iterator serverSession_end() const { return a_serverSessions.end(); }
109   static const ServerSession* serverSession(const_serverSession_iterator ii) { return ii->second; }
110
111   // INTERNAL CREATORS AND CLOSE METHODS
112   ServerSession *createServerSession(const anna::comm::ClientSocket&) noexcept(false);
113   void closeServerSession(ServerSession*) noexcept(false);
114
115   // INTERNAL ALLOCATORS
116   ServerSession* allocateServerSession() ;
117   void releaseServerSession(ServerSession*) ;
118
119   // Auxiliary
120   serverSession_iterator a_deliveryIterator;
121   ServerSession *a_lastUsedResource;
122
123 public:
124
125   /** Constructor */
126   LocalServer();
127
128   /** Destructor */
129   ~LocalServer() { close(); }
130
131
132   // setters
133
134   /**
135   * Sets the local server key
136   * @param LocalServer key
137   */
138   void setKey(const socket_t &key) { a_key = key; }
139
140   /**
141      Sets the server socket optional description
142
143      @param description Server socket description
144   */
145   void setDescription(const std::string description) { a_description = description; }
146
147   /**
148      Set timeout to consider failed a request.
149      \param v Requests class code.
150      \param millisecond Milliseconds wait before considering the requests failed.
151
152      Timers are internally managed and automatically activated.
153   */
154   void setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) ;
155
156   /**
157      Sets the server socket optional category
158
159      @param description Server socket category
160   */
161   void setCategory(int category) { a_category = category; }
162
163   /**
164      Sets the maximum supported connections.
165      If provided value is negative or lesser than the number of current connections, an exception will be launched.
166      If all the connections was established, a new maximum will open the listen port.
167      when margin is zeroed (maximum configured is equal to current connections), listen port will be closed.
168
169      @param maxConnections Number of maximum connections allowed
170   */
171   void setMaxConnections(int maxConnections) noexcept(false);
172
173   /**
174      Sets the maximum allowed inactivity time on server sessions born over the local server before being reset.
175      Communication engine assign a default value of 90000 msecs.
176
177      @param allowedInactivityTime Inactivity time allowed
178   */
179   void setAllowedInactivityTime(const anna::Millisecond & allowedInactivityTime) { a_allowedInactivityTime = allowedInactivityTime; }
180
181   /**
182   * Sets the diameter::comm::Engine
183   * @param e Diameter::comm::Engine
184   */
185   void setEngine(Engine *e) { a_engine = e; }
186
187   // getters
188
189   /**
190   * Gets the local server key
191   * @return LocalServer key
192   */
193   const socket_t & getKey() const { return a_key; }
194
195   /**
196      Gets the number of maximum accepted connections that server socket is configured to handle
197   */
198   int getMaxConnections() const { return a_maxConnections; }
199
200   /**
201      Gets the number of current connections being established through server socket
202   */
203   int getCurrentConnections() const { return a_currentConnections; }
204
205   /**
206      Gets the maximum allowed inactivity time on server sessions born over the local server before being reset
207
208      @return Inactivity time allowed
209   */
210   const anna::Millisecond & getAllowedInactivityTime() const { return a_allowedInactivityTime; }
211
212   /**
213      Returns true when any of the server-sessions is Bound. False when all not-bound.
214   */
215   bool isAvailable() const { return a_available; }
216
217   // helpers
218
219   /**
220      Disables local server socket (listener) keeping current server sessions alive.
221      Note that applications should not close the listen port directly to keep coherence (see #resetConnectionsMargin)
222
223      @param lock Locks disabled state (make it permanent even if new connections margin is reached).
224      Used during diameter agent isolation (lost of service, maintenance, etc.)
225   */
226   void disable(bool lock = false) noexcept(false);
227
228   /** Enables local server socket (listener)
229
230      @param unlock Unlocks permanent disabled states
231   */
232   void enable(bool unlock = false) noexcept(false);
233
234   /**
235      Gets the number of requests messages over-the-air.
236
237      @return OTA messages.
238   */
239   int getOTARequests() const ;
240
241   /**
242      Returns idle state (no pending answers).
243
244      @return Idle state.
245   */
246   bool idle() const { return (getOTARequests() == 0); }
247
248   /**
249      Close the local server means two things: close the server socket and close all the server sessions born
250      from this local server freeing such server sessions resources.
251   */
252   void close() noexcept(false);
253
254   /**
255      Performs coherent server socket close procedure zeroing margin between current established connections and maximum allowed.
256   */
257   void resetConnectionsMargin() noexcept(false) { setMaxConnections(a_currentConnections); }
258
259
260   /**
261    * Returns server-session instance identified by client socket provided.
262    *
263    * \param clientSocket Client socket associated to the server session
264    * \param emode Action when no client-session is found with provided parameters (Throw/Ignore).
265    *
266    * \return The server-session instance identified by client socket provided.
267    *
268    * \warning If no server-session found, an exception is launched by default.
269    */
270   ServerSession* findServerSession(const anna::comm::ClientSocket &clientSocket, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) noexcept(false);
271
272   /**
273    * Returns server-session instance identified by socket id provided (hash over serialized client socket information).
274    *
275    * \param socketId Socket id which is key for the server session
276    * \param emode Action when no client-session is found with provided parameters (Throw/Ignore).
277    *
278    * \return The server-session instance identified by client socket provided.
279    *
280    * \warning If no server-session found, an exception is launched by default.
281    */
282   ServerSession* findServerSession(int socketId, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) noexcept(false);
283
284
285   /**
286      Sent a message to the client using a certain server-session provided or defined by #readSocketId if not.
287      When the message is a request, a timer will be set automatically to control the response time.
288      If expires, the ResultCode Timeout will be finally notified on #LocalServer::eventResponse. This
289      timeout value will be configured at #setClassCodeTimeout.
290
291      \param message Message sent.
292      \param socketId Server session socket id INetAddress serialization. By default, #readSocketId is invoked to get the socket id used (which uses round-robin if not re-implemented)
293
294      @return Boolean about success in send operation. True when any of the server sessions could send the message.
295      False, when neither of the server sessions was available or fail to send the message. Broadcast try to send all over
296      the resources in spite of any fail. If a specific socket id is provided, only this socket is used without trying any other
297      and returning false if fails.
298   */
299   bool send(const Message*, int socketId = -1 /* default uses readSocketId() */) noexcept(false);
300   bool send(const Message& message, int socketId = -1 /* default uses readSocketId() */) noexcept(false) { return send(&message, socketId); }
301
302   /**
303      Gets the last used resource (server session) during sending.
304      Broadcast doesn't updates this information.
305   */
306   ServerSession *getLastUsedResource() const { return (a_lastUsedResource); }
307
308   /**
309      Before sending a message over each local server, socketId could be specified to select
310      which session within such server will manage the message.
311
312      Default implementation performs round-robin (value '-1' for socketId) but any other kind of
313      application could re-implement this method and change the behaviour.
314
315      \param message Message which is being sent.
316
317      @return Socket-id (hash over serialized client socket information). Value '-1' if round-robin is desired.
318      If socket-id is unkonwn, send procedure will throw an exception.
319   */
320   virtual int readSocketId(const Message *message) const { return -1; }
321
322   /**
323      Sent a message to all the server sessions.
324      It is used, i.e., in Disconnect-Peer-Request procedure over a certain entity.
325
326      \param message Message which is being sent.
327
328      @return Returns true (success) only when broadcast is success over all the entity servers. If any server fails,
329      then false is returned.
330   */
331   bool broadcast(const Message *message) noexcept(false);
332   bool broadcast(const Message &message) noexcept(false) { return broadcast(&message); }
333
334
335   /**
336      Class string representation
337      \return String with relevant information for this instance.
338   */
339   std::string asString() const ;
340
341   /**
342      Class xml representation
343      \param parent Parent XML node on which hold this instance information.
344      \return XML document with relevant information for this instance.
345   */
346   anna::xml::Node* asXML(anna::xml::Node* parent) const ;
347
348   // Statistics
349   void updateProcessingTimeStatisticConcept(const double &value, const anna::diameter::CommandId &cid) ;
350   void updateReceivedMessageSizeStatisticConcept(const double &value, const anna::diameter::CommandId &cid) ;
351 //  int getProcessingTimeStatisticConcept() const { return a_processing_time__StatisticConceptId; }
352 //  int getReceivedMessageSizeStatisticConcept() const { return a_received_message_size__StatisticConceptId; }
353
354 protected:
355
356   // Handlers:
357   /**
358      Handler about event break connection from diameter client over this server-session.
359      When notified, ANNA.diameter.comm generates an diameter::comm::ServerSession::eventResponse for every request with pending answers.
360      Default implementation traces warning event
361      \param serverSession ServerSession from which shutdown has been received
362   */
363   virtual void eventPeerShutdown(const ServerSession* serverSession) ;
364
365   /**
366      Handler about a request retransmission over the server-session.
367      Default implementation traces warning event
368      \param serverSession ServerSession from which retransmission happened
369      \param request Retransmitted request message
370   */
371   virtual void eventRequestRetransmission(const ServerSession* serverSession, Message *request) ;
372
373   /**
374      Handler for diameter client responses
375
376      \param response Answer container object for corresponding diameter request
377      \param myNode Own origin host
378   */
379   virtual void eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
380
381   /**
382      Handler for diameter client requests
383
384      \param serverSession ServerSession from which request has been received
385      \param request Request data block object for corresponding diameter reception
386      \param myNode Own origin host
387   */
388   virtual void eventRequest(ServerSession* serverSession, const anna::DataBlock& request, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
389   //void eventRequest(ServerSession* serverSession, const Message& request) noexcept(false);
390
391   /**
392      Handler for diameter client responses out of context
393
394      \param serverSession ServerSession from which request has been received
395      \param response Answer data block object without context match
396      \param myNode Own origin host
397   */
398   virtual void eventUnknownResponse(ServerSession* serverSession, const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
399
400   /**
401      Handler for diameter client Disconnect-Peer-Answer messages
402
403      \param serverSession ServerSession from which request has been received
404      \param response Answer data block object without context match
405      \param myNode Own origin host
406   */
407   virtual void eventDPA(ServerSession* serverSession, const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
408
409
410   friend class anna::diameter::comm::Timer;
411   friend class Engine;
412   friend class ServerSocket;
413   friend class ServerSession;
414   friend class ServerSessionReceiver;
415 };
416
417 }
418 }
419 }
420
421 #endif