+namespace {
+
+ void usage (std::string &response) {
+ response += "\n\nInvalid arguments. Provide these ones:";
+ response += "\n";
+ response += "\n<test timeout ms (0: no timeout step)><initial sequence>|<final sequence>|<digits>|<CCR-I xml file>[|CCR-T xml file]";
+ response += "\n";
+ response += "\nSequences are parsed when needed, over AVPs or internal values:";
+ response += "\n";
+ response += "\nSession-Id: <DiameterIdentity>;<high 32 bits>;<low 32 bits>[;<optional value>]";
+ response += "\n \\_fixed_/\\_digits_/ \\_fixed_/\\_digits_/";
+ response += "\n";
+ response += "\nFor example, imagine a 13-digits diameter identity, and a 10-digits optional part.";
+ response += "\nThis procedure will sequence the range for 8 digits in this way:";
+ response += "\n";
+ response += "\n111111<7-digit-sequence>;BAT004;esmdx0900.gxrel10plusrealm.com;901<7-digit-sequence>";
+ response += "\n";
+ response += "\nThe same will be done in MSISDN and IMSI (Subscription-Data AVPs).";
+ response += "\nFramed-IP-Address will be sequenced with a direct correspondence to hex value.";
+ response += "\n";
+ response += "\nThen, you could provide these arguments: \"5000|2000000|9000000|7|CCR-I.xml|CCR-T.xml\"";
+ response += "\n";
+ }
+}
+
+void Procedure::execute(const std::string &args, std::string &response, anna::diameter::comm::OriginHost *originHost) throw(anna::RuntimeException) {
+
+ response = "Dynamic procedure failed to process '"; response += args; response += "': ";
+
+ anna::Tokenizer targs;
+ targs.apply(args, "|");
+
+ if (targs.size() < 5) {
+ usage(response);
+ return;
+ }
+
+ anna::Tokenizer::const_iterator tok_it = targs.begin();
+
+ std::string seq_i = anna::Tokenizer::data(tok_it); tok_it++;
+ std::string seq_f = anna::Tokenizer::data(tok_it); tok_it++;
+ std::string timeout = anna::Tokenizer::data(tok_it); tok_it++;
+ std::string digits = anna::Tokenizer::data(tok_it); tok_it++;
+ std::string ccr_i = anna::Tokenizer::data(tok_it); tok_it++;
+ std::string ccr_t = ((tok_it != targs.end()) ? anna::Tokenizer::data(tok_it):"");
+ bool haveTermination = (ccr_t != "");
+
+ // Test cases cycles:
+ int i_timeout = std::atoi(timeout.c_str());
+ unsigned int ll_seq_i = std::atol(seq_i.c_str());
+ unsigned int ll_seq_f = std::atol(seq_f.c_str());
+ unsigned int ll_seq_size = ll_seq_f - ll_seq_i + 1;
+ int i_digits = std::atoi(digits.c_str());
+
+ if (ll_seq_i > ll_seq_f) {
+ response += "<final sequence> must be greater or equal than <initial sequence>";
+ return;
+ }
+
+ if (seq_f.size() > i_digits) {
+ response += "<final sequence> must be lesser than number of <digits>";
+ return;
+ }
+
+ unsigned int ll_seq, ll_index;
+ anna::Millisecond timeoutMS(i_timeout);
+
+ // Load xml messages:
+ anna::diameter::codec::Message ccri, ccrt;
+ anna::diameter::codec::Avp *ccri_sessionId, *ccrt_sessionId, *ccri_framedIPAddress, *ccrt_framedIPAddress, *ccri_msisdn, *ccri_imsi;
+ anna::diameter::codec::Avp *si1, *si2, *sidata1, *sidata2, *sitype1, *sitype2;
+
+ try {
+
+ ///////// CCR-Initial:
+ ccri.loadXML(ccr_i);
+
+ // Session-Id & Framed-Ip-Address AVPs
+ ccri_sessionId = ccri.getAvp("Session-Id");
+ ccri_framedIPAddress = ccri.getAvp("Framed-IP-Address");
+
+ // Subscription-Id AVPs
+ if (ccri.countAvp("Subscription-Id") != 2) {
+ response += "Both Subscription-Id MSISDN & IMSI Avps must be present in the CCR-Initial provided !";
+ return;
+ }
+
+ si1 = ccri.getAvp("Subscription-Id", 1, anna::Exception::Mode::Ignore);
+ si2 = ccri.getAvp("Subscription-Id", 2, anna::Exception::Mode::Ignore);
+
+ if (!si1 || !si2) {
+ response += "Cannot found Subscription-Id MSISDN & IMSI Avps !" ;
+ return;
+ }
+
+ sidata1 = si1->getAvp("Subscription-Id-Data");
+ sidata2 = si2->getAvp("Subscription-Id-Data");
+ sitype1 = si1->getAvp("Subscription-Id-Type");
+ //sitype2 = si2->getAvp("Subscription-Id-Type");
+
+ if (sitype1->getEnumerated()->getValue() == anna::diameter::helpers::dcca::AVPVALUES__Subscription_Id_Type::END_USER_E164) {
+ ccri_msisdn = sidata1;
+ ccri_imsi = sidata2;
+ }
+ else {
+ ccri_msisdn = sidata2;
+ ccri_imsi = sidata1;
+ }
+
+ ///////// CCR-Termination:
+ if (haveTermination) {
+ ccrt.loadXML(ccr_t);
+
+ // Session-Id & Framed-Ip-Address AVPs
+ ccrt_sessionId = ccrt.getAvp("Session-Id");
+ ccrt_framedIPAddress = ccrt.getAvp("Framed-IP-Address");
+ }
+ }
+ catch(anna::RuntimeException &ex) {
+ ex.trace();
+ }
+
+ // Prepare session-id string:
+ std::string sessionId = ccri_sessionId->getUTF8String()->getValue();
+ std::size_t last_semicolon = sessionId.rfind(";");
+ anna::Tokenizer tsessionid;
+ tsessionid.apply(sessionId, ";");
+
+ if (tsessionid.size() < 4) {
+ response += "Session-Id must be in form '<a>;<b>;<c>;<d>'.\n\n";
+ usage(response);
+ return;
+ }
+
+ tok_it = tsessionid.begin();
+ std::string d_identity = anna::Tokenizer::data(tok_it); tok_it++; tok_it++; tok_it++;
+ std::string o_part = anna::Tokenizer::data(tok_it);
+ int d_identity_len = d_identity.size();
+ int left_di = d_identity_len - i_digits;
+ if (left_di < 0) {
+ response += "Session-Id diameter identity length is lower than selected number of digits ";
+ response += anna::functions::asString("(%d < %d).\n\n", d_identity_len, i_digits);
+ usage(response);
+ return;
+ }
+ int o_part_len = o_part.size();
+ int left_op = o_part_len - i_digits;
+ if (left_op < 0) {
+ response += "Session-Id optional part length is lower than selected number of digits ";
+ response += anna::functions::asString("(%d < %d).\n\n", o_part_len, i_digits);
+ usage(response);
+ return;
+ }
+
+ // Idem for MSISDN & IMSI Subscription-Data:
+ std::string msisdn = ccri_msisdn->getUTF8String()->getValue();
+ int msisdn_len = msisdn.size();
+ int left_msisdn = msisdn_len - i_digits;
+ if (left_msisdn < 0) {
+ response += "MSISDN Subscription-Data length is lower than selected number of digits ";
+ response += anna::functions::asString("(%d < %d).\n\n", left_msisdn, i_digits);
+ usage(response);
+ return;