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>
31 #include <anna/diameter.comm/OriginHostManager.hpp>
32 #include <anna/diameter.comm/OriginHost.hpp>
34 #include <anna/app/functions.hpp>
35 #include <anna/comm/ClientSocket.hpp>
36 #include <anna/core/functions.hpp>
37 #include <anna/core/DataBlock.hpp>
38 #include <anna/core/tracing/Logger.hpp>
39 #include <anna/core/tracing/TraceMethod.hpp>
40 #include <anna/xml/Node.hpp>
41 #include <anna/timex/Engine.hpp>
44 #include <stdlib.h> // rand()
50 using namespace anna::diameter;
51 using namespace anna::diameter::comm;
54 const anna::Millisecond ServerSession::DefaultAllowedInactivityTime(90000); // Inactivity timeout
57 ServerSession::ServerSession() : Session("diameter::comm::ServerSession", "Diameter Inactivity Detection Timer"),
58 a_receiverFactory(this)
61 void ServerSession::initialize() {
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) {
71 a_clientSocket = clientSocket;
72 a_clientSocket->setReceiverFactory(a_receiverFactory);
76 const std::string& ServerSession::getAddress() const {
77 return a_parent->getKey().first;
80 int ServerSession::getPort() const {
81 return a_parent->getKey().second;
84 const Response* ServerSession::send(const Message* message) noexcept(false) {
85 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "send", ANNA_FILE_LOCATION));
88 throw anna::RuntimeException("Cannot send a NULL message", ANNA_FILE_LOCATION);
92 diameter::CommandId cid = message->getCommandId(isRequest);
93 diameter::ApplicationId aid = message->getApplicationId();
96 std::string msg = "Sending diameter message: ";
97 msg += anna::diameter::functions::commandIdAsPairString(cid);
98 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
103 string msg(asString());
104 msg += " | ServerSession is deprecated and will be erased";
105 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
108 if((a_state == State::Closed) && (cid != helpers::base::COMMANDID__Capabilities_Exchange_Answer)) {
109 string msg(asString());
110 msg += " | ServerSession is not bound";
111 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
114 // CER/DWR are not sent from server-side:
115 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) {
116 string msg(asString());
117 msg += " | Trying to send CER: unexpected message from server-side";
118 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
121 if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) {
122 string msg(asString());
123 msg += " | Trying to send DWR: unexpected message from server-side";
124 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
128 /*if (cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) {
129 if (a_state != State::Closed) {
130 string msg(asString());
131 msg += " | Discarding CEA on not closed state";
132 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
135 } else*/ if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) {
136 if(a_state == State::WaitingDPA) {
137 string msg(asString());
138 msg += " | DWA is not sent on 'WaitingDPA' state";
139 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
140 LOGDEBUG(anna::Logger::debug(msg, ANNA_FILE_LOCATION));
144 if(a_state == State::Disconnecting) {
145 string msg(asString());
146 msg += " | DWA is not sent on 'Disconnecting' state";
147 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
148 LOGDEBUG(anna::Logger::debug(msg, ANNA_FILE_LOCATION));
151 } else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) {
152 if(a_state == State::WaitingDPA) {
153 string msg(asString());
154 msg += " | Still waiting for DPR ack (DPA)";
155 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
158 if(a_state == State::Disconnecting) {
159 string msg(asString());
160 msg += " | Server disconnection has already been initiated";
161 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
164 if((a_state == State::WaitingDPA) || (a_state == State::Disconnecting)) {
165 if(cid != helpers::base::COMMANDID__Disconnect_Peer_Answer) {
167 string msg("diameter::comm::ServerSession::send | ");
169 msg += " | Sents (request or answer) blocked to diameter client (disconnection in progress). Discarding ...";
170 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
177 // Trace send operation:
179 string msg("diameter::comm::ServerSession::send | ");
182 msg += message->asString();
183 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
185 bool fixed = false; // answers cannot be fixed
186 Message * message_nc = const_cast<Message*>(message);
190 fixed = message_nc->fixRequestSequence(a_nextHopByHop, a_nextEndToEnd);
191 message_nc->updateRequestTimestampMs(); // statistics purposes (processing time for request type)
196 message->send(*this);
198 // Next hop by hop & end to end identifiers:
199 if(isRequest) generateNextSequences();
202 // The Diameter protocol requires that agents maintain transaction
203 // state, which is used for failover purposes. Transaction state
204 // implies that upon forwarding a request, the Hop-by-Hop identifier
205 // is saved; the field is replaced with a locally unique identifier,
206 // which is restored to its original value when the corresponding
207 // answer is received. The request's state is released upon receipt
208 // of the answer. A stateless agent is one that only maintains
209 // transaction state.
211 updateOutgoingActivityTime();
213 countSendings(cid, aid, true /* send ok */);
215 // Restore sequences:
216 if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix
217 } catch(anna::RuntimeException&) {
218 if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix
221 countSendings(cid, aid, false /* send no ok */);
226 /*if (cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) {
227 setState(State::Bound); // Done at sendCEA if proceed
229 } else */if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) {
230 LOGWARNING(anna::Logger::warning("DPR has been sent to the peer (diameter client)", ANNA_FILE_LOCATION));
231 setState(State::WaitingDPA);
234 // Answers are not temporized:
235 if(!isRequest) return NULL;
237 // Request will have context responses:
238 Response* result(NULL);
239 result = Response::instance(message->getClassCode(), a_nextHopByHop - 1 /* current request sent to client */);
240 result->setRequest(message);
241 response_add(result);
247 bool ServerSession::unbind(bool forceDisconnect) noexcept(false) {
248 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "unbind", ANNA_FILE_LOCATION));
250 if(a_state == State::Closed)
254 anna::comm::ClientSocket * cs = a_clientSocket;
255 //anna::comm::ClientSocket * cs = const_cast<anna::comm::ClientSocket*>(a_clientSocket);
257 if(forceDisconnect) {
258 LOGDEBUG(anna::Logger::debug("Immediate disconnection (forceDisconnect)", ANNA_FILE_LOCATION));
260 if(cs) cs->requestClose(); // this will invoke finalize()
265 // if (a_state == State::Disconnecting) {
267 // string msg("diameter::comm::ServerSession::unbind | ");
268 // msg += asString();
269 // msg += " | Disconnection already in progress !";
270 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
276 // if (a_onDisconnect == OnDisconnect::IgnorePendings) {
277 // LOGDEBUG(anna::Logger::debug("Immediate disconnection (IgnorePendings)", ANNA_FILE_LOCATION));
279 // if (cs) cs->requestClose(); // this will invoke finalize()
284 // if (getOTARequests() == 0) { // No pendings
285 // LOGDEBUG(anna::Logger::debug("No pending answers. Perform client-session close.", ANNA_FILE_LOCATION));
287 // if (cs) cs->requestClose(); // this will invoke finalize()
294 void ServerSession::eventPeerShutdown() {
295 // Inform father server:
296 a_parent->eventPeerShutdown(this);
299 void ServerSession::eventRequestRetransmission(Message *request) {
302 OamModule &oamModule = OamModule::instantiate();
303 oamModule.count(OamModule::Counter::RequestRetransmitted);
304 oamModule.count(OamModule::Counter::RequestRetransmittedOnServerSession);
306 // Inform father server:
307 a_parent->eventRequestRetransmission(this, request);
310 void ServerSession::eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) {
311 // Inform father server:
312 a_parent->eventResponse(response, myNode);
315 void ServerSession::eventRequest(const anna::DataBlock &request, const anna::diameter::comm::OriginHost *myNode) noexcept(false) {
316 // Inform father server:
317 a_parent->eventRequest(this, request, myNode);
320 void ServerSession::eventUnknownResponse(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) {
321 // Inform father server:
322 a_parent->eventUnknownResponse(this, response, myNode);
325 void ServerSession::eventDPA(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) {
326 // Inform father server:
327 a_parent->eventDPA(this, response, myNode);
331 anna::U32 ServerSession::getAuthApplicationIdFromCER(const anna::DataBlock &cer, bool &found) const {
336 anna::diameter::codec::Message codecMsg; // codec engine to pre-assigned, but will be inferred from ApplicationId during decoding:
337 try { codecMsg.decode(cer); } catch(anna::RuntimeException &ex) { ex.trace(); found = false; return result; }
339 // Look at first level:
341 result = codecMsg.getAvp(helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->getValue();
343 catch(anna::RuntimeException &ex) {
347 // Look within Vendor-Specific-Application-Id:
350 result = codecMsg.getAvp(helpers::base::AVPID__Vendor_Specific_Application_Id)->getAvp(helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->getValue();
352 catch(anna::RuntimeException &ex) {
360 //------------------------------------------------------------------------------------------
361 // Se invoca desde el diameter::comm::Receiver
362 //------------------------------------------------------------------------------------------
363 void ServerSession::receive(const anna::comm::Message& message)
365 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "receive", ANNA_FILE_LOCATION));
369 updateIncomingActivityTime();
372 const anna::DataBlock & db = message.getBody();
373 diameter::CommandId cid = codec::functions::getCommandId(db);
374 bool isRequest = cid.second;
376 std::string msg = "Received diameter message: ";
377 msg += anna::diameter::functions::commandIdAsPairString(cid);
378 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
381 OamModule &oamModule = OamModule::instantiate();
382 oamModule.count(isRequest ? OamModule::Counter::RequestReceived : OamModule::Counter::AnswerReceived);
383 oamModule.count(isRequest ? OamModule::Counter::RequestReceivedOnServerSession : OamModule::Counter::AnswerReceivedOnServerSession);
385 a_parent->updateReceivedMessageSizeStatisticConcept(message.getSize(), cid); // only on reception (application could manage sent sizes)
387 // OriginHostManager (to register remote origin host in order to associate with specific comm engine):
388 anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
390 // Extract OriginHost from datablock (db):
391 std::string remoteOriginHost = anna::diameter::helpers::base::functions::getOriginHost(db);
392 LOGDEBUG(anna::Logger::debug(anna::functions::asString("REMOTE ORIGIN HOST FOR THE MESSAGE RECEIVED: %s", remoteOriginHost.c_str()), ANNA_FILE_LOCATION));
394 // Now, get the corresponding own origin host for it; in case of CER received, this will be unkonwn:
395 const anna::diameter::comm::OriginHost *originHost = ohm.getOriginHostForRemoteOriginHost(remoteOriginHost);
398 // Si recibo un request, el message solo tiene fiable el DataBlock. Como por defecto se construye como ApplicationMessage,
399 // el unico caso que no cuadraria seria la recepcion de un CER. Lo que hacemos es NO PROGRESAR NUNCA un CER (*).
400 // El DWR sin embargo, si podriamos progresarlo al ser de aplicacion, pero no les sirve para nada (**).
401 /////////////////////////////
402 // Here received a request //
403 /////////////////////////////
406 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) {
408 // For CERs, we need to extract the Auth-Application-Id:
410 anna::U32 authApplicationId = getAuthApplicationIdFromCER(db, found);
412 // Now, sequential search in OriginHostManager for that id:
413 anna::diameter::comm::OriginHost *originHost = ohm.getOriginHost(authApplicationId);
416 LOGWARNING(anna::Logger::warning("DIAMETER_NO_COMMON_APPLICATION with received CER. TODO: send CEA with that result code", ANNA_FILE_LOCATION));
417 unbind(true /* always immediate */);
421 // Map origin host of received CER, to own OriginHost pointer. This will be used in future: DWR, DPR, normal messages
422 ohm.registerRemoteOriginHost(remoteOriginHost, originHost->getName());
426 oamModule.count(OamModule::Counter::CERReceived);
428 if(a_state == State::Bound) {
429 LOGWARNING(anna::Logger::warning("Received another CER over already bound connection. Anyway, will be replied with CEA", ANNA_FILE_LOCATION));
433 originHost->getCommEngine()->manageDrDhServerSession(this, true /* register */);
435 sendCEA(originHost->getCommEngine(), db);
436 //activateTimer(); // Ya se invoca al inicio de este metodo ::receive
437 //bool changes = a_parent->refreshAvailability();
441 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) {
442 oamModule.count(OamModule::Counter::DWRReceived);
444 if (!originHost) return; // TODO, responding DWA with result code error
446 sendDWA(originHost->getCommEngine(), db);
450 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) {
451 oamModule.count(OamModule::Counter::DPRReceived);
453 if (!originHost) return; // TODO, responding DPA with result code error
455 if(a_state == State::Bound) {
456 setState(State::Disconnecting);
457 LOGWARNING(anna::Logger::warning("DPR has been received from peer (diameter client)", ANNA_FILE_LOCATION));
458 // Ignore pending on server sessions:
459 /*if (getOTARequests() == 0) */sendDPA(originHost->getCommEngine(), db);
460 return; // DPR won't be informed because virtual readDPA is available for this
465 // application message counters
466 ApplicationMessageOamModule::instantiate().count(cid.first, -1 /* no result code */, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Request_Received_AsServer);
468 if (!originHost) return; // TODO, responding DWA with result code error
470 eventRequest(db, originHost);
471 } catch(anna::RuntimeException& ex) {
478 /////////////////////////////
479 // Here received an answer //
480 /////////////////////////////
481 bool doUnbind = false;
485 resultCode = helpers::base::functions::getResultCode(db);
486 } catch(anna::RuntimeException& ex) {
491 if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) {
492 oamModule.count(OamModule::Counter::DPAReceived);
494 if(a_state == State::WaitingDPA) {
495 if(resultCode != helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) {
496 LOGWARNING(anna::Logger::warning("Received DPA with non-success Result-Code. Ignoring and recovering Bound state", ANNA_FILE_LOCATION));
497 setState(State::Bound);
499 LOGWARNING(anna::Logger::warning("Received DPA With Result-Code = DIAMETER_SUCCESS. Disconnect now.", ANNA_FILE_LOCATION));
505 eventDPA(db, originHost);
507 } else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) { // non usual (server should not send DWR's)
508 oamModule.count(OamModule::Counter::DWAReceived);
511 HopByHop hopByHop = codec::functions::getHopByHop(db); // context identification
512 Response* response = response_find(hopByHop);
514 // Out-of-context responses:
517 oamModule.count(OamModule::Counter::AnswerReceivedUnknown);
518 oamModule.count(OamModule::Counter::AnswerReceivedOnServerSessionUnknown);
519 oamModule.activateAlarm(OamModule::Alarm::AnswerReceivedOnServerSessionUnknown);
521 // application message counters
522 ApplicationMessageOamModule::instantiate().count(cid.first, resultCode, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_UnknownReceived_AsServer);
525 eventUnknownResponse(db, originHost);
527 string msg(asString());
528 msg += anna::functions::asString(" | Response received from client, for non registered context (HopByHop: %u)", hopByHop);
529 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
532 response->setResultCode(Response::ResultCode::Success);
533 response->cancelTimer();
535 string msg("diameter::comm::ServerSession::receive | ");
537 msg += " | Received answer";
538 msg += response->asString();
539 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
542 anna::Millisecond current = (anna::Millisecond)anna::functions::millisecond();
543 anna::Millisecond request = response->getRequest()->getRequestTimestampMs();
544 anna::Millisecond timeToAnswerMs = current - request;
545 a_parent->updateProcessingTimeStatisticConcept(timeToAnswerMs, cid);
548 // std::string msg = "This diameter request context lasted ";
549 // msg += anna::functions::asString(timeToAnswerMs);
550 // msg += " milliseconds at diameter client (included network time)";
551 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
553 // Progress origin for tracking purposes on asyncronous boxes with both diameter interfaces (entities and clients)
554 Message * requestMessage = const_cast<Message*>(response->getRequest());
555 requestMessage->setRequestClientSessionKey(response->getRequest()->getRequestClientSessionKey()); // "" means unkown/unset
557 if(cid != helpers::base::COMMANDID__Disconnect_Peer_Answer) {
558 // don't progress DPA: unbind is automatically performed and not open to any application decision
560 response->setMessage(&db);
561 // Restore received datablock
563 string msg("diameter::comm::ClientSession::receive | Restore answer to original request sequences (hop-by-hop = ");
564 msg += anna::functions::asString(response->getRequest()->getRequestHopByHop());
565 msg += ", end-to-end = ";
566 msg += anna::functions::asString(response->getRequest()->getRequestEndToEnd());
568 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
570 diameter::codec::functions::setHopByHop((anna::DataBlock&)db, response->getRequest()->getRequestHopByHop());
571 diameter::codec::functions::setEndToEnd((anna::DataBlock&)db, response->getRequest()->getRequestEndToEnd());
573 // application message counters
574 ApplicationMessageOamModule::instantiate().count(cid.first, resultCode, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_Received_AsServer);
577 eventResponse(*response, originHost);
579 } catch(anna::RuntimeException& ex) {
584 response_erase(response);
588 unbind(true /* always immediate */);
591 void ServerSession::finalize() {
592 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "finalize", ANNA_FILE_LOCATION));
593 // Configuration overiddings
594 setOnDisconnect(OnDisconnect::IgnorePendings);
595 notifyOrphansOnExpiration(false);
596 // session will be idle after 'Session::finalize'
597 // (anyway at 99% of the cases, server session would be idle because is not usual to send request from diameter servers)
598 // Closing state won't be used on server-sessions
599 Session::finalize(); // sets closed state (unbind at closeServerSession won't repeat client socket close, because returns at the beginning)
602 // "delete this" indirecto (seria mas elegante borrar las server sessions deprecated mediante un temporizador de purgado)
604 if(idle()) getParent()->closeServerSession(this); // http://www.parashift.com/c++-faq-lite/delete-this.html
605 } catch(anna::RuntimeException& ex) {
609 // Inform father local server (availability changes):
610 getParent()->refreshAvailability();
612 bool multipleConnections = (getParent()->getMaxConnections() > 1);
613 std::string socket = anna::functions::socketLiteralAsString(getAddress(), getPort());
614 OamModule &oamModule = OamModule::instantiate();
616 if(multipleConnections) {
617 oamModule.activateAlarm(OamModule::Alarm::LostConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__, socket.c_str(), getSocketId());
618 oamModule.count(OamModule::Counter::LostConnectionForServerSession);
620 oamModule.activateAlarm(OamModule::Alarm::LostConnectionForServerSessionAtLocalServer__s__, socket.c_str());
621 oamModule.count(OamModule::Counter::LostConnectionForServerSession);
627 void ServerSession::sendCEA(const Engine *commEngine, const anna::DataBlock &cerDataBlock)
629 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendCEA", ANNA_FILE_LOCATION));
631 anna::DataBlock cea(true);
632 commEngine->readCEA(cea, cerDataBlock); // Asume that CEA is valid ...
633 // If one peer sends a CER message to another Peer and receiver does not have support for
635 // 1) any common application then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_APPLICATION
636 // and should disconnect the transport layer connection (automatically done by diameter::comm module).
637 // 2) no common security mechanism then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_SECURITY
638 // and should disconnect the transport layer connection (automatically done by diameter::comm module).
639 // 3) if CER is received from any unknown peer then receiver should discard the message, or send the CEA with the
640 // Result-Code Avp set to DIAMETER_UNKNOWN_PEER.
643 LOGDEBUG(anna::Logger::debug("Empty CEA message. Remote client never will bound this connection at application level", ANNA_FILE_LOCATION));
644 LOGWARNING(anna::Logger::warning("Discarding received CER: cannot send empty CEA (consider to send CEA with Result-Code DIAMETER_UNKNOWN_PEER)", ANNA_FILE_LOCATION));
651 // Here, CEA has been sent (no exception). Analize CEA Result-Code chosen:
655 resultCode = helpers::base::functions::getResultCode(cea);
656 } catch(anna::RuntimeException& ex) {
661 case helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS:
662 setState(State::Bound);
664 case helpers::base::AVPVALUES__Result_Code::DIAMETER_NO_COMMON_APPLICATION:
665 LOGWARNING(anna::Logger::warning("DIAMETER_NO_COMMON_APPLICATION CEA Result-Code implies unbinding connection", ANNA_FILE_LOCATION));
666 unbind(true /* always immediate */); // no delegamos en un planning o similar
667 // Realmente el cliente diameter tambien deberia cerrar la conexion al recibir este Result-Code
669 case helpers::base::AVPVALUES__Result_Code::DIAMETER_NO_COMMON_SECURITY:
670 LOGWARNING(anna::Logger::warning("DIAMETER_NO_COMMON_SECURITY CEA Result-Code implies unbinding connection", ANNA_FILE_LOCATION));
671 unbind(true /* always immediate */); // no delegamos en un planning o similar
672 // Realmente el cliente diameter tambien deberia cerrar la conexion al recibir este Result-Code
679 void ServerSession::sendDWA(const Engine *commEngine, const anna::DataBlock &dwrDataBlock)
681 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendDWA", ANNA_FILE_LOCATION));
682 anna::DataBlock dwa(true);
683 commEngine->readDWA(dwa, dwrDataBlock); // Asume that DWA is valid ...
686 throw anna::RuntimeException("This diameter agent defines an empty DWA message. Remote client never will validate this connection health", ANNA_FILE_LOCATION);
694 //-------------------------------------------------------------------------
695 // Se invoca desde diameter::comm::Timer
696 //-------------------------------------------------------------------------
697 void ServerSession::expireResponse(diameter::comm::Response* response)
699 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expireResponse", ANNA_FILE_LOCATION));
700 Session::expireResponse(response);
702 OamModule &oamModule = OamModule::instantiate();
703 oamModule.count(OamModule::Counter::RequestSentExpired);
704 oamModule.count(OamModule::Counter::RequestSentOnServerSessionExpired);
705 oamModule.activateAlarm(OamModule::Alarm::RequestSentOnServerSessionExpired);
706 // // "delete this" indirecto (seria mas elegante borrar las server sessions deprecated mediante un temporizador de purgado)
707 // if (idle()) a_parent->eraseServerSession(*a_clientSocket); // http://www.parashift.com/c++-faq-lite/delete-this.html
710 std::string ServerSession::asString() const
712 string result = Session::asString();
713 result += " | Parent Local Server: ";
714 result += anna::functions::socketLiteralAsString(getAddress(), getPort());
715 result += " | Client Socket: ";
716 result += a_clientSocket->asString();
717 // Diferente del timeout de ApplicationMessage:
718 result += " | Allowed inactivity time: ";
719 result += getTimeout().asString();
720 result += " | Deprecated: ";
721 result += (a_deprecated ? "yes" : "no");
722 return result += " }";
725 anna::xml::Node* ServerSession::asXML(anna::xml::Node* parent) const
727 anna::xml::Node* result = Session::asXML(parent);
728 parent->createChild("diameter.comm.ServerSession");
729 result->createAttribute("ParentLocalServer", anna::functions::socketLiteralAsString(getAddress(), getPort()));
730 result->createAttribute("ClientSocket", a_clientSocket->asString());
731 // Diferente del timeout de ApplicationMessage:
732 result->createAttribute("AllowedInactivityTime", getTimeout().asString());
733 result->createAttribute("Deprecated", a_deprecated ? "yes" : "no");
738 //------------------------------------------------------------------------------
739 //------------------------------------------------------ ServerSession::expire()
740 //------------------------------------------------------------------------------
741 void ServerSession::expire(anna::timex::Engine *timeController) noexcept(false) {
742 LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expire (inactivity check timer)", ANNA_FILE_LOCATION));
743 LOGWARNING(anna::Logger::warning("Detecting anomaly (too inactivity time) over server session. Resetting", ANNA_FILE_LOCATION));
745 bool multipleConnections = (getParent()->getMaxConnections() > 1);
746 std::string socket = anna::functions::socketLiteralAsString(getAddress(), getPort());
747 OamModule &oamModule = OamModule::instantiate();
749 if(multipleConnections) {
750 oamModule.activateAlarm(OamModule::Alarm::UnbindConnectionForServerSessionAtLocalServer__s__ServerSessionId__d__DueToInactivityTimeAnomaly, socket.c_str(), getSocketId());
751 oamModule.count(OamModule::Counter::UnbindConnectionForServerSessionDueToInactivityTimeAnomaly);
753 oamModule.activateAlarm(OamModule::Alarm::UnbindConnectionForServerSessionAtLocalServer__s__DueToInactivityTimeAnomaly, socket.c_str());
754 oamModule.count(OamModule::Counter::UnbindConnectionForServerSessionDueToInactivityTimeAnomaly);
757 unbind(true /* always immediate */); // no delegamos en un planning o similar
760 void ServerSession::setAllowedInactivityTime(const anna::Millisecond & allowedInactivityTime) {
761 setTimeout(allowedInactivityTime);
764 //------------------------------------------------------------------------------
765 //---------------------------------- ServerSession::updateIncomingActivityTime()
766 //------------------------------------------------------------------------------
767 void ServerSession::updateIncomingActivityTime() {
768 Session::updateIncomingActivityTime();
769 a_parent->updateIncomingActivityTime();
773 //------------------------------------------------------------------------------
774 //---------------------------------- ServerSession::updateOutgoingActivityTime()
775 //------------------------------------------------------------------------------
776 void ServerSession::updateOutgoingActivityTime(void) {
777 Session::updateOutgoingActivityTime();
778 a_parent->updateOutgoingActivityTime();
782 //------------------------------------------------------------------------------
783 //----------------------------------------------- ServerSession::countSendings()
784 //------------------------------------------------------------------------------
785 void ServerSession::countSendings(const diameter::CommandId & cid, unsigned int aid, bool ok){
786 OamModule &oamModule = OamModule::instantiate();
787 ApplicationMessageOamModule &appMsgOamModule = ApplicationMessageOamModule::instantiate();
789 bool isRequest = cid.second;
793 oamModule.count(isRequest ? OamModule::Counter::RequestSentOK : OamModule::Counter::AnswerSentOK);
794 oamModule.count(isRequest ? OamModule::Counter::RequestSentOnServerSessionOK : OamModule::Counter::AnswerSentOnServerSessionOK);
796 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) oamModule.count(OamModule::Counter::CEASentOK);
797 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentOK);
798 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentOK); // not usual
799 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentOK);
800 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentOK);
801 // Application messages:
803 appMsgOamModule.count(cid.first, -1 /* no result code */, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentOK_AsServer : ApplicationMessageOamModule::Counter::Answer_SentOK_AsServer);
807 oamModule.count(isRequest ? OamModule::Counter::RequestSentNOK : OamModule::Counter::AnswerSentNOK);
808 oamModule.count(isRequest ? OamModule::Counter::RequestSentOnServerSessionNOK : OamModule::Counter::RequestSentOnServerSessionNOK);
810 if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) oamModule.count(OamModule::Counter::CEASentNOK);
811 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentNOK);
812 else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentNOK); // not usual
813 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentNOK);
814 else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentNOK);
815 // Application messages:
817 appMsgOamModule.count(cid.first, -1 /* no result code */, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentNOK_AsServer : ApplicationMessageOamModule::Counter::Answer_SentNOK_AsServer);