1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
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 //
9 #ifndef anna_diameter_comm_Session_hpp
10 #define anna_diameter_comm_Session_hpp
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>
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>
52 Modela la conexion realizada contra un servidor diameter.
54 class Session : public anna::timex::Timer {
58 Session(const char *className, const char *timerName);
62 * Default timeout for application message requests over the session.
64 static const anna::Millisecond DefaultTimeout;
67 * Default diameter port
69 static const int DefaultPort;
76 \see diameter::comm::Session::getState
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 */
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 */
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 */
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 */
110 \return State for this session.
112 State::_v getState() const { return a_state; }
115 * Defines behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers)
117 struct OnDisconnect { enum _v { IgnorePendings, WaitPendings /* graceful unbind */ }; };
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).
123 void setOnDisconnect(const OnDisconnect::_v onDisconnect) { a_onDisconnect = onDisconnect; }
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).
129 OnDisconnect::_v getOnDisconnect() const { return a_onDisconnect; }
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).
137 virtual const std::string& getAddress() const = 0;
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).
143 virtual int getPort() const = 0;
149 int getSocketId() const { return a_socketId; }
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
156 const HopByHop & getNextHopByHop() const { return a_nextHopByHop; }
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
162 const EndToEnd & getNextEndToEnd() const { return a_nextEndToEnd; }
166 Set timeout to consider failed a request.
167 \param v Requests class code.
168 \param millisecond Milliseconds wait before considering the requests failed.
170 Timers are internally managed and automatically activated.
172 void setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) { a_timeouts [v] = millisecond; }
175 * Timeout configured for class code \em v requests.
176 * \return Timeout configured for class code \em v requests.
178 anna::Millisecond getClassCodeTimeout(const ClassCode::_v v) const { return a_timeouts [v]; }
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.
185 bool isBound() const { return a_state == State::Bound; }
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).
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.
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); }
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)
210 Gets the timestamp for last incoming activity over the session.
212 @return Last incoming activity timestamp.
214 const anna::Millisecond & getLastIncomingActivityTime() const { return a_lastIncomingActivityTime; }
217 Gets the timestamp for last outgoing activity over the session.
219 @return Last outgoing activity timestamp.
221 const anna::Millisecond & getLastOutgoingActivityTime() const { return a_lastOutgoingActivityTime; }
224 Gets the number of requests messages over-the-air.
226 @return OTA messages.
228 int getOTARequests() const { return a_responses.size(); }
232 Returns idle state (no pending answers).
236 bool idle() const { return (getOTARequests() == 0); }
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.
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.
248 @defer Delayed notification for orphan request due to transport failures
250 void notifyOrphansOnExpiration(bool defer = true) { a_notifyOrphansOnExpiration = defer; }
253 Class string representation
254 \return String with relevant information for this instance.
256 virtual std::string asString() const ;
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.
264 virtual anna::xml::Node* asXML(anna::xml::Node* parent) const ;
268 // Auxiliary messages:
271 // Internal, traces, etc.
272 const char *a_className;
274 // Main session attributes
275 int a_socketId; // multiple connection functionality
277 OnDisconnect::_v a_onDisconnect;
279 anna::diameter::comm::Timer *a_actionTimer;
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++; }
290 static HopByHop value(const Response*) ;
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;
298 void response_add(Response* response) ;
299 void response_erase(Response* response) ;
300 Response* response_find(const HopByHop hopByHop) noexcept(false);
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); }
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); }
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() ;
317 // Self-timer expiration handler
318 virtual void expire(anna::timex::Engine *timeController) noexcept(false) {;}
321 anna::Millisecond a_timeouts [ClassCode::Max];
325 Handler about event break connection over the session.
327 When notified, ANNA.diameter.comm generates an diameter::comm::ClientSession::eventResponse for every request with pending answers.
329 virtual void eventPeerShutdown() = 0;
332 Handler about a request retransmission over the session.
334 \param request Message retransmitted
336 virtual void eventRequestRetransmission(Message *request) = 0;
339 Handler for diameter session responses
341 \param response Answer data block object for corresponding diameter request
343 virtual void eventResponse(const Response& response) noexcept(false) = 0;
346 Handler for diameter session requests
348 \param request Request container object for corresponding diameter reception
350 virtual void eventRequest(const anna::DataBlock& request) noexcept(false) = 0;
351 //void eventRequest(const Message& request) noexcept(false);
355 Handler for diameter session responses out of context
357 \param response Answer data block object without context match
359 virtual void eventUnknownResponse(const anna::DataBlock& response) noexcept(false) = 0;
362 Handler for diameter session Disconnect-Peer-Answer messages
364 \param response Answer data block object without context match
366 virtual void eventDPA(const anna::DataBlock& response) noexcept(false) = 0;
373 virtual void receive(const anna::comm::Message& message) noexcept(false) = 0;
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.
388 virtual void finalize() ; // invoked from ClientSessionReceiver::eventBreakConnection()
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() {;}
401 virtual void setState(State::_v state) ;
403 //anna::diameter::comm::Timer *getActionTimer() const { return (a_actionTimer); }
407 static const char* asText(const State::_v) ;
408 static const char* asText(const OnDisconnect::_v) ;
411 friend class anna::diameter::comm::Timer;
413 friend class Response;