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 #include <anna/core/functions.hpp>
10 #include <anna/diameter/defines.hpp>
11 #include <anna/diameter/functions.hpp>
12 #include <anna/diameter/helpers/helpers.hpp>
13 #include <anna/diameter/codec/functions.hpp>
14 #include <anna/diameter/codec/Message.hpp>
15 #include <anna/diameter/helpers/base/functions.hpp>
16 #include <anna/time/functions.hpp>
19 #include <anna/diameter.comm/ServerSession.hpp>
20 #include <anna/diameter.comm/Engine.hpp>
21 #include <anna/diameter.comm/Entity.hpp>
22 #include <anna/diameter.comm/Response.hpp>
23 #include <anna/diameter.comm/Message.hpp>
24 #include <anna/diameter.comm/OamModule.hpp>
25 #include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
26 #include <anna/diameter.comm/TimerManager.hpp>
27 #include <anna/diameter.comm/Timer.hpp>
28 #include <anna/diameter.comm/LocalServer.hpp>
29 #include <anna/diameter.comm/ServerSessionReceiver.hpp>
30 #include <anna/diameter.comm/ReceiverFactoryImpl.hpp>
32 #include <anna/app/functions.hpp>
33 #include <anna/comm/ClientSocket.hpp>
34 #include <anna/core/functions.hpp>
35 #include <anna/core/DataBlock.hpp>
36 #include <anna/core/tracing/Logger.hpp>
37 #include <anna/core/tracing/TraceMethod.hpp>
38 #include <anna/xml/Node.hpp>
39 #include <anna/timex/Engine.hpp>
42 #include <stdlib.h> // rand()
48 using namespace anna::diameter;
49 using namespace anna::diameter::comm;
52 const anna::Millisecond ServerSession::DefaultAllowedInactivityTime(90000); // Inactivity timeout
55 ServerSession::ServerSession() : Session("diameter::comm::ServerSession", "Diameter Inactivity Detection Timer"),
56 a_receiverFactory(this),
57 a_cer(ClassCode::Bind),
58 a_dwr(ClassCode::ApplicationMessage) // realmente no es necesario, los Message son por defecto de aplicacion
61 void ServerSession::initialize() throw() {
62 Session::initialize();
64 a_clientSocket = NULL;
65 a_deprecated = false; // selected for remove (server session was lost due to event break connection)
68 //ServerSession::~ServerSession() {;}
70 void ServerSession::setClientSocket(anna::comm::ClientSocket *clientSocket) throw() {
71 a_clientSocket = clientSocket;
72 a_clientSocket->setReceiverFactory(a_receiverFactory);
76 const std::string& ServerSession::getAddress() const throw() {
77 return a_parent->getKey().first;
80 int ServerSession::getPort() const throw() {
81 return a_parent->getKey().second;
85 const Response* ServerSession::send(const Message* message) throw(anna::RuntimeException) {
86 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "send", ANNA_FILE_LOCATION));
89 throw anna::RuntimeException("Cannot send a NULL message", ANNA_FILE_LOCATION);
93 diameter::CommandId cid = message->getCommandId(isRequest);
94 diameter::ApplicationId aid = message->getApplicationId();
97 std::string msg = "Sending diameter message: ";
98 msg += anna::diameter::functions::commandIdAsPairString(cid);
99 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
104 string msg(asString());
105 msg += " | ServerSession is deprecated and will be erased";
106 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
109 if((a_state == State::Closed) && (cid != helpers::base::COMMANDID__Capabilities_Exchange_Answer)) {
110 string msg(asString());
111 msg += " | ServerSession is not bound";
112 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
115 // CER/DWR are not sent from server-side:
116 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) {
117 string msg(asString());
118 msg += " | Trying to send CER: unexpected message from server-side";
119 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
122 if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) {
123 string msg(asString());
124 msg += " | Trying to send DWR: unexpected message from server-side";
125 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
129 /*if (cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) {
130 if (a_state != State::Closed) {
131 string msg(asString());
132 msg += " | Discarding CEA on not closed state";
133 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
136 } else*/ if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) {
137 if(a_state == State::WaitingDPA) {
138 string msg(asString());
139 msg += " | DWA is not sent on 'WaitingDPA' state";
140 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
141 LOGDEBUG(anna::Logger::debug(msg, ANNA_FILE_LOCATION));
145 if(a_state == State::Disconnecting) {
146 string msg(asString());
147 msg += " | DWA is not sent on 'Disconnecting' state";
148 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
149 LOGDEBUG(anna::Logger::debug(msg, ANNA_FILE_LOCATION));
152 } else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) {
153 if(a_state == State::WaitingDPA) {
154 string msg(asString());
155 msg += " | Still waiting for DPR ack (DPA)";
156 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
159 if(a_state == State::Disconnecting) {
160 string msg(asString());
161 msg += " | Server disconnection has already been initiated";
162 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
165 if((a_state == State::WaitingDPA) || (a_state == State::Disconnecting)) {
166 if(cid != helpers::base::COMMANDID__Disconnect_Peer_Answer) {
168 string msg("diameter::comm::ServerSession::send | ");
170 msg += " | Sents (request or answer) blocked to diameter client (disconnection in progress). Discarding ...";
171 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
178 // Trace send operation:
180 string msg("diameter::comm::ServerSession::send | ");
183 msg += message->asString();
184 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
186 bool fixed = false; // answers cannot be fixed
187 Message * message_nc = const_cast<Message*>(message);
191 fixed = message_nc->fixRequestSequence(a_nextHopByHop, a_nextEndToEnd);
192 message_nc->updateRequestTimestampMs(); // statistics purposes (processing time for request type)
197 message->send(*this);
199 // Next hop by hop & end to end identifiers:
200 if(isRequest) generateNextSequences();
203 // The Diameter protocol requires that agents maintain transaction
204 // state, which is used for failover purposes. Transaction state
205 // implies that upon forwarding a request, the Hop-by-Hop identifier
206 // is saved; the field is replaced with a locally unique identifier,
207 // which is restored to its original value when the corresponding
208 // answer is received. The request's state is released upon receipt
209 // of the answer. A stateless agent is one that only maintains
210 // transaction state.
212 updateOutgoingActivityTime();
214 countSendings(cid, aid, true /* send ok */);
215 // Trace non-application messages:
218 if( (cid == helpers::base::COMMANDID__Device_Watchdog_Request) ||
219 (cid == helpers::base::COMMANDID__Disconnect_Peer_Request)) {
220 anna::Logger::debug("Sent DataBlock to XML representation:", ANNA_FILE_LOCATION);
222 anna::diameter::codec::Message msg(a_engine->getBaseProtocolCodecEngine()); msg.decode(message->getBody()); /* decode to be traced */
224 catch(anna::RuntimeException &ex) {
225 std::string msg = ex.getText();
226 msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages full tracing";
227 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
232 // Restore sequences:
233 if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix
234 } catch(anna::RuntimeException&) {
235 if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix
238 countSendings(cid, aid, false /* send no ok */);
243 /*if (cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) {
244 setState(State::Bound); // Done at sendCEA if proceed
246 } else */if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) {
247 LOGWARNING(anna::Logger::warning("DPR has been sent to the peer (diameter client)", ANNA_FILE_LOCATION));
248 setState(State::WaitingDPA);
251 // Answers are not temporized:
252 if(!isRequest) return NULL;
254 // Request will have context responses:
255 Response* result(NULL);
256 result = Response::instance(message->getClassCode(), a_nextHopByHop - 1 /* current request sent to client */);
257 result->setRequest(message);
258 response_add(result);
264 bool ServerSession::unbind(bool forceDisconnect) throw(anna::RuntimeException) {
265 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "unbind", ANNA_FILE_LOCATION));
267 if(a_state == State::Closed)
271 anna::comm::ClientSocket * cs = a_clientSocket;
272 //anna::comm::ClientSocket * cs = const_cast<anna::comm::ClientSocket*>(a_clientSocket);
274 if(forceDisconnect) {
275 LOGDEBUG(anna::Logger::debug("Immediate disconnection (forceDisconnect)", ANNA_FILE_LOCATION));
277 if(cs) cs->requestClose(); // this will invoke finalize()
282 // if (a_state == State::Disconnecting) {
284 // string msg("diameter::comm::ServerSession::unbind | ");
285 // msg += asString();
286 // msg += " | Disconnection already in progress !";
287 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
293 // if (a_onDisconnect == OnDisconnect::IgnorePendings) {
294 // LOGDEBUG(anna::Logger::debug("Immediate disconnection (IgnorePendings)", ANNA_FILE_LOCATION));
296 // if (cs) cs->requestClose(); // this will invoke finalize()
301 // if (getOTARequests() == 0) { // No pendings
302 // LOGDEBUG(anna::Logger::debug("No pending answers. Perform client-session close.", ANNA_FILE_LOCATION));
304 // if (cs) cs->requestClose(); // this will invoke finalize()
311 void ServerSession::eventPeerShutdown() throw() {
312 // Inform father server:
313 a_parent->eventPeerShutdown(this);
316 void ServerSession::eventRequestRetransmission(Message *request) throw() {
319 OamModule &oamModule = OamModule::instantiate();
320 oamModule.count(OamModule::Counter::RequestRetransmitted);
321 oamModule.count(OamModule::Counter::RequestRetransmittedOnServerSession);
323 // Inform father server:
324 a_parent->eventRequestRetransmission(this, request);
327 void ServerSession::eventResponse(const Response& response) throw(anna::RuntimeException) {
328 // Inform father server:
329 a_parent->eventResponse(response);
332 void ServerSession::eventRequest(const anna::DataBlock &request) throw(anna::RuntimeException) {
333 // Inform father server:
334 a_parent->eventRequest(this, request);
337 void ServerSession::eventUnknownResponse(const anna::DataBlock& response) throw(anna::RuntimeException) {
338 // Inform father server:
339 a_parent->eventUnknownResponse(this, response);
342 void ServerSession::eventDPA(const anna::DataBlock& response) throw(anna::RuntimeException) {
343 // Inform father server:
344 a_parent->eventDPA(this, response);
347 //------------------------------------------------------------------------------------------
348 // Se invoca desde el diameter::comm::Receiver
349 //------------------------------------------------------------------------------------------
350 void ServerSession::receive(const anna::comm::Message& message)
351 throw(anna::RuntimeException) {
352 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "receive", ANNA_FILE_LOCATION));
354 updateIncomingActivityTime();
357 const anna::DataBlock & db = message.getBody();
358 diameter::CommandId cid = codec::functions::getCommandId(db);
359 bool isRequest = cid.second;
361 std::string msg = "Received diameter message: ";
362 msg += anna::diameter::functions::commandIdAsPairString(cid);
363 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
365 if( (cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) ||
366 (cid.first == helpers::base::COMMANDID__Device_Watchdog_Request.first)) {
368 anna::diameter::codec::Message dmsg(a_engine->getBaseProtocolCodecEngine()); dmsg.decode(db); /* decode to be traced */
370 catch(anna::RuntimeException &ex) {
371 std::string msg = ex.getText();
372 msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages full tracing";
373 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
378 OamModule &oamModule = OamModule::instantiate();
379 oamModule.count(isRequest ? OamModule::Counter::RequestReceived : OamModule::Counter::AnswerReceived);
380 oamModule.count(isRequest ? OamModule::Counter::RequestReceivedOnServerSession : OamModule::Counter::AnswerReceivedOnServerSession);
382 a_parent->updateReceivedMessageSizeStatisticConcept(message.getSize()); // only on reception (application could manage sent sizes)
385 // Si recibo un request, el message solo tiene fiable el DataBlock. Como por defecto se construye como ApplicationMessage,
386 // el unico caso que no cuadraria seria la recepcion de un CER. Lo que hacemos es NO PROGRESAR NUNCA un CER (*).
387 // El DWR sin embargo, si podriamos progresarlo al ser de aplicacion, pero no les sirve para nada (**).
388 /////////////////////////////
389 // Here received a request //
390 /////////////////////////////
393 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) {
394 oamModule.count(OamModule::Counter::CERReceived);
396 if(a_state == State::Bound) {
397 LOGWARNING(anna::Logger::warning("Received another CER over already bound connection. Anyway, will be replied with CEA", ANNA_FILE_LOCATION));
402 //activateTimer(); // Ya se invoca al inicio de este metodo ::receive
403 //bool changes = a_parent->refreshAvailability();
407 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) {
408 oamModule.count(OamModule::Counter::DWRReceived);
414 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) {
415 oamModule.count(OamModule::Counter::DPRReceived);
417 if(a_state == State::Bound) {
419 setState(State::Disconnecting);
420 LOGWARNING(anna::Logger::warning("DPR has been received from peer (diameter client)", ANNA_FILE_LOCATION));
421 // Ignore pending on server sessions:
422 /*if (getOTARequests() == 0) */sendDPA();
423 return; // DPR won't be informed because virtual readDPA is available for this
428 // application message counters
429 ApplicationMessageOamModule::instantiate().count(cid.first, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Request_Received_AsServer);
432 } catch(anna::RuntimeException& ex) {
439 /////////////////////////////
440 // Here received an answer //
441 /////////////////////////////
442 bool doUnbind = false;
446 resultCode = helpers::base::functions::getResultCode(db);
447 } catch(anna::RuntimeException& ex) {
452 if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) {
453 oamModule.count(OamModule::Counter::DPAReceived);
455 if(a_state == State::WaitingDPA) {
456 if(resultCode != helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) {
457 LOGWARNING(anna::Logger::warning("Received DPA with non-success Result-Code. Ignoring and recovering Bound state", ANNA_FILE_LOCATION));
458 setState(State::Bound);
460 LOGWARNING(anna::Logger::warning("Received DPA With Result-Code = DIAMETER_SUCCESS. Disconnect now.", ANNA_FILE_LOCATION));
467 } else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) { // non usual (server should not send DWR's)
468 oamModule.count(OamModule::Counter::DWAReceived);
471 HopByHop hopByHop = codec::functions::getHopByHop(db); // context identification
472 Response* response = response_find(hopByHop);
474 // Out-of-context responses:
477 oamModule.count(OamModule::Counter::AnswerReceivedUnknown);
478 oamModule.count(OamModule::Counter::AnswerReceivedOnServerSessionUnknown);
479 oamModule.activateAlarm(OamModule::Alarm::AnswerReceivedOnServerSessionUnknown);
481 // application message counters
482 ApplicationMessageOamModule::instantiate().count(cid.first, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_UnknownReceived_AsServer);
484 eventUnknownResponse(db);
486 string msg(asString());
487 msg += anna::functions::asString(" | Response received from client, for non registered context (HopByHop: %u)", hopByHop);
488 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
491 response->setResultCode(Response::ResultCode::Success);
492 response->cancelTimer();
494 string msg("diameter::comm::ServerSession::receive | ");
496 msg += " | Received answer";
497 msg += response->asString();
498 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
501 anna::Millisecond current = (anna::Millisecond)anna::functions::millisecond();
502 anna::Millisecond request = response->getRequest()->getRequestTimestampMs();
503 anna::Millisecond timeToAnswerMs = current - request;
504 a_parent->updateProcessingTimeStatisticConcept(timeToAnswerMs);
507 std::string msg = "This diameter request context lasted ";
508 msg += anna::functions::asString(timeToAnswerMs);
509 msg += " milliseconds at diameter client (included network time)";
510 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
512 // Progress origin for tracking purposes on asyncronous boxes with both diameter interfaces (entities and clients)
513 Message * requestMessage = const_cast<Message*>(response->getRequest());
514 requestMessage->setRequestClientSessionKey(response->getRequest()->getRequestClientSessionKey()); // "" means unkown/unset
516 if(cid != helpers::base::COMMANDID__Disconnect_Peer_Answer) {
517 // don't progress DPA: unbind is automatically performed and not open to any application decision
519 response->setMessage(&db);
520 // Restore received datablock
522 string msg("diameter::comm::ClientSession::receive | Restore answer to original request sequences (hop-by-hop = ");
523 msg += anna::functions::asString(response->getRequest()->getRequestHopByHop());
524 msg += ", end-to-end = ";
525 msg += anna::functions::asString(response->getRequest()->getRequestEndToEnd());
527 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
529 diameter::codec::functions::setHopByHop((anna::DataBlock&)db, response->getRequest()->getRequestHopByHop());
530 diameter::codec::functions::setEndToEnd((anna::DataBlock&)db, response->getRequest()->getRequestEndToEnd());
532 // application message counters
533 ApplicationMessageOamModule::instantiate().count(cid.first, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_Received_AsServer);
535 eventResponse(*response);
537 } catch(anna::RuntimeException& ex) {
542 response_erase(response);
546 unbind(true /* always immediate */);
549 void ServerSession::finalize() throw() {
550 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "finalize", ANNA_FILE_LOCATION));
551 // Configuration overiddings
552 setOnDisconnect(OnDisconnect::IgnorePendings);
553 notifyOrphansOnExpiration(false);
554 // session will be idle after 'Session::finalize'
555 // (anyway at 99% of the cases, server session would be idle because is not usual to send request from diameter servers)
556 // Closing state won't be used on server-sessions
557 Session::finalize(); // sets closed state (unbind at closeServerSession won't repeat client socket close, because returns at the beginning)
560 // "delete this" indirecto (seria mas elegante borrar las server sessions deprecated mediante un temporizador de purgado)
562 if(idle()) getParent()->closeServerSession(this); // http://www.parashift.com/c++-faq-lite/delete-this.html
563 } catch(anna::RuntimeException& ex) {
567 // Inform father local server (availability changes):
568 bool changes = getParent()->refreshAvailability();
570 bool multipleConnections = (getParent()->getMaxConnections() > 1);
571 std::string socket = anna::functions::socketLiteralAsString(getAddress(), getPort());
572 OamModule &oamModule = OamModule::instantiate();
574 if(multipleConnections) {
575 oamModule.activateAlarm(OamModule::Alarm::LostConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__, socket.c_str(), getSocketId());
576 oamModule.count(OamModule::Counter::LostConnectionForServerSession);
578 oamModule.activateAlarm(OamModule::Alarm::LostConnectionForServerSessionAtLocalServer__s__, socket.c_str());
579 oamModule.count(OamModule::Counter::LostConnectionForServerSession);
585 void ServerSession::sendCEA()
586 throw(anna::RuntimeException) {
587 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendCEA", ANNA_FILE_LOCATION));
588 anna::DataBlock cea(true);
589 a_engine->readCEA(cea, a_cer.getBody()); // Asume that CEA is valid ...
590 // If one peer sends a CER message to another Peer and receiver does not have support for
592 // 1) any common application then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_APPLICATION
593 // and should disconnect the transport layer connection (automatically done by diameter::comm module).
594 // 2) no common security mechanism then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_SECURITY
595 // and should disconnect the transport layer connection (automatically done by diameter::comm module).
596 // 3) if CER is received from any unknown peer then receiver should discard the message, or send the CEA with the
597 // Result-Code Avp set to DIAMETER_UNKNOWN_PEER.
600 LOGDEBUG(anna::Logger::debug("Empty CEA message. Remote client never will bound this connection at application level", ANNA_FILE_LOCATION));
601 LOGWARNING(anna::Logger::warning("Discarding received CER: cannot send empty CEA (consider to send CEA with Result-Code DIAMETER_UNKNOWN_PEER)", ANNA_FILE_LOCATION));
608 // Here, CEA has been sent (no exception). Analize CEA Result-Code chosen:
612 resultCode = helpers::base::functions::getResultCode(cea);
613 } catch(anna::RuntimeException& ex) {
618 case helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS:
619 setState(State::Bound);
621 case helpers::base::AVPVALUES__Result_Code::DIAMETER_NO_COMMON_APPLICATION:
622 LOGWARNING(anna::Logger::warning("DIAMETER_NO_COMMON_APPLICATION CEA Result-Code implies unbinding connection", ANNA_FILE_LOCATION));
623 unbind(true /* always immediate */); // no delegamos en un planning o similar
624 // Realmente el cliente diameter tambien deberia cerrar la conexion al recibir este Result-Code
626 case helpers::base::AVPVALUES__Result_Code::DIAMETER_NO_COMMON_SECURITY:
627 LOGWARNING(anna::Logger::warning("DIAMETER_NO_COMMON_SECURITY CEA Result-Code implies unbinding connection", ANNA_FILE_LOCATION));
628 unbind(true /* always immediate */); // no delegamos en un planning o similar
629 // Realmente el cliente diameter tambien deberia cerrar la conexion al recibir este Result-Code
636 void ServerSession::sendDWA()
637 throw(anna::RuntimeException) {
638 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendDWA", ANNA_FILE_LOCATION));
639 anna::DataBlock dwa(true);
640 a_engine->readDWA(dwa, a_dwr.getBody()); // Asume that DWA is valid ...
643 throw anna::RuntimeException("This diameter agent defines an empty DWA message. Remote client never will validate this connection health", ANNA_FILE_LOCATION);
651 //-------------------------------------------------------------------------
652 // Se invoca desde diameter::comm::Timer
653 //-------------------------------------------------------------------------
654 void ServerSession::expireResponse(diameter::comm::Response* response)
656 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expireResponse", ANNA_FILE_LOCATION));
657 Session::expireResponse(response);
659 OamModule &oamModule = OamModule::instantiate();
660 oamModule.count(OamModule::Counter::RequestSentExpired);
661 oamModule.count(OamModule::Counter::RequestSentOnServerSessionExpired);
662 oamModule.activateAlarm(OamModule::Alarm::RequestSentOnServerSessionExpired);
663 // // "delete this" indirecto (seria mas elegante borrar las server sessions deprecated mediante un temporizador de purgado)
664 // if (idle()) a_parent->eraseServerSession(*a_clientSocket); // http://www.parashift.com/c++-faq-lite/delete-this.html
667 std::string ServerSession::asString() const
669 string result = Session::asString();
670 result += " | Parent Local Server: ";
671 result += anna::functions::socketLiteralAsString(getAddress(), getPort());
672 result += " | Client Socket: ";
673 result += a_clientSocket->asString();
674 // Diferente del timeout de ApplicationMessage:
675 result += " | Allowed inactivity time: ";
676 result += getTimeout().asString();
677 result += " | Deprecated: ";
678 result += (a_deprecated ? "yes" : "no");
679 return result += " }";
682 anna::xml::Node* ServerSession::asXML(anna::xml::Node* parent) const
684 anna::xml::Node* result = Session::asXML(parent);
685 parent->createChild("diameter.comm.ServerSession");
686 result->createAttribute("ParentLocalServer", anna::functions::socketLiteralAsString(getAddress(), getPort()));
687 result->createAttribute("ClientSocket", a_clientSocket->asString());
688 // Diferente del timeout de ApplicationMessage:
689 result->createAttribute("AllowedInactivityTime", getTimeout().asString());
690 result->createAttribute("Deprecated", a_deprecated ? "yes" : "no");
695 //------------------------------------------------------------------------------
696 //------------------------------------------------------ ServerSession::expire()
697 //------------------------------------------------------------------------------
698 void ServerSession::expire(anna::timex::Engine *timeController) throw(anna::RuntimeException) {
699 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expire (inactivity check timer)", ANNA_FILE_LOCATION));
700 LOGWARNING(anna::Logger::warning("Detecting anomaly (too inactivity time) over server session. Resetting", ANNA_FILE_LOCATION));
702 bool multipleConnections = (getParent()->getMaxConnections() > 1);
703 std::string socket = anna::functions::socketLiteralAsString(getAddress(), getPort());
704 OamModule &oamModule = OamModule::instantiate();
706 if(multipleConnections) {
707 oamModule.activateAlarm(OamModule::Alarm::UnbindConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__DueToInactivityTimeAnomaly, socket.c_str(), getSocketId());
708 oamModule.count(OamModule::Counter::UnbindConnectionForServerSessionDueToInactivityTimeAnomaly);
710 oamModule.activateAlarm(OamModule::Alarm::UnbindConnectionForServerSessionAtLocalServer__s__DueToInactivityTimeAnomaly, socket.c_str());
711 oamModule.count(OamModule::Counter::UnbindConnectionForServerSessionDueToInactivityTimeAnomaly);
714 unbind(true /* always immediate */); // no delegamos en un planning o similar
717 void ServerSession::setAllowedInactivityTime(const anna::Millisecond & allowedInactivityTime) throw() {
718 setTimeout(allowedInactivityTime);
721 //------------------------------------------------------------------------------
722 //---------------------------------- ServerSession::updateIncomingActivityTime()
723 //------------------------------------------------------------------------------
724 void ServerSession::updateIncomingActivityTime() throw() {
725 Session::updateIncomingActivityTime();
726 a_parent->updateIncomingActivityTime();
730 //------------------------------------------------------------------------------
731 //---------------------------------- ServerSession::updateOutgoingActivityTime()
732 //------------------------------------------------------------------------------
733 void ServerSession::updateOutgoingActivityTime(void) throw() {
734 Session::updateOutgoingActivityTime();
735 a_parent->updateOutgoingActivityTime();
739 //------------------------------------------------------------------------------
740 //----------------------------------------------- ServerSession::countSendings()
741 //------------------------------------------------------------------------------
742 void ServerSession::countSendings(const diameter::CommandId & cid, unsigned int aid, bool ok)throw() {
743 OamModule &oamModule = OamModule::instantiate();
744 ApplicationMessageOamModule &appMsgOamModule = ApplicationMessageOamModule::instantiate();
746 bool isRequest = cid.second;
750 oamModule.count(isRequest ? OamModule::Counter::RequestSentOK : OamModule::Counter::AnswerSentOK);
751 oamModule.count(isRequest ? OamModule::Counter::RequestSentOnServerSessionOK : OamModule::Counter::AnswerSentOnServerSessionOK);
753 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) oamModule.count(OamModule::Counter::CEASentOK);
754 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentOK);
755 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentOK); // not usual
756 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentOK);
757 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentOK);
758 // Application messages:
760 appMsgOamModule.count(cid.first, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentOK_AsServer : ApplicationMessageOamModule::Counter::Answer_SentOK_AsServer);
764 oamModule.count(isRequest ? OamModule::Counter::RequestSentNOK : OamModule::Counter::AnswerSentNOK);
765 oamModule.count(isRequest ? OamModule::Counter::RequestSentOnServerSessionNOK : OamModule::Counter::RequestSentOnServerSessionNOK);
767 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) oamModule.count(OamModule::Counter::CEASentNOK);
768 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentNOK);
769 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentNOK); // not usual
770 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentNOK);
771 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentNOK);
772 // Application messages:
774 appMsgOamModule.count(cid.first, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentNOK_AsServer : ApplicationMessageOamModule::Counter::Answer_SentNOK_AsServer);