6027bf0d526df2da86a3cdcd32ee26e7bd86ec18
[anna.git] / example / diameter / launcher / MyDiameterEntity.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
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 //
7
8
9 // Project
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.comm/ClientSession.hpp>
15 #include <anna/diameter.comm/OriginHost.hpp>
16 #include <anna/diameter/helpers/base/functions.hpp>
17 #include <anna/diameter/helpers/dcca/functions.hpp>
18
19 // Process
20 #include <MyDiameterEngine.hpp>
21 #include <MyDiameterEntity.hpp>
22 #include <MyLocalServer.hpp>
23 #include <Launcher.hpp>
24 #include <anna/testing/TestManager.hpp>
25
26
27 void MyDiameterEntity::eventRequestRetransmission(const anna::diameter::comm::ClientSession* clientSession, anna::diameter::comm::Message *request) throw() {
28
29   LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventRequestRetransmission", ANNA_FILE_LOCATION));
30
31   // Base class:
32   Entity::eventRequestRetransmission(clientSession, request); // warning trace
33
34   // Performance stats:
35   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
36   anna::diameter::comm::OriginHost * my_node = my_app.getOriginHost(getEngine()->getOriginHostName());
37   // CommandId:
38   anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(request->getBody());
39   LOGDEBUG
40   (
41     std::string msg = "Request retransmitted: ";
42     msg += anna::diameter::functions::commandIdAsPairString(cid);
43     msg += " | DiameterServer: ";
44     msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort());
45     msg += " | EventTime: ";
46     msg += anna::time::functions::currentTimeAsString();
47     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
48   );
49
50   // Write retransmission
51   if(my_node->logEnabled()) my_node->writeLogFile(request->getBody(), "retry", clientSession->asString());
52 }
53
54
55 void MyDiameterEntity::eventRequest(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message)
56 throw(anna::RuntimeException) {
57   LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventRequest", ANNA_FILE_LOCATION));
58   // Performance stats:
59   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
60   anna::diameter::comm::OriginHost * my_node = my_app.getOriginHost(getEngine()->getOriginHostName());
61
62   // CommandId:
63   anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message);
64   LOGDEBUG
65   (
66     std::string msg = "Request received: ";
67     msg += anna::diameter::functions::commandIdAsPairString(cid);
68     msg += " | DiameterServer: ";
69     msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort());
70     msg += " | EventTime: ";
71     msg += anna::time::functions::currentTimeAsString();
72     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
73   );
74
75   // Write reception
76   if(my_node->logEnabled()) my_node->writeLogFile(message, "recvfe", clientSession->asString());
77
78   // Lookup reacting answers list:
79   int code = cid.first;
80   anna::diameter::codec::Message *answer_message = a_reactingAnswers.getMessage(code);
81   if (answer_message) {
82     // Prepare answer:
83     my_app.getCommunicator()->prepareAnswer(answer_message, message);
84     anna::diameter::comm::Message *msg;
85
86     try {
87       msg = my_node->createCommMessage();
88       msg->setBody(answer_message->code());
89       /* response = NULL =*/clientSession->send(msg);
90
91       if(my_node->logEnabled()) my_node->writeLogFile(*answer_message, "sent2e", clientSession->asString());
92     } catch(anna::RuntimeException &ex) {
93       ex.trace();
94
95       if(my_node->logEnabled()) my_node->writeLogFile(*answer_message, "send2eError", clientSession->asString());
96     }
97
98     // release msg
99     my_node->releaseCommMessage(msg);
100
101     // Pop front the reacting answer:
102     a_reactingAnswers.nextMessage(code);
103     return;
104   }
105
106   LOGDEBUG
107   (
108     std::string msg = "No answers programmed (maybe sold out) for request coming from entity: ";
109     msg += anna::diameter::functions::commandIdAsPairString(cid);
110     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
111   );
112
113   // not found: forward to client (if exists)
114   // Forward to client:
115   MyLocalServer *localServer = (MyLocalServer *)my_node->getDiameterServer();
116
117   if(localServer && (cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) /* don't forward CER */) {
118     try {
119       anna::diameter::comm::Message *msg = my_node->createCommMessage();
120       msg->forwardEndToEnd(); // end-to-end will be kept
121       msg->setBody(message);
122       msg->setRequestClientSessionKey(clientSession->getKey());
123       bool success = localServer->send(msg);
124
125       // Detailed log:
126       if(my_node->logEnabled()) {
127         anna::diameter::comm::ServerSession *usedServerSession = localServer->getLastUsedResource();
128         std::string detail = usedServerSession ? usedServerSession->asString() : "<null server session>"; // esto no deberia ocurrir
129         my_node->writeLogFile(message, (success ? "fwd2c" : "fwd2cError"), detail);
130       }
131     } catch(anna::RuntimeException &ex) {
132       ex.trace();
133     }
134   }
135
136   // Testing:
137   anna::testing::TestManager::instantiate().receiveMessage(message, clientSession);
138 }
139
140 void MyDiameterEntity::eventResponse(const anna::diameter::comm::Response &response)
141 throw(anna::RuntimeException) {
142   LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventResponse", ANNA_FILE_LOCATION));
143   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
144   anna::diameter::comm::OriginHost *my_node = my_app.getOriginHost(getEngine()->getOriginHostName());
145   anna::diameter::comm::ClassCode::_v code = response.getClassCode();
146   anna::diameter::comm::Response::ResultCode::_v result = response.getResultCode();
147   anna::diameter::comm::Message* request = const_cast<anna::diameter::comm::Message*>(response.getRequest());
148   const anna::DataBlock* message = response.getMessage();
149   const anna::diameter::comm::ClientSession *clientSession = static_cast<const anna::diameter::comm::ClientSession *>(response.getSession());
150   bool isBindResponse = (code == anna::diameter::comm::ClassCode::Bind);
151   bool isApplicationMessage = (code == anna::diameter::comm::ClassCode::ApplicationMessage);
152   bool contextExpired = (result == anna::diameter::comm::Response::ResultCode::Timeout);
153   bool isUnavailable = (result == anna::diameter::comm::Response::ResultCode::DiameterUnavailable);
154   bool isOK = (result == anna::diameter::comm::Response::ResultCode::Success);
155
156   // CommandId:
157   anna::diameter::CommandId request_cid = request->getCommandId();
158   LOGDEBUG
159   (
160     std::string msg = "Response received for original diameter request: ";
161     msg += anna::diameter::functions::commandIdAsPairString(request_cid);
162     msg += " | Response: ";
163     msg += response.asString();
164     msg += " | DiameterServer: ";
165     msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort());
166     msg += " | EventTime: ";
167     msg += anna::time::functions::currentTimeAsString();
168     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
169   );
170
171   if(isUnavailable) {
172     //if (isApplicationMessage)
173     LOGWARNING(anna::Logger::warning("Diameter entity unavailable for Diameter Request", ANNA_FILE_LOCATION));
174   }
175
176   if(contextExpired) {
177     //if (isApplicationMessage)
178     LOGWARNING(anna::Logger::warning("Context Expired for Diameter Request which was sent to the entity", ANNA_FILE_LOCATION));
179
180     if(request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) {  // don't trace CEA
181       if(my_node->logEnabled()) my_node->writeLogFile(*request, "req2e-expired", clientSession->asString());
182     }
183   }
184
185   if(isOK) {
186     LOGDEBUG(
187       std::string msg = "Received response for diameter message:  ";
188       msg += anna::diameter::functions::commandIdAsPairString(request_cid);
189       anna::Logger::debug(msg, ANNA_FILE_LOCATION);
190     );
191
192     // Write reception
193     if(request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) {  // don't trace CEA
194       if(my_node->logEnabled()) {
195         my_node->writeLogFile(*message, "recvfe", clientSession->asString());
196       }
197     }
198
199     // Forward to client:
200     MyLocalServer *localServer = (MyLocalServer *)my_node->getDiameterServer();
201
202     if(localServer && (request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) /* don't forward CEA */) {
203       anna::diameter::comm::Message *msg;
204
205       try {
206         msg = my_node->createCommMessage();
207         msg->forwardEndToEnd(); // end-to-end will be kept
208         msg->setBody(*message);
209         bool success = localServer->send(msg, request->getRequestServerSessionKey());
210
211         // Detailed log:
212         anna::diameter::comm::ServerSession *usedServerSession = my_node->getCommEngine()->findServerSession(request->getRequestServerSessionKey());
213         std::string detail = usedServerSession ? usedServerSession->asString() : "<null server session>"; // esto no deberia ocurrir
214
215         if(my_node->logEnabled()) {
216           my_node->writeLogFile(*message, (success ? "fwd2c" : "fwd2cError"), detail);
217         }
218       } catch(anna::RuntimeException &ex) {
219         ex.trace();
220       }
221
222       // release msgs
223       my_node->releaseCommMessage(msg);
224       my_node->releaseCommMessage(request);
225     }
226   }
227
228   // Triggering burst:
229   if(isOK || contextExpired) my_node->sendBurstMessage();
230
231   // Testing:
232   if(isOK) anna::testing::TestManager::instantiate().receiveMessage(*message, clientSession);
233 }
234
235 void MyDiameterEntity::eventUnknownResponse(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message)
236 throw(anna::RuntimeException) {
237   LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventUnknownResponse", ANNA_FILE_LOCATION));
238   // Performance stats:
239   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
240   anna::diameter::comm::OriginHost * my_node = my_app.getOriginHost(getEngine()->getOriginHostName());
241   // CommandId:
242   anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message);
243   LOGDEBUG
244   (
245     std::string msg = "Out-of-context response received from entity: ";
246     msg += anna::diameter::functions::commandIdAsPairString(cid);
247     msg += " | DiameterServer: ";
248     msg += anna::functions::socketLiteralAsString(clientSession->getAddress(), clientSession->getPort());
249     msg += " | EventTime: ";
250     msg += anna::time::functions::currentTimeAsString();
251     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
252   );
253
254   // Write reception
255   if(my_node->logEnabled()) my_node->writeLogFile(message, "recvfe-ans-unknown", clientSession->asString());
256 }
257
258 void MyDiameterEntity::eventDPA(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message)
259 throw(anna::RuntimeException) {
260   LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventDPA", ANNA_FILE_LOCATION));
261   // Performance stats:
262   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
263   anna::diameter::comm::OriginHost * my_node = my_app.getOriginHost(getEngine()->getOriginHostName());
264   // CommandId:
265   anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message);
266   LOGDEBUG
267   (
268     std::string msg = "Disconnect-Peer-Answer 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);
275   );
276
277   // Write reception
278   if(my_node->logEnabled()) my_node->writeLogFile(message, "recvfe", clientSession->asString());
279
280   // Testing:
281   anna::testing::TestManager::instantiate().receiveMessage(message, clientSession);
282 }