Fix local server for multiple applications
[anna.git] / include / anna / diameter.comm / Session.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_Session_hpp
10 #define anna_diameter_comm_Session_hpp
11
12
13 // STL
14 #include <string>
15
16 #include <anna/core/util/SortedVector.hpp>
17 #include <anna/core/util/Millisecond.hpp>
18 #include <anna/core/RuntimeException.hpp>
19 #include <anna/timex/Timer.hpp>
20
21 #include <anna/diameter/defines.hpp>
22 #include <anna/diameter.comm/ClassCode.hpp>
23 #include <anna/diameter.comm/Message.hpp>
24 #include <anna/diameter.comm/Timer.hpp>
25
26
27 namespace anna {
28 class DataBlock;
29 namespace timex {
30 class Engine;
31 }
32 }
33
34
35 namespace anna {
36
37 namespace diameter {
38
39 namespace stack {
40 class Engine;
41 }
42
43 namespace comm {
44
45 class Timer;
46 class Engine;
47 class Response;
48 class OriginHost;
49
50
51
52 /**
53    Modela la conexion realizada contra un servidor diameter.
54 */
55 class Session : public anna::timex::Timer {
56
57 public:
58
59   Session(const char *className, const char *timerName);
60   //virtual ~Session();
61
62   /**
63    * Default timeout for application message requests over the session.
64    */
65   static const anna::Millisecond DefaultTimeout;
66
67   /**
68    * Default diameter port
69    */
70   static const int DefaultPort;
71
72
73
74
75   /**
76      Session states
77      \see diameter::comm::Session::getState
78   */
79   struct State {
80     enum _v {
81       /* client + server */ Closed, /**< Closed */
82       /* client          */ WaitingBind, /**< Connection confirmation pending*/
83       /* client + server */ Bound, /**< Connection done included level application */
84       /* client          */ Failover, /**< Last DWR timed out */
85       /*          server */ Suspect, /**< Inactivity detected on session */
86
87 // .......
88
89
90       // Cierre de iniciativa local:
91       // 1. Envio DPR al PCRF y me pongo en estado 'WaitingDPA'. En este estado no habr� keep-alive DWR/DWA.
92       // 2. No dejo pasar nuevas peticiones (BLOCK-SEND).
93       // 3. Cierro al recibir el DPA.
94       // 4. Si expira el DPA, tambien cierro.
95       WaitingDPA, /**< After requesting DPR to server, send is blocked over the session: when DPA arrives (or answer expires) the session is closed */
96
97       // Cierre de iniciativa remota:
98       // 1. Recibo DPR del PCRF y me pongo en estado 'Disconnecting'. En este estado no habr� keep-alive DWR/DWA.
99       // 2. No dejo pasar nuevas peticiones (BLOCK-SEND).
100       // 3. Espero cursar las peticiones pendientes (a m�s tardar, ser� una expiracion Tx desde la recepcion del DPR).
101       // 4. Envio DPA y activo un temporizador de cierre local (2*Tx) como proteccion (por si el servidor no cierra).
102       Disconnecting, /**< After receiving DPR from server, send is blocked over the session: when no pending requests, DPA is sent to the server who will close connection */
103
104       // Cierre abrupto con/sin espera de pendings:
105       Closing /** Planned local disconnection without DPR; send is blocked over the session. Immediate unbind is used when IgnorePendings behaviour is configured */
106     };
107   };
108
109   /**
110      Session state.
111      \return State for this session.
112   */
113   State::_v getState() const { return a_state; }
114
115   /**
116    * Defines behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers)
117    */
118   struct OnDisconnect { enum _v { IgnorePendings, WaitPendings /* graceful unbind */ }; };
119
120   /**
121    * Sets behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers).
122    * \param onDisconnect Behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers).
123    */
124   void setOnDisconnect(const OnDisconnect::_v onDisconnect)  { a_onDisconnect = onDisconnect; }
125
126   /**
127    * Returns behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers).
128    * \return behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers).
129    */
130   OnDisconnect::_v getOnDisconnect() const { return a_onDisconnect; }
131
132
133
134   /**
135      Diameter server address, ip or hostname (remote for client-session, local for server-session).
136      \return Diameter server address (remote for client-session, local for server-session).
137   */
138   virtual const std::string& getAddress() const  = 0;
139
140   /**
141      Diameter server listen port (remote for client-session, local for server-session).
142      \return Diameter server listen port (remote for client-session, local for server-session).
143   */
144   virtual int getPort() const  = 0;
145
146   /**
147      Socket id.
148      \return Socket id.
149   */
150   int getSocketId() const { return a_socketId; }
151
152   /**
153      Returns the next hop-by-hop which will be used over the diameter session to send a message
154      It is recommended to fix the message with this value (or store along with the message),
155      for application context identification purposes
156   */
157   const HopByHop & getNextHopByHop() const { return a_nextHopByHop; }
158
159   /** Returns the next end-to-end which will be used over the diameter session to send a message
160       It is recommended to fix the message with this value (or store along with the message),
161       for application context identification purposes
162   */
163   const EndToEnd & getNextEndToEnd() const { return a_nextEndToEnd; }
164
165
166   /**
167      Set timeout to consider failed a request.
168      \param v Requests class code.
169      \param millisecond Milliseconds wait before considering the requests failed.
170
171      Timers are internally managed and automatically activated.
172   */
173   void setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) { a_timeouts [v] = millisecond;  }
174
175   /**
176    * Timeout configured for class code \em v requests.
177    * \return Timeout configured for class code \em v requests.
178    */
179   anna::Millisecond getClassCodeTimeout(const ClassCode::_v v) const { return a_timeouts [v]; }
180
181
182   /**
183      Returns \em true when diameter server is connected (application level) \em false in other case.
184      \return \em true when diameter server is connected (application level) \em false in other case.
185   */
186   bool isBound() const { return a_state == State::Bound; }
187
188
189 // Envia el mensaje recibido como parametro al servidor con el que estamos conectados mediante esta
190 // sesion diameter. Dicho mensaje puede ser una peticion o una respuesta (no temporizada).
191 //
192 // En caso de enviar una peticion se activara automaticamente un temporizador. Si este llegara a caducar
193 // se cancelara la busqueda y se invocara al metodo Session::eventResponse indicado que se ha producido
194 // un error de temporizaci�n. La duracion del temporizador sera la establecida por
195 // diameter::comm::TimerManager::setTimeout o el valor defecto.
196 //
197 // \param message Mensaje a enviar al servidor diameter con el que estamos conectados.
198 // @return Diameter response reference asociated to a request. NULL if answer sent.
199 // \warning Solo se podra hacer uso de este metodo cuando el metodo #isBound devuelva \em true.
200   virtual const Response* send(const Message* message) noexcept(false) = 0;
201   const Response* send(const Message& message) noexcept(false) { return send(&message); }
202
203 // Desconecta del extremo remoto
204 // Se notifica la terminaci�n de cada una de las peticiones pendientes invocando al m�todo Session::eventResponse
205 // \warning Despu�s de invocar a este m�todo habr�a que volver a iniciar una sesion.
206   virtual bool unbind(bool forceDisconnect /* se usa en timer, para el actionTimer del tipo SessionUnbind, etc. */ = false) noexcept(false) = 0;
207   // returns true if done at call time (no pendings or ignore pendings, except Disconnecting state by mean DPR/DPA)
208
209
210   /**
211      Gets the timestamp for last incoming activity over the session.
212
213      @return Last incoming activity timestamp.
214   */
215   const anna::Millisecond & getLastIncomingActivityTime() const { return a_lastIncomingActivityTime; }
216
217   /**
218      Gets the timestamp for last outgoing activity over the session.
219
220      @return Last outgoing activity timestamp.
221   */
222   const anna::Millisecond & getLastOutgoingActivityTime() const { return a_lastOutgoingActivityTime; }
223
224   /**
225      Gets the number of requests messages over-the-air.
226
227      @return OTA messages.
228   */
229   int getOTARequests() const { return a_responses.size(); }
230
231
232   /**
233      Returns idle state (no pending answers).
234
235      @return Idle state.
236   */
237   bool idle() const { return (getOTARequests() == 0); }
238
239
240   /**
241      In order to avoid message burst during failover procedures (alternate server forwardings done by application),
242      orphan request notification could be deferred to expiration event. This is the default behaviour, however if
243      need to notice quickly the transport failure for such requets, 'false' should be established. Result code of
244      'OrphanTimeout' will be configured at response instance.
245
246      This only applies to client-sessions because is not usual to send request from server sessions and there wont
247      be impact notifying orphan requests at the moment of the transport failure.
248
249      @defer Delayed notification for orphan request due to transport failures
250   */
251   void notifyOrphansOnExpiration(bool defer = true) { a_notifyOrphansOnExpiration = defer; }
252
253   /**
254      Class string representation
255      \return String with relevant information for this instance.
256   */
257   virtual std::string asString() const ;
258
259
260   /**
261      Class xml representation
262      \param parent Parent XML node on which hold this instance information.
263      \return XML document with relevant information for this instance.
264   */
265   virtual anna::xml::Node* asXML(anna::xml::Node* parent) const ;
266
267 protected:
268
269   // Internal, traces, etc.
270   const char *a_className;
271
272   // Main session attributes
273   int a_socketId; // multiple connection functionality
274   State::_v a_state;
275   OnDisconnect::_v a_onDisconnect;
276   anna::diameter::comm::Timer *a_actionTimer;
277
278   // Sequencing
279   HopByHop a_nextHopByHop;
280   EndToEnd a_nextEndToEnd;
281   virtual void initialize() ;
282   void initializeSequences() ; // debe invocarse despues de haber asignado el a_parent
283   void generateNextSequences() { a_nextHopByHop++; a_nextEndToEnd++; }
284
285   // Context Responses
286   struct SortById {
287     static HopByHop value(const Response*) ;
288   };
289   typedef anna::SortedVector <Response, SortById, HopByHop> response_container;
290   typedef response_container::iterator response_iterator;
291   typedef response_container::const_iterator const_response_iterator;
292   response_container a_responses;
293   bool a_notifyOrphansOnExpiration;
294
295   void response_add(Response* response) ;
296   void response_erase(Response* response) ;
297   Response* response_find(const HopByHop hopByHop) noexcept(false);
298
299   response_iterator response_begin() { return a_responses.begin(); }
300   response_iterator response_end() { return a_responses.end(); }
301   static Response* response(response_iterator ii) { return response_container::data(ii); }
302
303   const_response_iterator response_begin() const { return a_responses.begin(); }
304   const_response_iterator response_end() const { return a_responses.end(); }
305   static const Response* response(const_response_iterator ii) { return response_container::data(ii); }
306
307   // Activity
308   anna::timex::Engine* a_timeController;
309   anna::Millisecond a_lastIncomingActivityTime;   // last unix timestamp (in milliseconds) when message reception was managed over the session
310   anna::Millisecond a_lastOutgoingActivityTime;   // last unix timestamp (in milliseconds) when message sending was managed over the session
311   virtual void updateIncomingActivityTime() ;
312   virtual void updateOutgoingActivityTime() ;
313
314   // Self-timer expiration handler
315   virtual void expire(anna::timex::Engine *timeController) noexcept(false) {;}
316
317   // Timming:
318   anna::Millisecond a_timeouts [ClassCode::Max];
319
320   // Handlers:
321   /**
322      Handler about event break connection over the session.
323
324      When notified, ANNA.diameter.comm generates an diameter::comm::ClientSession::eventResponse for every request with pending answers.
325   */
326   virtual void eventPeerShutdown()  = 0;
327
328   /**
329      Handler about a request retransmission over the session.
330
331      \param request Message retransmitted
332   */
333   virtual void eventRequestRetransmission(Message *request)  = 0;
334
335   /**
336      Handler for diameter session responses
337
338      \param response Answer data block object for corresponding diameter request
339      \param myNode Own origin host
340   */
341   virtual void eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
342
343   /**
344      Handler for diameter session requests
345
346      \param request Request container object for corresponding diameter reception
347      \param myNode Own origin host
348   */
349   virtual void eventRequest(const anna::DataBlock& request, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
350   //void eventRequest(const Message& request) noexcept(false);
351
352
353   /**
354      Handler for diameter session responses out of context
355
356      \param response Answer data block object without context match
357      \param myNode Own origin host
358   */
359   virtual void eventUnknownResponse(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
360
361   /**
362      Handler for diameter session Disconnect-Peer-Answer messages
363
364      \param response Answer data block object without context match
365      \param myNode Own origin host
366   */
367   virtual void eventDPA(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0;
368
369
370
371   /**
372   * Handlers
373   */
374   virtual void receive(const anna::comm::Message& message) noexcept(false) = 0;
375 //PROTOCOL ERRORS
376 //The errors at the protocol level are reported in response messages that contain the �E� bit and the error code in the AVP result-Code (various errors having been produced only the first one of them is reported). Examples of these errors are:
377 //An unrecognized AVP with the �M� bit is received.
378 //An AVP is received with an unrecognized value (in the AVP failed-AVP indicates the attribute that the error caused).
379 //An mandatory AVP is not received.
380 //Length of operation incorrect.
381 //Length of AVP incorrect.
382 //Coding of some AVP incorrect.
383 //Erroneous inclusion of parameters.
384
385
386
387
388
389   virtual void finalize() ; // invoked from ClientSessionReceiver::eventBreakConnection()
390
391
392   virtual void expireResponse(Response*) ;
393   void sendDPA(const Engine *commEngine, const anna::DataBlock &dprDataBlock) noexcept(false);
394   void activateActionTimer(const anna::diameter::comm::Timer::Type::_v type) ;
395   void cancelActionTimer() ;
396   void activateTimer() ; // Session timer
397   void cancelTimer() ; // Session timer
398   virtual void timerStopped() {;}
399   virtual void timerStarted() {;}
400
401
402   virtual void setState(State::_v state) ;
403
404   //anna::diameter::comm::Timer *getActionTimer() const { return (a_actionTimer); }
405
406
407   // helpers
408   static const char* asText(const State::_v) ;
409   static const char* asText(const OnDisconnect::_v) ;
410
411
412   friend class anna::diameter::comm::Timer;
413   friend class Response;
414 };
415
416 }
417 }
418 }
419
420 #endif
421