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 //
10 #include <anna/core/core.hpp>
11 #include <anna/diameter/functions.hpp>
12 #include <anna/time/functions.hpp>
13 #include <anna/diameter.comm/Response.hpp>
14 #include <anna/diameter/helpers/base/functions.hpp>
15 #include <anna/diameter/helpers/dcca/functions.hpp>
18 #include "MyDiameterEntity.hpp"
19 #include "Launcher.hpp"
22 void MyDiameterEntity::eventRequestRetransmission(const anna::diameter::comm::ClientSession* clientSession, anna::diameter::comm::Message *request) throw() {
24 LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventRequestRetransmission", ANNA_FILE_LOCATION));
27 Entity::eventRequestRetransmission(clientSession, request); // warning trace
30 Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
31 CommandLine& cl(anna::CommandLine::instantiate());
33 anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(request->getBody());
36 std::string msg = "Request retransmitted: ";
37 msg += anna::diameter::functions::commandIdAsPairString(cid);
38 msg += " | DiameterServer: ";
39 msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort());
40 msg += " | EventTime: ";
41 msg += anna::time::functions::currentTimeAsString();
42 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
45 // Write retransmission
46 if(my_app.logEnabled()) my_app.writeLogFile(request->getBody(), "retry", clientSession->asString(), a_codecEngine);
50 int MyDiameterEntity::readSocketId(const anna::diameter::comm::Message* message, int maxClientSessions) const throw() {
51 CommandLine& cl(anna::CommandLine::instantiate());
52 std::string sessionBasedModelsType = (cl.exists("sessionBasedModelsClientSocketSelection") ? cl.getValue("sessionBasedModelsClientSocketSelection") : "SessionIdLowPart");
54 if(sessionBasedModelsType == "RoundRobin") return -1; // IEC also would return -1
57 // Service-Context-Id:
58 anna::diameter::helpers::dcca::ChargingContext::_v chargingContext;
59 std::string scid = anna::diameter::helpers::dcca::functions::getServiceContextId(message->getBody(), chargingContext);
61 switch(chargingContext) {
62 case anna::diameter::helpers::dcca::ChargingContext::Data:
63 case anna::diameter::helpers::dcca::ChargingContext::Voice:
64 case anna::diameter::helpers::dcca::ChargingContext::Content: {
65 // Session-Id: '<DiameterIdentity>;<high 32 bits>;<low 32 bits>[;<optional value>="">]'
66 std::string sid = anna::diameter::helpers::base::functions::getSessionId(message->getBody());
67 std::string diameterIdentity, optional;
69 anna::diameter::helpers::base::functions::decodeSessionId(sid, diameterIdentity, high, low /* context-teid */, optional);
71 if(sessionBasedModelsType == "SessionIdLowPart") return (low % maxClientSessions);
73 if(sessionBasedModelsType == "SessionIdHighPart") return (high % maxClientSessions);
75 if(sessionBasedModelsType == "SessionIdOptionalPart") return (atoi(optional.c_str()) % maxClientSessions);
77 case anna::diameter::helpers::dcca::ChargingContext::SMS:
78 case anna::diameter::helpers::dcca::ChargingContext::MMS:
79 case anna::diameter::helpers::dcca::ChargingContext::Unknown:
81 return -1; // IEC model and Unknown traffic types
83 } catch(anna::RuntimeException &ex) {
85 std::string msg = ex.getText();
86 msg += " | Round-robin between sessions will be used to send";
87 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
94 void MyDiameterEntity::eventRequest(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message)
95 throw(anna::RuntimeException) {
96 LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventRequest", ANNA_FILE_LOCATION));
98 Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
99 CommandLine& cl(anna::CommandLine::instantiate());
101 anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message);
104 std::string msg = "Request received: ";
105 msg += anna::diameter::functions::commandIdAsPairString(cid);
106 msg += " | DiameterServer: ";
107 msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort());
108 msg += " | EventTime: ";
109 msg += anna::time::functions::currentTimeAsString();
110 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
114 if(my_app.logEnabled()) my_app.writeLogFile(message, "recvfe", clientSession->asString(), a_codecEngine);
116 // Lookup reacting answers list:
117 int code = cid.first;
118 anna::diameter::codec::Message *answer_message = a_reactingAnswers.getMessage(code);
119 if (answer_message) {
121 my_app.getCommunicator()->prepareAnswer(answer_message, message);
124 anna::diameter::comm::Message *msg = my_app.createCommMessage();
125 msg->setBody(answer_message->code());
126 /* response = NULL =*/clientSession->send(msg);
127 my_app.releaseCommMessage(msg);
129 if(my_app.logEnabled()) my_app.writeLogFile(*answer_message, "sent2e", clientSession->asString());
130 } catch(anna::RuntimeException &ex) {
133 if(my_app.logEnabled()) my_app.writeLogFile(*answer_message, "send2eError", clientSession->asString());
136 // Pop front the reacting answer:
137 a_reactingAnswers.nextMessage(code);
143 std::string msg = "No answers programmed (maybe sold out) for request coming from entity: ";
144 msg += anna::diameter::functions::commandIdAsPairString(cid);
145 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
148 // not found: forward to client (if exists)
149 // Forward to client:
150 anna::diameter::comm::LocalServer *localServer = my_app.getDiameterLocalServer();
152 if(localServer && (cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) /* don't forward CER */) {
154 anna::diameter::comm::Message *msg = my_app.createCommMessage();
155 msg->forwardEndToEnd(); // end-to-end will be kept
156 msg->setBody(message);
157 msg->setRequestClientSessionKey(clientSession->getKey());
158 bool success = localServer->send(msg);
161 if(my_app.logEnabled()) {
162 anna::diameter::comm::ServerSession *usedServerSession = localServer->getLastUsedResource();
163 std::string detail = usedServerSession ? usedServerSession->asString() : "<null server session>"; // esto no deberia ocurrir
164 my_app.writeLogFile(message, (success ? "fwd2c" : "fwd2cError"), detail, a_codecEngine);
166 } catch(anna::RuntimeException &ex) {
172 void MyDiameterEntity::eventResponse(const anna::diameter::comm::Response &response)
173 throw(anna::RuntimeException) {
174 LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventResponse", ANNA_FILE_LOCATION));
175 Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
176 CommandLine& cl(anna::CommandLine::instantiate());
177 anna::diameter::comm::ClassCode::_v code = response.getClassCode();
178 anna::diameter::comm::Response::ResultCode::_v result = response.getResultCode();
179 anna::diameter::comm::Message* request = const_cast<anna::diameter::comm::Message*>(response.getRequest());
180 const anna::DataBlock* message = response.getMessage();
181 const anna::diameter::comm::ClientSession *clientSession = static_cast<const anna::diameter::comm::ClientSession *>(response.getSession());
182 bool isBindResponse = (code == anna::diameter::comm::ClassCode::Bind);
183 bool isApplicationMessage = (code == anna::diameter::comm::ClassCode::ApplicationMessage);
184 bool contextExpired = (result == anna::diameter::comm::Response::ResultCode::Timeout);
185 bool isUnavailable = (result == anna::diameter::comm::Response::ResultCode::DiameterUnavailable);
186 bool isOK = (result == anna::diameter::comm::Response::ResultCode::Success);
188 anna::diameter::CommandId request_cid = request->getCommandId();
191 std::string msg = "Response received for original diameter request: ";
192 msg += anna::diameter::functions::commandIdAsPairString(request_cid);
193 msg += " | Response: ";
194 msg += response.asString();
195 msg += " | DiameterServer: ";
196 msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort());
197 msg += " | EventTime: ";
198 msg += anna::time::functions::currentTimeAsString();
199 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
203 //if (isApplicationMessage)
204 LOGWARNING(anna::Logger::warning("Diameter entity unavailable for Diameter Request", ANNA_FILE_LOCATION));
208 //if (isApplicationMessage)
209 LOGWARNING(anna::Logger::warning("Context Expired for Diameter Request which was sent to the entity", ANNA_FILE_LOCATION));
211 if(request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) { // don't trace CEA
212 if(my_app.logEnabled()) my_app.writeLogFile(*request, "req2e-expired", clientSession->asString(), a_codecEngine);
218 std::string msg = "Received response for diameter message: ";
219 msg += anna::diameter::functions::commandIdAsPairString(request_cid);
220 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
224 if(request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) { // don't trace CEA
225 if(my_app.logEnabled()) {
226 my_app.writeLogFile(*message, "recvfe", clientSession->asString(), a_codecEngine);
230 // Forward to client:
231 anna::diameter::comm::LocalServer *localServer = my_app.getDiameterLocalServer();
233 if(localServer && (request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) /* don't forward CEA */) {
235 anna::diameter::comm::Message *msg = my_app.createCommMessage();
236 msg->forwardEndToEnd(); // end-to-end will be kept
237 msg->setBody(*message);
238 bool success = localServer->send(msg, request->getRequestServerSessionKey());
239 my_app.releaseCommMessage(msg);
240 my_app.releaseCommMessage(request);
243 anna::diameter::comm::ServerSession *usedServerSession = my_app.getMyDiameterEngine()->findServerSession(request->getRequestServerSessionKey());
244 std::string detail = usedServerSession ? usedServerSession->asString() : "<null server session>"; // esto no deberia ocurrir
246 if(my_app.logEnabled()) {
247 my_app.writeLogFile(*message, (success ? "fwd2c" : "fwd2cError"), detail, a_codecEngine);
249 } catch(anna::RuntimeException &ex) {
256 if(isOK || contextExpired) my_app.sendBurstMessage();
259 void MyDiameterEntity::eventUnknownResponse(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message)
260 throw(anna::RuntimeException) {
261 LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventUnknownResponse", ANNA_FILE_LOCATION));
262 // Performance stats:
263 Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
265 anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message);
268 std::string msg = "Out-of-context response received from entity: ";
269 msg += anna::diameter::functions::commandIdAsPairString(cid);
270 msg += " | DiameterServer: ";
271 msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort());
272 msg += " | EventTime: ";
273 msg += anna::time::functions::currentTimeAsString();
274 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
278 if(my_app.logEnabled()) my_app.writeLogFile(message, "recvfe-ans-unknown", clientSession->asString(), a_codecEngine);
281 void MyDiameterEntity::eventDPA(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message)
282 throw(anna::RuntimeException) {
283 LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventDPA", ANNA_FILE_LOCATION));
284 // Performance stats:
285 Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
287 anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message);
290 std::string msg = "Disconnect-Peer-Answer received from entity: ";
291 msg += anna::diameter::functions::commandIdAsPairString(cid);
292 msg += " | DiameterServer: ";
293 msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort());
294 msg += " | EventTime: ";
295 msg += anna::time::functions::currentTimeAsString();
296 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
300 if(my_app.logEnabled()) my_app.writeLogFile(message, "recvfe", clientSession->asString(), a_codecEngine);