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