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 //
13 #include <anna/core/util/Tokenizer.hpp>
14 #include <anna/core/Exception.hpp>
15 #include <anna/testing/TestManager.hpp>
16 #include <anna/diameter/codec/Message.hpp>
17 #include <anna/diameter/codec/Avp.hpp>
18 #include <anna/diameter/helpers/dcca/functions.hpp>
19 #include <anna/diameter/helpers/dcca/functions.hpp>
20 #include <anna/diameter.comm/OriginHost.hpp>
21 #include <anna/diameter.comm/OriginHostManager.hpp>
24 #include "Procedure.hpp"
28 void usage (std::string &response) {
29 response += "\n\nInvalid arguments. Provide these ones:";
31 response += "\n<initial sequence>|<final sequence>|<test timeout ms (0: no timeout step)>|<digits>|<CCR-I xml file>[|CCR-T xml file]";
33 response += "\nSequences are parsed when needed, over AVPs or internal values:";
35 response += "\nSession-Id: <DiameterIdentity>;<high 32 bits>;<low 32 bits>[;<optional value>]";
36 response += "\n \\_fixed_/\\_digits_/ \\_fixed_/\\_digits_/";
38 response += "\nFor example, imagine a 13-digits diameter identity, and a 10-digits optional part.";
39 response += "\nThis procedure will sequence the range for 8 digits in this way:";
41 response += "\n111111<7-digit-sequence>;BAT004;esmdx0900.gxrel10plusrealm.com;901<7-digit-sequence>";
43 response += "\nThe same will be done in MSISDN and IMSI (Subscription-Data AVPs).";
44 response += "\nFramed-IP-Address will be sequenced with a direct correspondence to hex value.";
46 response += "\nThen, you could provide these arguments: \"2000000|9000000|5000|7|CCR-I.xml|CCR-T.xml\"";
51 void Procedure::execute(const std::string &args, std::string &response) throw(anna::RuntimeException) {
53 response = "Dynamic procedure failed to process '"; response += args; response += "': ";
55 anna::Tokenizer targs;
56 targs.apply(args, "|");
58 if (targs.size() < 5) {
63 anna::Tokenizer::const_iterator tok_it = targs.begin();
65 std::string seq_i = anna::Tokenizer::data(tok_it); tok_it++;
66 std::string seq_f = anna::Tokenizer::data(tok_it); tok_it++;
67 std::string timeout = anna::Tokenizer::data(tok_it); tok_it++;
68 std::string digits = anna::Tokenizer::data(tok_it); tok_it++;
69 std::string ccr_i = anna::Tokenizer::data(tok_it); tok_it++;
70 std::string ccr_t = ((tok_it != targs.end()) ? anna::Tokenizer::data(tok_it):"");
71 bool haveTermination = (ccr_t != "");
74 int i_timeout = std::atoi(timeout.c_str());
75 unsigned int ll_seq_i = std::atol(seq_i.c_str());
76 unsigned int ll_seq_f = std::atol(seq_f.c_str());
77 unsigned int ll_seq_size = ll_seq_f - ll_seq_i + 1;
78 int i_digits = std::atoi(digits.c_str());
80 if (ll_seq_i > ll_seq_f) {
81 response += "<final sequence> must be greater or equal than <initial sequence>";
85 if (seq_f.size() > i_digits) {
86 response += "<final sequence> must be lesser than number of <digits>";
90 unsigned int ll_seq, ll_index;
91 anna::Millisecond timeoutMS(i_timeout);
94 anna::diameter::codec::Message ccri, ccrt;
95 anna::diameter::codec::Avp *ccri_sessionId, *ccrt_sessionId, *ccri_framedIPAddress, *ccrt_framedIPAddress, *ccri_msisdn, *ccri_imsi;
96 anna::diameter::codec::Avp *si1, *si2, *sidata1, *sidata2, *sitype1;
97 anna::diameter::codec::Avp *ccri_originHost;
99 ///////// CCR-Initial:
102 // Session-Id & Framed-Ip-Address AVPs
103 ccri_sessionId = ccri.getAvp("Session-Id");
104 ccri_framedIPAddress = ccri.getAvp("Framed-IP-Address");
105 ccri_originHost = ccri.getAvp("Origin-Host");
107 // Subscription-Id AVPs
108 if (ccri.countAvp("Subscription-Id") != 2) {
109 response += "Both Subscription-Id MSISDN & IMSI Avps must be present in the CCR-Initial provided !";
113 si1 = ccri.getAvp("Subscription-Id", 1, anna::Exception::Mode::Ignore);
114 si2 = ccri.getAvp("Subscription-Id", 2, anna::Exception::Mode::Ignore);
117 response += "Cannot found Subscription-Id MSISDN & IMSI Avps !" ;
121 sidata1 = si1->getAvp("Subscription-Id-Data");
122 sidata2 = si2->getAvp("Subscription-Id-Data");
123 sitype1 = si1->getAvp("Subscription-Id-Type");
124 //sitype2 = si2->getAvp("Subscription-Id-Type");
126 if (sitype1->getEnumerated()->getValue() == anna::diameter::helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_E164) {
127 ccri_msisdn = sidata1;
131 ccri_msisdn = sidata2;
135 ///////// CCR-Termination:
136 if (haveTermination) {
139 // Session-Id & Framed-Ip-Address AVPs
140 ccrt_sessionId = ccrt.getAvp("Session-Id");
141 ccrt_framedIPAddress = ccrt.getAvp("Framed-IP-Address");
145 // Prepare session-id string:
146 std::string sessionId = ccri_sessionId->getUTF8String()->getValue();
147 std::size_t last_semicolon = sessionId.rfind(";");
148 anna::Tokenizer tsessionid;
149 tsessionid.apply(sessionId, ";");
151 if (tsessionid.size() < 4) {
152 response += "Session-Id must be in form '<a>;<b>;<c>;<d>'.\n\n";
157 tok_it = tsessionid.begin();
158 std::string d_identity = anna::Tokenizer::data(tok_it); tok_it++; tok_it++; tok_it++;
159 std::string o_part = anna::Tokenizer::data(tok_it);
160 int d_identity_len = d_identity.size();
161 int left_di = d_identity_len - i_digits;
163 response += "Session-Id diameter identity length is lower than selected number of digits ";
164 response += anna::functions::asString("(%d < %d).\n\n", d_identity_len, i_digits);
168 int o_part_len = o_part.size();
169 int left_op = o_part_len - i_digits;
171 response += "Session-Id optional part length is lower than selected number of digits ";
172 response += anna::functions::asString("(%d < %d).\n\n", o_part_len, i_digits);
177 // Idem for MSISDN & IMSI Subscription-Data:
178 std::string msisdn = ccri_msisdn->getUTF8String()->getValue();
179 int msisdn_len = msisdn.size();
180 int left_msisdn = msisdn_len - i_digits;
181 if (left_msisdn < 0) {
182 response += "MSISDN Subscription-Data length is lower than selected number of digits ";
183 response += anna::functions::asString("(%d < %d).\n\n", left_msisdn, i_digits);
187 std::string imsi = ccri_imsi->getUTF8String()->getValue();
188 int imsi_len = imsi.size();
189 int left_imsi = imsi_len - i_digits;
191 response += "IMSI Subscription-Data length is lower than selected number of digits ";
192 response += anna::functions::asString("(%d < %d).\n\n", left_imsi, i_digits);
199 char ndigit_format[32];
200 sprintf(ndigit_format, "%s%d%s", "%0", i_digits, "u");
202 //response += "\nSession-Id original: "; response += sessionId;
203 //response += "\nMSISDN original: "; response += msisdn;
204 //response += "\nIMSI original: "; response += imsi;
207 anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
210 anna::testing::TestCase *tc;
212 // Origin host manager:
213 anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
214 // Assume the oh name from CCR-I (same as CCR-T):
215 std::string originHostName = ccri_originHost->getDiameterIdentity()->getValue();
216 anna::diameter::comm::OriginHost *originHost = ohm.getOriginHost(originHostName);
218 for (ll_index = 0; ll_index < ll_seq_size; ll_index++) {
220 // Calculate next values ////////////////////////////////////////////////////////////
221 ll_seq = ll_seq_i + ll_index;
222 sprintf(cad_aux, ndigit_format, ll_seq);
223 sprintf(cad_framed, "%08x", ll_seq);
225 // Activity indicator:
226 if (ll_seq % 10000 == 0) std::cout << ".";
228 sessionId.replace(left_di, i_digits, cad_aux);
229 sessionId.replace(last_semicolon + left_op + 1, i_digits, cad_aux);
231 msisdn.replace(left_msisdn, i_digits, cad_aux);
233 imsi.replace(left_imsi, i_digits, cad_aux);
235 //response += "\nSession-Id modified: "; response += sessionId;
236 //response += "\nMSISDN modified: "; response += msisdn;
237 //response += "\nIMSI modified: "; response += imsi;
238 //response += "\nFramedIP modified: "; response += cad_framed;
240 // Update diameter messages /////////////////////////////////////////////////////////
241 ccri_sessionId->getUTF8String()->setValue(sessionId);
242 ccri_framedIPAddress->getOctetString()->fromHexString(cad_framed);
243 ccri_msisdn->getUTF8String()->setValue(msisdn);
244 ccri_imsi->getUTF8String()->setValue(imsi);
246 if (haveTermination) {
247 ccrt_sessionId->getUTF8String()->setValue(sessionId);
248 ccrt_framedIPAddress->getOctetString()->fromHexString(cad_framed);
252 tc = testManager.getTestCase(ll_index+1);
253 // test|__TESTID__|timeout|6000
254 // test|__TESTID__|sendxml2e|ccr-i.xml
255 // test|__TESTID__|waitfe|272|0|||11111__SEQ8__;BAT004;esmdx0900.gxrel10plusrealm.com;90__SEQ8__|2001
256 // test|__TESTID__|sendxml2e|ccr-t.xml
257 // test|__TESTID__|waitfe|272|0|||11111__SEQ8__;BAT004;esmdx0900.gxrel10plusrealm.com;90__SEQ8__|2001
259 if (i_timeout != 0) {
260 // Step 1: timeout 5000 ms:
261 tc->addTimeout(timeoutMS);
264 // Step 2: sendxml2e: CCR-Initial
265 tc->addSendDiameterXml2e(ccri.code(), originHost, -1 /* 'wait for request' step number for answers */);
267 // Step 3: waitfe: CCA with same session id
268 // PARAM: 1 2 3 4 5 6 7 8 9 10 11
269 // wait<fe/fc>|[code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]
270 tc->addWaitDiameter(true /* from entity */, "272", "0", "", "", sessionId, "2001", "", "", "");
272 if (haveTermination) {
273 // Step 4: sendxml2e: CCR-Termination
274 tc->addSendDiameterXml2e(ccrt.code(), originHost, -1 /* 'wait for request' step number for answers */);
276 // Step 5: waitfe: CCA with same session id
277 tc->addWaitDiameter(true /* from entity */, "272", "0", "", "", sessionId, "2001", "", "", "");
281 response = "Completed provision for pid "; response += anna::functions::asString(a_app->getPid()); response += "; range [";
282 response += seq_i; response += ", "; response += seq_f; response += "]; scenary: ";
283 response += "CCR-Initial"; if (haveTermination) response += " + CCR-Termination";