1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #ifndef anna_diameter_comm_Session_hpp
38 #define anna_diameter_comm_Session_hpp
44 #include <anna/core/util/SortedVector.hpp>
45 #include <anna/core/util/Millisecond.hpp>
46 #include <anna/core/RuntimeException.hpp>
47 #include <anna/timex/Timer.hpp>
49 #include <anna/diameter/defines.hpp>
50 #include <anna/diameter.comm/ClassCode.hpp>
51 #include <anna/diameter.comm/Message.hpp>
52 #include <anna/diameter.comm/Timer.hpp>
80 Modela la conexion realizada contra un servidor diameter.
82 class Session : public anna::timex::Timer {
86 Session(const char *className, const char *timerName);
90 * Default timeout for application message requests over the session.
92 static const anna::Millisecond DefaultTimeout;
95 * Default diameter port
97 static const int DefaultPort;
104 \see diameter::comm::Session::getState
108 /* client + server */ Closed, /**< Closed */
109 /* client */ WaitingBind, /**< Connection confirmation pending*/
110 /* client + server */ Bound, /**< Connection done included level application */
111 /* client */ Failover, /**< Last DWR timed out */
112 /* server */ Suspect, /**< Inactivity detected on session */
117 // Cierre de iniciativa local:
118 // 1. Envio DPR al PCRF y me pongo en estado 'WaitingDPA'. En este estado no habrá keep-alive DWR/DWA.
119 // 2. No dejo pasar nuevas peticiones (BLOCK-SEND).
120 // 3. Cierro al recibir el DPA.
121 // 4. Si expira el DPA, tambien cierro.
122 WaitingDPA, /**< After requesting DPR to server, send is blocked over the session: when DPA arrives (or answer expires) the session is closed */
124 // Cierre de iniciativa remota:
125 // 1. Recibo DPR del PCRF y me pongo en estado 'Disconnecting'. En este estado no habrá keep-alive DWR/DWA.
126 // 2. No dejo pasar nuevas peticiones (BLOCK-SEND).
127 // 3. Espero cursar las peticiones pendientes (a más tardar, será una expiracion Tx desde la recepcion del DPR).
128 // 4. Envio DPA y activo un temporizador de cierre local (2*Tx) como proteccion (por si el servidor no cierra).
129 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 */
131 // Cierre abrupto con/sin espera de pendings:
132 Closing /** Planned local disconnection without DPR; send is blocked over the session. Immediate unbind is used when IgnorePendings behaviour is configured */
138 \return State for this session.
140 State::_v getState() const throw() { return a_state; }
143 * Defines behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers)
145 struct OnDisconnect { enum _v { IgnorePendings, WaitPendings /* graceful unbind */ }; };
148 * Sets behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers).
149 * \param onDisconnect Behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers).
151 void setOnDisconnect(const OnDisconnect::_v onDisconnect) throw() { a_onDisconnect = onDisconnect; }
154 * Returns behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers).
155 * \return behaviour on 'Disconnecting' state, about #unbind action (ignore/wait pending answers).
157 OnDisconnect::_v getOnDisconnect() const throw() { return a_onDisconnect; }
162 Diameter server address, ip or hostname (remote for client-session, local for server-session).
163 \return Diameter server address (remote for client-session, local for server-session).
165 virtual const std::string& getAddress() const throw() = 0;
168 Diameter server listen port (remote for client-session, local for server-session).
169 \return Diameter server listen port (remote for client-session, local for server-session).
171 virtual int getPort() const throw() = 0;
177 int getSocketId() const throw() { return a_socketId; }
180 Returns the next hop-by-hop which will be used over the diameter session to send a message
181 It is recommended to fix the message with this value (or store along with the message),
182 for application context identification purposes
184 const HopByHop & getNextHopByHop() const throw() { return a_nextHopByHop; }
186 /** Returns the next end-to-end which will be used over the diameter session to send a message
187 It is recommended to fix the message with this value (or store along with the message),
188 for application context identification purposes
190 const EndToEnd & getNextEndToEnd() const throw() { return a_nextEndToEnd; }
194 Set timeout to consider failed a request.
195 \param v Requests class code.
196 \param millisecond Milliseconds wait before considering the requests failed.
198 Timers are internally managed and automatically activated.
200 void setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) throw() { a_timeouts [v] = millisecond; }
203 * Timeout configured for class code \em v requests.
204 * \return Timeout configured for class code \em v requests.
206 anna::Millisecond getClassCodeTimeout(const ClassCode::_v v) const throw() { return a_timeouts [v]; }
210 Returns \em true when diameter server is connected (application level) \em false in other case.
211 \return \em true when diameter server is connected (application level) \em false in other case.
213 bool isBound() const throw() { return a_state == State::Bound; }
216 // Envia el mensaje recibido como parametro al servidor con el que estamos conectados mediante esta
217 // sesion diameter. Dicho mensaje puede ser una peticion o una respuesta (no temporizada).
219 // En caso de enviar una peticion se activara automaticamente un temporizador. Si este llegara a caducar
220 // se cancelara la busqueda y se invocara al metodo Session::eventResponse indicado que se ha producido
221 // un error de temporización. La duracion del temporizador sera la establecida por
222 // diameter::comm::TimerManager::setTimeout o el valor defecto.
224 // \param message Mensaje a enviar al servidor diameter con el que estamos conectados.
225 // @return Diameter response reference asociated to a request. NULL if answer sent.
226 // \warning Solo se podra hacer uso de este metodo cuando el metodo #isBound devuelva \em true.
227 virtual const Response* send(const Message* message) throw(anna::RuntimeException) = 0;
228 const Response* send(const Message& message) throw(anna::RuntimeException) { return send(&message); }
230 // Desconecta del extremo remoto
231 // Se notifica la terminación de cada una de las peticiones pendientes invocando al método Session::eventResponse
232 // \warning Después de invocar a este método habría que volver a iniciar una sesion.
233 virtual bool unbind(bool forceDisconnect /* se usa en timer, para el actionTimer del tipo SessionUnbind, etc. */ = false) throw(anna::RuntimeException) = 0;
234 // returns true if done at call time (no pendings or ignore pendings, except Disconnecting state by mean DPR/DPA)
238 Gets the timestamp for last incoming activity over the session.
240 @return Last incoming activity timestamp.
242 const anna::Millisecond & getLastIncomingActivityTime() const throw() { return a_lastIncomingActivityTime; }
245 Gets the timestamp for last outgoing activity over the session.
247 @return Last outgoing activity timestamp.
249 const anna::Millisecond & getLastOutgoingActivityTime() const throw() { return a_lastOutgoingActivityTime; }
252 Gets the number of requests messages over-the-air.
254 @return OTA messages.
256 int getOTARequests() const throw() { return a_responses.size(); }
260 Returns idle state (no pending answers).
264 bool idle() const throw() { return (getOTARequests() == 0); }
268 In order to avoid message burst during failover procedures (alternate server forwardings done by application),
269 orphan request notification could be deferred to expiration event. This is the default behaviour, however if
270 need to notice quickly the transport failure for such requets, 'false' should be established. Result code of
271 'OrphanTimeout' will be configured at response instance.
273 This only applies to client-sessions because is not usual to send request from server sessions and there wont
274 be impact notifying orphan requests at the moment of the transport failure.
276 @defer Delayed notification for orphan request due to transport failures
278 void notifyOrphansOnExpiration(bool defer = true) throw() { a_notifyOrphansOnExpiration = defer; }
281 Class string representation
282 \return String with relevant information for this instance.
284 virtual std::string asString() const throw();
288 Class xml representation
289 \param parent Parent XML node on which hold this instance information.
290 \return XML document with relevant information for this instance.
292 virtual anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
296 // Auxiliary messages:
299 // Internal, traces, etc.
300 const char *a_className;
302 // Main session attributes
303 int a_socketId; // multiple connection functionality
305 OnDisconnect::_v a_onDisconnect;
307 anna::diameter::comm::Timer *a_actionTimer;
310 HopByHop a_nextHopByHop;
311 EndToEnd a_nextEndToEnd;
312 virtual void initialize() throw();
313 void initializeSequences() throw(); // debe invocarse despues de haber asignado el a_parent
314 void generateNextSequences() throw() { a_nextHopByHop++; a_nextEndToEnd++; }
318 static HopByHop value(const Response*) throw();
320 typedef anna::SortedVector <Response, SortById, HopByHop> response_container;
321 typedef response_container::iterator response_iterator;
322 typedef response_container::const_iterator const_response_iterator;
323 response_container a_responses;
324 bool a_notifyOrphansOnExpiration;
326 void response_add(Response* response) throw();
327 void response_erase(Response* response) throw();
328 Response* response_find(const HopByHop hopByHop) throw(anna::RuntimeException);
330 response_iterator response_begin() throw() { return a_responses.begin(); }
331 response_iterator response_end() throw() { return a_responses.end(); }
332 static Response* response(response_iterator ii) throw() { return response_container::data(ii); }
334 const_response_iterator response_begin() const throw() { return a_responses.begin(); }
335 const_response_iterator response_end() const throw() { return a_responses.end(); }
336 static const Response* response(const_response_iterator ii) throw() { return response_container::data(ii); }
339 anna::timex::Engine* a_timeController;
340 anna::Millisecond a_lastIncomingActivityTime; // last unix timestamp (in milliseconds) when message reception was managed over the session
341 anna::Millisecond a_lastOutgoingActivityTime; // last unix timestamp (in milliseconds) when message sending was managed over the session
342 virtual void updateIncomingActivityTime() throw();
343 virtual void updateOutgoingActivityTime() throw();
345 // Self-timer expiration handler
346 virtual void expire(anna::timex::Engine *timeController) throw(anna::RuntimeException) {;}
349 anna::Millisecond a_timeouts [ClassCode::Max];
353 Handler about event break connection over the session.
355 When notified, ANNA.diameter.comm generates an diameter::comm::ClientSession::eventResponse for every request with pending answers.
357 virtual void eventPeerShutdown() throw() = 0;
360 Handler for diameter session responses
362 \param response Answer data block object for corresponding diameter request
364 virtual void eventResponse(const Response& response) throw(anna::RuntimeException) = 0;
367 Handler for diameter session requests
369 \param request Request container object for corresponding diameter reception
371 virtual void eventRequest(const anna::DataBlock& request) throw(anna::RuntimeException) = 0;
372 //void eventRequest(const Message& request) throw(anna::RuntimeException);
376 Handler for diameter session responses out of context
378 \param response Answer data block object without context match
380 virtual void eventUnknownResponse(const anna::DataBlock& response) throw(anna::RuntimeException) = 0;
387 virtual void receive(const anna::comm::Message& message) throw(anna::RuntimeException) = 0;
389 //The errors at the protocol level are reported in response messages that contain the
\93E
\94 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:
390 //An unrecognized AVP with the
\93M
\94 bit is received.
391 //An AVP is received with an unrecognized value (in the AVP failed-AVP indicates the attribute that the error caused).
392 //An mandatory AVP is not received.
393 //Length of operation incorrect.
394 //Length of AVP incorrect.
395 //Coding of some AVP incorrect.
396 //Erroneous inclusion of parameters.
402 virtual void finalize() throw(); // invoked from ClientSessionReceiver::eventBreakConnection()
405 virtual void expireResponse(Response*) throw();
406 void sendDPA() throw(anna::RuntimeException);
407 void activateActionTimer(const anna::diameter::comm::Timer::Type::_v type) throw();
408 void cancelActionTimer() throw();
409 void activateTimer() throw(); // Session timer
410 void cancelTimer() throw(); // Session timer
411 virtual void timerStopped() throw() {;}
412 virtual void timerStarted() throw() {;}
415 virtual void setState(State::_v state) throw();
417 //anna::diameter::comm::Timer *getActionTimer() const { return (a_actionTimer); }
421 static const char* asText(const State::_v) throw();
422 static const char* asText(const OnDisconnect::_v) throw();
425 friend class anna::diameter::comm::Timer;
427 friend class Response;