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 #include <anna/core/functions.hpp>
38 #include <anna/diameter/defines.hpp>
39 #include <anna/diameter/functions.hpp>
40 #include <anna/diameter/helpers/helpers.hpp>
41 #include <anna/diameter/codec/functions.hpp>
42 #include <anna/diameter/codec/Message.hpp>
43 #include <anna/diameter/helpers/base/functions.hpp>
44 #include <anna/time/functions.hpp>
47 #include <anna/diameter.comm/ServerSession.hpp>
48 #include <anna/diameter.comm/Engine.hpp>
49 #include <anna/diameter.comm/Entity.hpp>
50 #include <anna/diameter.comm/Response.hpp>
51 #include <anna/diameter.comm/Message.hpp>
52 #include <anna/diameter.comm/OamModule.hpp>
53 #include <anna/diameter.comm/TimerManager.hpp>
54 #include <anna/diameter.comm/Timer.hpp>
55 #include <anna/diameter.comm/LocalServer.hpp>
56 #include <anna/diameter.comm/ServerSessionReceiver.hpp>
57 #include <anna/diameter.comm/ReceiverFactoryImpl.hpp>
59 #include <anna/app/functions.hpp>
60 #include <anna/comm/ClientSocket.hpp>
61 #include <anna/core/functions.hpp>
62 #include <anna/core/DataBlock.hpp>
63 #include <anna/core/tracing/Logger.hpp>
64 #include <anna/core/tracing/TraceMethod.hpp>
65 #include <anna/xml/Node.hpp>
66 #include <anna/timex/Engine.hpp>
69 #include <stdlib.h> // rand()
75 using namespace anna::diameter;
76 using namespace anna::diameter::comm;
79 const anna::Millisecond ServerSession::DefaultAllowedInactivityTime(90000); // Inactivity timeout
82 ServerSession::ServerSession() : Session("diameter::comm::ServerSession", "Diameter Inactivity Detection Timer"),
83 a_receiverFactory(this),
84 a_cer(ClassCode::Bind),
85 a_dwr(ClassCode::ApplicationMessage) // realmente no es necesario, los Message son por defecto de aplicacion
88 void ServerSession::initialize() throw() {
89 Session::initialize();
91 a_clientSocket = NULL;
92 a_deprecated = false; // selected for remove (server session was lost due to event break connection)
95 //ServerSession::~ServerSession() {;}
97 void ServerSession::setClientSocket(anna::comm::ClientSocket *clientSocket) throw() {
98 a_clientSocket = clientSocket;
99 a_clientSocket->setReceiverFactory(a_receiverFactory);
103 const std::string& ServerSession::getAddress() const throw() {
104 return a_parent->getKey().first;
107 int ServerSession::getPort() const throw() {
108 return a_parent->getKey().second;
112 const Response* ServerSession::send(const Message* message) throw(anna::RuntimeException) {
113 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "send", ANNA_FILE_LOCATION));
116 throw anna::RuntimeException("Cannot send a NULL message", ANNA_FILE_LOCATION);
120 diameter::CommandId cid = message->getCommandId(isRequest);
122 std::string msg = "Sending diameter message: ";
123 msg += anna::diameter::functions::commandIdAsPairString(cid);
124 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
129 string msg(asString());
130 msg += " | ServerSession is deprecated and will be erased";
131 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
134 if((a_state == State::Closed) && (cid != helpers::base::COMMANDID__Capabilities_Exchange_Answer)) {
135 string msg(asString());
136 msg += " | ServerSession is not bound";
137 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
140 // CER/DWR are not sent from server-side:
141 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) {
142 string msg(asString());
143 msg += " | Trying to send CER: unexpected message from server-side";
144 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
147 if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) {
148 string msg(asString());
149 msg += " | Trying to send DWR: unexpected message from server-side";
150 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
154 /*if (cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) {
155 if (a_state != State::Closed) {
156 string msg(asString());
157 msg += " | Discarding CEA on not closed state";
158 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
161 } else*/ if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) {
162 if(a_state == State::WaitingDPA) {
163 string msg(asString());
164 msg += " | DWA is not sent on 'WaitingDPA' state";
165 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
166 LOGDEBUG(anna::Logger::debug(msg, ANNA_FILE_LOCATION));
170 if(a_state == State::Disconnecting) {
171 string msg(asString());
172 msg += " | DWA is not sent on 'Disconnecting' state";
173 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
174 LOGDEBUG(anna::Logger::debug(msg, ANNA_FILE_LOCATION));
177 } else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) {
178 if(a_state == State::WaitingDPA) {
179 string msg(asString());
180 msg += " | Still waiting for DPR ack (DPA)";
181 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
184 if(a_state == State::Disconnecting) {
185 string msg(asString());
186 msg += " | Server disconnection has already been initiated";
187 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
190 if((a_state == State::WaitingDPA) || (a_state == State::Disconnecting)) {
191 if(cid != helpers::base::COMMANDID__Disconnect_Peer_Answer) {
193 string msg("diameter::comm::ServerSession::send | ");
195 msg += " | Sents (request or answer) blocked to diameter client (disconnection in progress). Discarding ...";
196 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
203 // Trace send operation:
205 string msg("diameter::comm::ServerSession::send | ");
208 msg += message->asString();
209 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
211 bool fixed = false; // answers cannot be fixed
212 Message * message_nc = const_cast<Message*>(message);
216 fixed = message_nc->fixRequestSequence(a_nextHopByHop, a_nextEndToEnd, a_engine->getFreezeEndToEndOnSending());
217 message_nc->updateRequestTimestampMs(); // statistics purposes (processing time for request type)
222 message->send(*this);
224 // Next hop by hop & end to end identifiers:
225 if(isRequest) generateNextSequences();
228 // The Diameter protocol requires that agents maintain transaction
229 // state, which is used for failover purposes. Transaction state
230 // implies that upon forwarding a request, the Hop-by-Hop identifier
231 // is saved; the field is replaced with a locally unique identifier,
232 // which is restored to its original value when the corresponding
233 // answer is received. The request's state is released upon receipt
234 // of the answer. A stateless agent is one that only maintains
235 // transaction state.
237 updateOutgoingActivityTime();
239 countSendings(cid, true /* send ok */);
240 // Trace non-application messages:
243 if((cid == helpers::base::COMMANDID__Device_Watchdog_Request) ||
244 (cid == helpers::base::COMMANDID__Disconnect_Peer_Request)) {
245 anna::Logger::debug("Sent DataBlock to XML representation:", ANNA_FILE_LOCATION);
246 try { anna::diameter::codec::Message msg; msg.decode(message->getBody()); /* decode to be traced */ } catch(anna::RuntimeException&) {;}
250 // Restore sequences:
251 if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix
252 } catch(anna::RuntimeException&) {
253 if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix
256 countSendings(cid, false /* send no ok */);
261 /*if (cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) {
262 setState(State::Bound); // Done at sendCEA if proceed
264 } else */if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) {
265 LOGWARNING(anna::Logger::warning("DPR has been sent to the peer (diameter client)", ANNA_FILE_LOCATION));
266 setState(State::WaitingDPA);
269 // Answers are not temporized:
270 if(!isRequest) return NULL;
272 // Request will have context responses:
273 Response* result(NULL);
274 result = Response::instance(message->getClassCode(), a_nextHopByHop - 1 /* current request sent to client */);
275 result->setRequest(message);
276 response_add(result);
282 bool ServerSession::unbind(bool forceDisconnect) throw(anna::RuntimeException) {
283 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "unbind", ANNA_FILE_LOCATION));
285 if(a_state == State::Closed)
289 anna::comm::ClientSocket * cs = a_clientSocket;
290 //anna::comm::ClientSocket * cs = const_cast<anna::comm::ClientSocket*>(a_clientSocket);
292 if(forceDisconnect) {
293 LOGDEBUG(anna::Logger::debug("Immediate disconnection (forceDisconnect)", ANNA_FILE_LOCATION));
295 if(cs) cs->requestClose(); // this will invoke finalize()
300 // if (a_state == State::Disconnecting) {
302 // string msg("diameter::comm::ServerSession::unbind | ");
303 // msg += asString();
304 // msg += " | Disconnection already in progress !";
305 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
311 // if (a_onDisconnect == OnDisconnect::IgnorePendings) {
312 // LOGDEBUG(anna::Logger::debug("Immediate disconnection (IgnorePendings)", ANNA_FILE_LOCATION));
314 // if (cs) cs->requestClose(); // this will invoke finalize()
319 // if (getOTARequests() == 0) { // No pendings
320 // LOGDEBUG(anna::Logger::debug("No pending answers. Perform client-session close.", ANNA_FILE_LOCATION));
322 // if (cs) cs->requestClose(); // this will invoke finalize()
329 void ServerSession::eventPeerShutdown() throw() {
330 // Inform father server:
331 a_parent->eventPeerShutdown(this);
334 void ServerSession::eventResponse(const Response& response) throw(anna::RuntimeException) {
335 // Inform father server:
336 a_parent->eventResponse(response);
339 void ServerSession::eventRequest(const anna::DataBlock &request) throw(anna::RuntimeException) {
340 // Inform father server:
341 a_parent->eventRequest(this, request);
344 void ServerSession::eventUnknownResponse(const anna::DataBlock& response) throw(anna::RuntimeException) {
345 // Inform father server:
346 a_parent->eventUnknownResponse(this, response);
350 //------------------------------------------------------------------------------------------
351 // Se invoca desde el diameter::comm::Receiver
352 //------------------------------------------------------------------------------------------
353 void ServerSession::receive(const anna::comm::Message& message)
354 throw(anna::RuntimeException) {
355 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "receive", ANNA_FILE_LOCATION));
357 updateIncomingActivityTime();
360 const anna::DataBlock & db = message.getBody();
361 diameter::CommandId cid = codec::functions::getCommandId(db);
362 bool isRequest = cid.second;
364 std::string msg = "Received diameter message: ";
365 msg += anna::diameter::functions::commandIdAsPairString(cid);
366 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
368 if((cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) || (cid.first == helpers::base::COMMANDID__Device_Watchdog_Request.first))
369 try { anna::diameter::codec::Message dmsg; dmsg.decode(db); /* decode to be traced */ } catch(anna::RuntimeException&) {;}
372 OamModule &oamModule = OamModule::instantiate();
373 oamModule.count(isRequest ? OamModule::Counter::RequestReceived : OamModule::Counter::AnswerReceived);
374 oamModule.count(isRequest ? OamModule::Counter::RequestReceivedOnServerSession : OamModule::Counter::AnswerReceivedOnServerSession);
376 a_parent->updateReceivedMessageSizeStatisticConcept(message.getSize()); // only on reception (application could manage sent sizes)
379 // Si recibo un request, el message solo tiene fiable el DataBlock. Como por defecto se construye como ApplicationMessage,
380 // el unico caso que no cuadraria seria la recepcion de un CER. Lo que hacemos es NO PROGRESAR NUNCA un CER (*).
381 // El DWR sin embargo, si podriamos progresarlo al ser de aplicacion, pero no les sirve para nada (**).
382 /////////////////////////////
383 // Here received a request //
384 /////////////////////////////
387 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) {
388 oamModule.count(OamModule::Counter::CERReceived);
390 if(a_state == State::Bound) {
391 LOGWARNING(anna::Logger::warning("Received another CER over already bound connection. Anyway, will be replied with CEA", ANNA_FILE_LOCATION));
396 //activateTimer(); // Ya se invoca al inicio de este metodo ::receive
397 //bool changes = a_parent->refreshAvailability();
401 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) {
402 oamModule.count(OamModule::Counter::DWRReceived);
408 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) {
409 oamModule.count(OamModule::Counter::DPRReceived);
411 if(a_state == State::Bound) {
413 setState(State::Disconnecting);
414 LOGWARNING(anna::Logger::warning("DPR has been received from peer (diameter client)", ANNA_FILE_LOCATION));
415 // Ignore pending on server sessions:
416 /*if (getOTARequests() == 0) */sendDPA();
417 return; // DPR won't be informed because virtual readDPA is available for this
423 } catch(anna::RuntimeException& ex) {
430 /////////////////////////////
431 // Here received an answer //
432 /////////////////////////////
433 bool doUnbind = false;
437 resultCode = helpers::base::functions::getResultCode(db);
438 } catch(anna::RuntimeException& ex) {
443 if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) {
444 oamModule.count(OamModule::Counter::DPAReceived);
446 if(a_state == State::WaitingDPA) {
447 if(resultCode != helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) {
448 LOGWARNING(anna::Logger::warning("Received DPA with non-success Result-Code. Ignoring and recovering Bound state", ANNA_FILE_LOCATION));
449 setState(State::Bound);
451 LOGWARNING(anna::Logger::warning("Received DPA With Result-Code = DIAMETER_SUCCESS. Disconnect now.", ANNA_FILE_LOCATION));
455 } else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) { // non usual (server should not send DWR's)
456 oamModule.count(OamModule::Counter::DWAReceived);
459 HopByHop hopByHop = codec::functions::getHopByHop(db); // context identification
460 Response* response = response_find(hopByHop);
462 // Out-of-context responses:
465 oamModule.count(OamModule::Counter::AnswerReceivedUnknown);
466 oamModule.count(OamModule::Counter::AnswerReceivedOnServerSessionUnknown);
467 oamModule.activateAlarm(OamModule::Alarm::AnswerReceivedOnServerSessionUnknown);
468 eventUnknownResponse(db);
469 string msg(asString());
470 msg += anna::functions::asString(" | Response received from client, for non registered context (HopByHop: %u)", hopByHop);
471 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
474 response->setResultCode(Response::ResultCode::Success);
475 response->cancelTimer();
477 string msg("diameter::comm::ServerSession::receive | ");
479 msg += " | Received answer";
480 msg += response->asString();
481 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
484 anna::Millisecond current = (anna::Millisecond)anna::functions::millisecond();
485 anna::Millisecond request = response->getRequest()->getRequestTimestampMs();
486 anna::Millisecond timeToAnswerMs = current - request;
487 a_parent->updateProcessingTimeStatisticConcept(timeToAnswerMs);
490 std::string msg = "This diameter request context lasted ";
491 msg += anna::functions::asString(timeToAnswerMs);
492 msg += " milliseconds at diameter client (included network time)";
493 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
495 // Progress origin for tracking purposes on asyncronous boxes with both diameter interfaces (entities and clients)
496 Message * requestMessage = const_cast<Message*>(response->getRequest());
497 requestMessage->setRequestClientSessionKey(response->getRequest()->getRequestClientSessionKey()); // "" means unkown/unset
499 if(cid != helpers::base::COMMANDID__Disconnect_Peer_Answer) {
500 // don't progress DPA: unbind is automatically performed and not open to any application decision
502 response->setMessage(&db);
503 // Restore received datablock
505 string msg("diameter::comm::ClientSession::receive | Restore answer to original request sequences (hop-by-hop = ");
506 msg += anna::functions::asString(response->getRequest()->getRequestHopByHop());
507 msg += ", end-to-end = ";
508 msg += anna::functions::asString(response->getRequest()->getRequestEndToEnd());
510 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
512 diameter::codec::functions::setHopByHop((anna::DataBlock&)db, response->getRequest()->getRequestHopByHop());
513 diameter::codec::functions::setEndToEnd((anna::DataBlock&)db, response->getRequest()->getRequestEndToEnd());
514 eventResponse(*response);
515 } catch(anna::RuntimeException& ex) {
520 response_erase(response);
524 unbind(true /* always immediate */);
527 void ServerSession::finalize() throw() {
528 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "finalize", ANNA_FILE_LOCATION));
529 // Configuration overiddings
530 setOnDisconnect(OnDisconnect::IgnorePendings);
531 notifyOrphansOnExpiration(false);
532 // session will be idle after 'Session::finalize'
533 // (anyway at 99% of the cases, server session would be idle because is not usual to send request from diameter servers)
534 // Closing state won't be used on server-sessions
535 Session::finalize(); // sets closed state (unbind at closeServerSession won't repeat client socket close, because returns at the beginning)
538 // "delete this" indirecto (seria mas elegante borrar las server sessions deprecated mediante un temporizador de purgado)
540 if(idle()) getParent()->closeServerSession(this); // http://www.parashift.com/c++-faq-lite/delete-this.html
541 } catch(anna::RuntimeException& ex) {
545 // Inform father local server (availability changes):
546 bool changes = getParent()->refreshAvailability();
548 bool multipleConnections = (getParent()->getMaxConnections() > 1);
549 std::string socket = anna::functions::socketLiteralAsString(getAddress(), getPort());
550 OamModule &oamModule = OamModule::instantiate();
552 if(multipleConnections) {
553 oamModule.activateAlarm(OamModule::Alarm::LostConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__, socket.c_str(), getSocketId());
554 oamModule.count(OamModule::Counter::LostConnectionForServerSession);
556 oamModule.activateAlarm(OamModule::Alarm::LostConnectionForServerSessionAtLocalServer__s__, socket.c_str());
557 oamModule.count(OamModule::Counter::LostConnectionForServerSession);
563 void ServerSession::sendCEA()
564 throw(anna::RuntimeException) {
565 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendCEA", ANNA_FILE_LOCATION));
566 anna::DataBlock cea(true);
567 a_engine->readCEA(cea, a_cer.getBody()); // Asume that CEA is valid ...
568 // If one peer sends a CER message to another Peer and receiver does not have support for
570 // 1) any common application then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_APPLICATION
571 // and should disconnect the transport layer connection (automatically done by diameter::comm module).
572 // 2) no common security mechanism then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_SECURITY
573 // and should disconnect the transport layer connection (automatically done by diameter::comm module).
574 // 3) if CER is received from any unknown peer then receiver should discard the message, or send the CEA with the
575 // Result-Code Avp set to DIAMETER_UNKNOWN_PEER.
578 LOGDEBUG(anna::Logger::debug("Empty CEA message. Remote client never will bound this connection at application level", ANNA_FILE_LOCATION));
579 LOGWARNING(anna::Logger::warning("Discarding received CER without sending CEA (consider to send CEA with Result-Code DIAMETER_UNKNOWN_PEER)", ANNA_FILE_LOCATION));
586 // Here, CEA has been sent (no exception). Analize CEA Result-Code chosen:
590 resultCode = helpers::base::functions::getResultCode(cea);
591 } catch(anna::RuntimeException& ex) {
596 case helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS:
597 setState(State::Bound);
599 case helpers::base::AVPVALUES__Result_Code::DIAMETER_NO_COMMON_APPLICATION:
600 LOGWARNING(anna::Logger::warning("DIAMETER_NO_COMMON_APPLICATION CEA Result-Code implies unbinding connection", ANNA_FILE_LOCATION));
601 unbind(true /* always immediate */); // no delegamos en un planning o similar
602 // Realmente el cliente diameter tambien deberia cerrar la conexion al recibir este Result-Code
604 case helpers::base::AVPVALUES__Result_Code::DIAMETER_NO_COMMON_SECURITY:
605 LOGWARNING(anna::Logger::warning("DIAMETER_NO_COMMON_SECURITY CEA Result-Code implies unbinding connection", ANNA_FILE_LOCATION));
606 unbind(true /* always immediate */); // no delegamos en un planning o similar
607 // Realmente el cliente diameter tambien deberia cerrar la conexion al recibir este Result-Code
614 void ServerSession::sendDWA()
615 throw(anna::RuntimeException) {
616 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendDWA", ANNA_FILE_LOCATION));
617 anna::DataBlock dwa(true);
618 a_engine->readDWA(dwa, a_dwr.getBody()); // Asume that DWA is valid ...
621 throw anna::RuntimeException("This diameter agent defines an empty DWA message. Remote client never will validate this connection health", ANNA_FILE_LOCATION);
629 //-------------------------------------------------------------------------
630 // Se invoca desde diameter::comm::Timer
631 //-------------------------------------------------------------------------
632 void ServerSession::expireResponse(diameter::comm::Response* response)
634 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expireResponse", ANNA_FILE_LOCATION));
635 Session::expireResponse(response);
637 OamModule &oamModule = OamModule::instantiate();
638 oamModule.count(OamModule::Counter::RequestSentExpired);
639 oamModule.count(OamModule::Counter::RequestSentOnServerSessionExpired);
640 oamModule.activateAlarm(OamModule::Alarm::RequestSentOnServerSessionExpired);
641 // // "delete this" indirecto (seria mas elegante borrar las server sessions deprecated mediante un temporizador de purgado)
642 // if (idle()) a_parent->eraseServerSession(*a_clientSocket); // http://www.parashift.com/c++-faq-lite/delete-this.html
645 std::string ServerSession::asString() const
647 string result = Session::asString();
648 result += " | Parent Local Server: ";
649 result += anna::functions::socketLiteralAsString(getAddress(), getPort());
650 result += " | Client Socket: ";
651 result += a_clientSocket->asString();
652 // Diferente del timeout de ApplicationMessage:
653 result += " | Allowed inactivity time: ";
654 result += getTimeout().asString();
655 result += " | Deprecated: ";
656 result += (a_deprecated ? "yes" : "no");
657 return result += " }";
660 anna::xml::Node* ServerSession::asXML(anna::xml::Node* parent) const
662 anna::xml::Node* result = Session::asXML(parent);
663 parent->createChild("diameter.comm.ServerSession");
664 result->createAttribute("ParentLocalServer", anna::functions::socketLiteralAsString(getAddress(), getPort()));
665 result->createAttribute("ClientSocket", a_clientSocket->asString());
666 // Diferente del timeout de ApplicationMessage:
667 result->createAttribute("AllowedInactivityTime", getTimeout().asString());
668 result->createAttribute("Deprecated", a_deprecated ? "yes" : "no");
673 //------------------------------------------------------------------------------
674 //------------------------------------------------------ ServerSession::expire()
675 //------------------------------------------------------------------------------
676 void ServerSession::expire(anna::timex::Engine *timeController) throw(anna::RuntimeException) {
677 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expire (inactivity check timer)", ANNA_FILE_LOCATION));
678 LOGWARNING(anna::Logger::warning("Detecting anomaly (too inactivity time) over server session. Resetting", ANNA_FILE_LOCATION));
680 bool multipleConnections = (getParent()->getMaxConnections() > 1);
681 std::string socket = anna::functions::socketLiteralAsString(getAddress(), getPort());
682 OamModule &oamModule = OamModule::instantiate();
684 if(multipleConnections) {
685 oamModule.activateAlarm(OamModule::Alarm::UnbindConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__DueToInactivityTimeAnomaly, socket.c_str(), getSocketId());
686 oamModule.count(OamModule::Counter::UnbindConnectionForServerSessionDueToInactivityTimeAnomaly);
688 oamModule.activateAlarm(OamModule::Alarm::UnbindConnectionForServerSessionAtLocalServer__s__DueToInactivityTimeAnomaly, socket.c_str());
689 oamModule.count(OamModule::Counter::UnbindConnectionForServerSessionDueToInactivityTimeAnomaly);
692 unbind(true /* always immediate */); // no delegamos en un planning o similar
695 void ServerSession::setAllowedInactivityTime(const anna::Millisecond & allowedInactivityTime) throw() {
696 setTimeout(allowedInactivityTime);
699 //------------------------------------------------------------------------------
700 //---------------------------------- ServerSession::updateIncomingActivityTime()
701 //------------------------------------------------------------------------------
702 void ServerSession::updateIncomingActivityTime() throw() {
703 Session::updateIncomingActivityTime();
704 a_parent->updateIncomingActivityTime();
708 //------------------------------------------------------------------------------
709 //---------------------------------- ServerSession::updateOutgoingActivityTime()
710 //------------------------------------------------------------------------------
711 void ServerSession::updateOutgoingActivityTime(void) throw() {
712 Session::updateOutgoingActivityTime();
713 a_parent->updateOutgoingActivityTime();
717 //------------------------------------------------------------------------------
718 //----------------------------------------------- ServerSession::countSendings()
719 //------------------------------------------------------------------------------
720 void ServerSession::countSendings(const diameter::CommandId & cid, bool ok)throw() {
721 OamModule &oamModule = OamModule::instantiate();
722 bool isRequest = cid.second;
726 oamModule.count(isRequest ? OamModule::Counter::RequestSentOK : OamModule::Counter::AnswerSentOK);
727 oamModule.count(isRequest ? OamModule::Counter::RequestSentOnServerSessionOK : OamModule::Counter::AnswerSentOnServerSessionOK);
729 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) oamModule.count(OamModule::Counter::CEASentOK);
730 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentOK);
731 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentOK); // not usual
732 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentOK);
733 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentOK);
736 oamModule.count(isRequest ? OamModule::Counter::RequestSentNOK : OamModule::Counter::AnswerSentNOK);
737 oamModule.count(isRequest ? OamModule::Counter::RequestSentOnServerSessionNOK : OamModule::Counter::RequestSentOnServerSessionNOK);
739 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) oamModule.count(OamModule::Counter::CEASentNOK);
740 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentNOK);
741 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentNOK); // not usual
742 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentNOK);
743 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentNOK);