Multistack launcher
[anna.git] / source / diameter / codec / Message.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 // Local
10 #include <anna/diameter/codec/Message.hpp>
11 #include <anna/diameter/codec/Format.hpp>
12
13 #include <anna/diameter/codec/functions.hpp> // REQUIRED_WORDS
14 #include <anna/config/defines.hpp> // general types, decoding helpers (DECODE[2/3/4]BYTES_INDX_VALUETYPE), etc.
15 #include <anna/diameter/functions.hpp>
16 #include <anna/diameter/codec/functions.hpp> // REQUIRED_WORDS
17 #include <anna/diameter/codec/OamModule.hpp>
18 #include <anna/diameter/codec/Engine.hpp>
19 #include <anna/diameter/stack/Avp.hpp>
20 #include <anna/diameter/stack/Format.hpp>
21 #include <anna/diameter/stack/Dictionary.hpp>
22 #include <anna/diameter/stack/Engine.hpp>
23 #include <anna/core/functions.hpp>
24 #include <anna/core/util/RegularExpression.hpp>
25 #include <anna/diameter/helpers/base/defines.hpp>
26
27 #include <anna/core/tracing/Logger.hpp>
28 #include <anna/core/functions.hpp>
29 #include <anna/core/tracing/TraceMethod.hpp>
30 #include <anna/xml/xml.hpp>
31
32 // STL
33 #include <string>
34 #include <vector>
35
36
37 using namespace anna;
38 using namespace anna::diameter::codec;
39
40
41 //static
42 namespace anna {
43
44 namespace diameter {
45
46 namespace codec {
47 const int Message::HeaderLength(20);
48 const U8 Message::RBitMask(0x80);
49 const U8 Message::PBitMask(0x40);
50 const U8 Message::EBitMask(0x20);
51 const U8 Message::TBitMask(0x10);
52 }
53 }
54 }
55
56 //------------------------------------------------------------------------------
57 //----------------------------------------------------------- Message::Message()
58 //------------------------------------------------------------------------------
59 Message::Message(Engine *engine) : a_engine(engine), a_forCode(true) {
60   initialize();
61 }
62
63
64 //------------------------------------------------------------------------------
65 //----------------------------------------------------------- Message::Message()
66 //------------------------------------------------------------------------------
67 Message::Message(CommandId id, Engine *engine) : a_engine(engine), a_forCode(true) {
68   initialize();
69   setId(id);
70 }
71
72
73 //------------------------------------------------------------------------------
74 //---------------------------------------------------------- Message::~Message()
75 //------------------------------------------------------------------------------
76 Message::~Message() {
77   clear();
78 }
79
80
81 //------------------------------------------------------------------------------
82 //--------------------------------------------------------- Message::getEngine()
83 //------------------------------------------------------------------------------
84 Engine * Message::getEngine() const throw(anna::RuntimeException) {
85   if(!a_engine)
86     throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION);
87
88   return a_engine;
89
90 }
91
92
93 //------------------------------------------------------------------------------
94 //-------------------------------------------------------- Message::initialize()
95 //------------------------------------------------------------------------------
96 void Message::initialize() throw() {
97   a_version = 1;
98   a_id = CommandId(0, false);
99   a_flags = 0x00;
100   a_applicationId = 0;
101   a_hopByHop = 0;
102   a_endToEnd = 0;
103   //a_avps.clear();
104   a_insertionPositionForChilds = 0;
105   //a_finds.clear();
106 }
107
108
109 //------------------------------------------------------------------------------
110 //------------------------------------------------------------- Message::clear()
111 //------------------------------------------------------------------------------
112 void Message::clear() throw(anna::RuntimeException) {
113   for(avp_iterator it = avp_begin(); it != avp_end(); it++) { /*avp(it)->clear(); */getEngine()->releaseAvp(Avp::avp(it)); }
114
115   a_avps.clear();
116   a_forCode.clear();
117   // Cache system:
118   a_finds.clear();
119   // Initialize:
120   initialize();
121 }
122
123
124 //------------------------------------------------------------------------------
125 //----------------------------------------------------------- Message::flagsOK()
126 //------------------------------------------------------------------------------
127 bool Message::flagsOK(int &rc) const throw() {
128   // Dictionary stack command:
129   const stack::Command *stackCommand = getStackCommand();
130
131   if(!stackCommand) {
132     anna::Logger::error("Impossible to decide if flags are correct because stack command is not identified. Assume flags ok", ANNA_FILE_LOCATION);
133     //rc = helpers::base::AVPVALUES__Result_Code::?????;
134     return true;
135   };
136
137   // DIAMETER_INVALID_HDR_BITS 3008
138   //
139   //      A request was received whose bits in the Diameter header were set
140   //      either to an invalid combination or to a value that is
141   //      inconsistent with the Command Code's definition.
142   bool ok = true;
143
144   if(stackCommand->isRequest() != isRequest()) ok = false;  // en teoria es imposible salir por aqui: blindado en la dtd
145
146   if(isRequest() && errorBit()) {
147     anna::Logger::error("E(rror) bit is not allowed at diameter requests", ANNA_FILE_LOCATION);
148     ok = false;
149   }
150
151   if(isAnswer() && potentiallyReTransmittedMessageBit()) {
152     anna::Logger::error("T(Potentially re-transmitted message) bit is not allowed at diameter answers", ANNA_FILE_LOCATION);
153     ok = false;
154   }
155
156   if(!ok) {
157     rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_HDR_BITS;
158     return false;
159   }
160
161   // DIAMETER_INVALID_BIT_IN_HEADER 5013
162   //
163   //      This error is returned when a reserved bit in the Diameter header
164   //      is set to one (1) or the bits in the Diameter header are set
165   //      incorrectly.
166   if((a_flags & 0x0f) != 0x00) {
167     anna::Logger::error("Any (or more than one) of the reserved message flags bit has been activated. Reserved bits must be null", ANNA_FILE_LOCATION);
168     rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_BIT_IN_HEADER;
169     return false;
170   }
171
172   return true;
173 }
174
175
176 //------------------------------------------------------------------------------
177 //------------------------------------------------------------- Message::setId()
178 //------------------------------------------------------------------------------
179 void Message::setId(CommandId id, bool _clear) throw(anna::RuntimeException) {
180   // Clear class content:
181   if(_clear) clear();
182
183   // Id assignment:
184   a_id = id;
185   // Dictionary stack command:
186   const stack::Command *stackCommand = getStackCommand(); // based on dictionary and a_id
187
188   // Dictionary flags for known types:
189   if(stackCommand) {
190     if(stackCommand->isRequest()) a_flags |= RBitMask;
191   } else {
192     if(a_id.second) a_flags |= RBitMask; else a_flags &= (~RBitMask);
193   }
194 }
195
196
197 //------------------------------------------------------------------------------
198 //------------------------------------------------------------- Message::setId()
199 //------------------------------------------------------------------------------
200 void Message::setId(const char *name) throw(anna::RuntimeException) {
201   setId(getEngine()->commandIdForName(name));
202 }
203
204
205 //------------------------------------------------------------------------------
206 //-------------------------------------------------- Message::setApplicationId()
207 //------------------------------------------------------------------------------
208 void Message::setApplicationId(U32 aid) throw(anna::RuntimeException) {
209   a_applicationId = aid;
210
211   // Default behaviour:
212   if (!getEngine()->hasSelectStackWithApplicationId()) return;
213
214   // Adapts for Application-ID stack identifier:
215   getEngine()->setDictionary(aid);
216 }
217
218
219 //------------------------------------------------------------------------------
220 //------------------------------------------------------------ Message::addAvp()
221 //------------------------------------------------------------------------------
222 Avp * Message::addAvp(const char *name) throw(anna::RuntimeException) {
223   return addAvp(getEngine()->avpIdForName(name));
224 }
225
226
227 //------------------------------------------------------------------------------
228 //--------------------------------------------------------- Message::removeAvp()
229 //------------------------------------------------------------------------------
230 bool Message::removeAvp(const char *name, int ocurrence) throw(anna::RuntimeException) {
231   return removeAvp(getEngine()->avpIdForName(name), ocurrence);
232 }
233
234
235 //------------------------------------------------------------------------------
236 //----------------------------------------------------------- Message::_getAvp()
237 //------------------------------------------------------------------------------
238 const Avp * Message::_getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) {
239   return getAvp(getEngine()->avpIdForName(name), ocurrence, emode);
240 }
241
242
243 //------------------------------------------------------------------------------
244 //---------------------------------------------------------- Message::countAvp()
245 //------------------------------------------------------------------------------
246 int Message::countAvp(const char *name) const throw(anna::RuntimeException) {
247   return countAvp(getEngine()->avpIdForName(name));
248 }
249
250
251 //------------------------------------------------------------------------------
252 //--------------------------------------------------------- Message::getLength()
253 //------------------------------------------------------------------------------
254 U24 Message::getLength() const throw() {
255   U24 result;
256   // Header length:
257   result = HeaderLength;
258
259   for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) result += 4 * REQUIRED_WORDS(Avp::avp(it)->getLength());
260
261   return result;
262 }
263
264
265 //------------------------------------------------------------------------------
266 //------------------------------------------------------------ Message::decode()
267 //------------------------------------------------------------------------------
268 void Message::decode(const anna::DataBlock &db, Message *ptrAnswer) throw(anna::RuntimeException) {
269   // Trace
270   LOGDEBUG(
271     anna::xml::Node root("Message::decode");
272     std::string trace = "DataBlock to decode:\n";
273     trace += db.asString();
274     anna::Logger::debug(trace, ANNA_FILE_LOCATION);
275   );
276   clear();
277   // EXCEPTION MANAGEMENT IN THIS METHOD
278   // ===================================
279   // DECODE PHASE
280   // If an error ocurred, decoding will stop launching exception but we will catch it and go on with validation because perhaps
281   //  the achieved message could be valid against all odds. Only fatal errors cause direct decoding exception (length problems
282   //  at header).
283   //
284   // VALIDATION PHASE
285   // Launch exception on first validation error (validateAll == false), or log warning reporting all validation errors when
286   //  complete validation is desired (validateAll == true, engine default) launching a final exception like "the decoded message is invalid".
287   // OAM
288   OamModule &oamModule = OamModule::instantiate();
289
290   if(db.getSize() < HeaderLength) {
291     oamModule.activateAlarm(OamModule::Alarm::MessageDecode__NotEnoughBytesToCoverMessageHeaderLength);
292     oamModule.count(OamModule::Counter::MessageDecode__NotEnoughBytesToCoverMessageHeaderLength);
293     // DIAMETER_INVALID_MESSAGE_LENGTH; // no podr� construir un answer fiable, as� que no registro el result-code
294     throw anna::RuntimeException("Not enough bytes to cover message header length (20 bytes)", ANNA_FILE_LOCATION);
295   }
296
297   const char * buffer = db.getData();
298
299   //         0                   1                   2                   3
300   //         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
301   //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
302   //        |    Version    |                 Message Length                |
303   //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
304   //        | command flags |                  Command-Code                 |
305   //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
306   //        |                         Application-ID                        |
307   //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
308   //        |                      Hop-by-Hop Identifier                    |
309   //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
310   //        |                      End-to-End Identifier                    |
311   //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
312   //        |  AVPs ...
313   //        +-+-+-+-+-+-+-+-+-+-+-+-+-
314   // Header fields:
315   a_version = (S8)buffer[0];
316
317   U24 length = DECODE3BYTES_INDX_VALUETYPE(buffer, 1, U24); // total length including header fields
318
319   a_flags = (S8)buffer[4];
320
321   U24 code = DECODE3BYTES_INDX_VALUETYPE(buffer, 5, U24);
322
323   a_id = CommandId(code, requestBit() /* based on a_flags */);
324
325   setApplicationId(DECODE4BYTES_INDX_VALUETYPE(buffer, 8, U32)); // centralize set, because it could be used for stack selection.
326
327   a_hopByHop = DECODE4BYTES_INDX_VALUETYPE(buffer, 12, U32);
328
329   a_endToEnd = DECODE4BYTES_INDX_VALUETYPE(buffer, 16, U32);
330
331   // Only build answer for a request:
332   Message *answer = isRequest() ? ptrAnswer : NULL;
333
334   if(answer) answer->setHeaderToAnswer(*this);
335
336   // Length check:
337   if(db.getSize() < length) {
338     oamModule.activateAlarm(OamModule::Alarm::MessageDecode__NotEnoughBytesToCoverMessageLength);
339     oamModule.count(OamModule::Counter::MessageDecode__NotEnoughBytesToCoverMessageLength);
340
341     if(answer) answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_MESSAGE_LENGTH);
342
343     throw anna::RuntimeException("Not enough bytes to cover message length", ANNA_FILE_LOCATION);
344   }
345
346   // Message identifier
347   // Flags could have been updated regarding dictionary, but during decoding we must respect buffer received:
348   a_flags = (S8)buffer[4];
349   // Avps start position:
350   const S8 * startData = buffer + HeaderLength;
351   U24 dataBytes = length - HeaderLength;
352
353   if(dataBytes < 8 /* minimum avp */) {
354     LOGDEBUG(anna::Logger::debug("Message empty (without avps)", ANNA_FILE_LOCATION));
355     return;
356   }
357
358   int avpPos = 0;
359   Avp* avp;
360   anna::DataBlock db_aux;
361
362   // Parent information:
363   parent_t parent;
364   parent.setMessage(a_id);
365
366
367   while(avpPos < dataBytes) {
368     try {
369       avp =  getEngine()->createAvp(NULL);
370       db_aux.assign(startData + avpPos, dataBytes - avpPos /* is valid to pass total length (indeed i don't know the real avp length) because it will be limited and this has deep copy disabled (no memory is reserved) */);
371       avp -> decode(db_aux, parent, answer);
372     } catch(anna::RuntimeException &ex) {
373       getEngine()->releaseAvp(avp);
374       LOGWARNING(
375         anna::Logger::warning(ex.getText(), ANNA_FILE_LOCATION);
376         anna::Logger::warning("Although a decoding error was found, validation could be checked because message could be enough for the application", ANNA_FILE_LOCATION);
377       );
378       break;
379     }
380
381     addChild(avp);
382     avpPos += 4 * REQUIRED_WORDS(avp->getLength());
383   }
384
385   // Post-Fixing
386   Engine::FixMode::_v fmode = getEngine()->getFixMode();
387
388   if((fmode == Engine::FixMode::AfterDecoding) || (fmode == Engine::FixMode::Always)) fix();
389
390   // Trace
391   LOGDEBUG(
392     std::string trace = "Message decoded:\n";
393     trace += asXMLString();
394     anna::Logger::debug(trace, ANNA_FILE_LOCATION);
395   );
396   // Post-Validation
397   Engine::ValidationMode::_v vmode = getEngine()->getValidationMode();
398
399   if((vmode == Engine::ValidationMode::AfterDecoding) || (vmode == Engine::ValidationMode::Always))
400     if(!valid(answer))
401       throw anna::RuntimeException("The decoded message is invalid. See previous report on warning-level traces", ANNA_FILE_LOCATION);
402 }
403
404
405 //------------------------------------------------------------------------------
406 //--------------------------------------------------- Message::getStackCommand()
407 //------------------------------------------------------------------------------
408 const anna::diameter::stack::Command *Message::getStackCommand(CommandId id) const throw(anna::RuntimeException) {
409   const stack::Dictionary * dictionary = getEngine()->getDictionary();
410   return (dictionary ? (dictionary->getCommand(id)) : NULL);
411 }
412
413
414 //------------------------------------------------------------------------------
415 //----------------------------------------------------- Message::setResultCode()
416 //------------------------------------------------------------------------------
417 void Message::setResultCode(int rc) throw(anna::RuntimeException) {
418   if(isRequest()) return;
419
420   // Add Result-Code if not yet added. Even if validation depth is set to 'Complete',
421   // the Result-Code value will be the first found during the message analysis:
422   Avp *resultCodeAvp = getAvp(helpers::base::AVPID__Result_Code, 1, anna::Exception::Mode::Ignore);
423
424   if(!resultCodeAvp)
425     addAvp(helpers::base::AVPID__Result_Code)->getUnsigned32()->setValue(rc);
426   else if(resultCodeAvp->getUnsigned32()->getValue() == helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS)  // Only success could be replaced
427     resultCodeAvp->getUnsigned32()->setValue(rc);
428
429   // Error bit:
430   setErrorBit(rc >= 3001 && rc <= 3010 /* protocol errors */);
431 }
432
433
434 //------------------------------------------------------------------------------
435 //----------------------------------------------------- Message::getResultCode()
436 //------------------------------------------------------------------------------
437 int Message::getResultCode() const throw() {
438   if(isAnswer()) {
439     const Avp *resultCodeAvp = getAvp(helpers::base::AVPID__Result_Code, 1, anna::Exception::Mode::Ignore);
440
441     if(resultCodeAvp)
442       return resultCodeAvp->getUnsigned32()->getValue();
443   }
444
445   return -1;
446 }
447
448
449 //------------------------------------------------------------------------------
450 //------------------------------------------------------ Message::setFailedAvp()
451 //------------------------------------------------------------------------------
452 void Message::setFailedAvp(const parent_t &parent, AvpId wrong, const char *wrongName) throw(anna::RuntimeException) {
453
454   if(isRequest()) return;
455
456 // RFC 6733:
457 //
458 //  7.5.  Failed-AVP AVP
459 //
460 //     The Failed-AVP AVP (AVP Code 279) is of type Grouped and provides
461 //     debugging information in cases where a request is rejected or not
462 //     fully processed due to erroneous information in a specific AVP.  The
463 //     value of the Result-Code AVP will provide information on the reason
464 //     for the Failed-AVP AVP.  A Diameter answer message SHOULD contain an
465 //     instance of the Failed-AVP AVP that corresponds to the error
466 //     indicated by the Result-Code AVP.  For practical purposes, this
467 //     Failed-AVP would typically refer to the first AVP processing error
468 //     that a Diameter node encounters.
469
470   // Although the Failed-AVP definition has cardinality 1* and Failed-AVP itself is defined in
471   // most of the command codes as *[Failed-AVP], i think this is not a deliberate ambiguity.
472   // Probably the RFC wants to give freedom to the application layer, but it is recommended to
473   // have only one child (wrong avp) inside a unique message Failed-AVP to ease the Result-Code
474   // correspondence. Anyway, this behaviour could be easily  opened by mean 'setSingleFailedAVP(false)'
475   Avp *theFailedAvp = getAvp(helpers::base::AVPID__Failed_AVP, 1, anna::Exception::Mode::Ignore);
476   if (theFailedAvp) {
477     if (getEngine()->getSingleFailedAVP()) {
478       LOGDEBUG(anna::Logger::debug("Failed-AVP has already been added. RFC 6733 Section 7.5 recommends to store only the first error found", ANNA_FILE_LOCATION));
479       return;
480     }
481   }
482
483   // Section 7.5 RFC 6733: A Diameter message SHOULD contain one Failed-AVP AVP
484   theFailedAvp = addAvp(helpers::base::AVPID__Failed_AVP);
485   Avp *leaf = theFailedAvp;
486
487   LOGDEBUG(
488     std::string msg = "Adding to Failed-AVP, the wrong avp ";
489     msg += wrongName ? wrongName : (anna::diameter::functions::avpIdAsPairString(wrong));
490     msg += " found inside ";
491     msg += parent.asString();
492
493     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
494   );
495
496   std::vector<AvpId>::const_iterator it;
497   for(it = parent.AvpsId.begin(); it != parent.AvpsId.end(); it++)
498         leaf = leaf->addAvp(*it);
499
500   leaf->addAvp(wrong);
501 }
502
503
504 //------------------------------------------------------------------------------
505 //----------------------------------------------- Message::setStandardToAnswer()
506 //------------------------------------------------------------------------------
507 void Message::setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode) throw() {
508   if(!request.getId().second) return;
509
510   // Message header:
511   setHeaderToAnswer(request);
512   // Session-Id if exists:
513   const Avp *reqSessionId = request.getAvp(helpers::base::AVPID__Session_Id, 1, anna::Exception::Mode::Ignore);
514
515   if(reqSessionId)
516         if(!getAvp(helpers::base::AVPID__Session_Id, 1, anna::Exception::Mode::Ignore))
517       addAvp(helpers::base::AVPID__Session_Id)->getUTF8String()->setValue(reqSessionId->getUTF8String()->getValue());
518
519   // Origin-Host & Realm
520   if(!getAvp(helpers::base::AVPID__Origin_Host, 1, anna::Exception::Mode::Ignore))
521     addAvp(helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(originHost);
522
523   if(!getAvp(helpers::base::AVPID__Origin_Realm, 1, anna::Exception::Mode::Ignore))
524     addAvp(helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(originRealm);
525
526   // Proxy-Info AVPs if exist, in the same order:
527   for(const_avp_iterator it = request.avp_begin(); it != request.avp_end(); it++)
528     if((*it).second->getId() == helpers::base::AVPID__Proxy_Info)
529       addAvp((*it).second);
530
531   // If no Result-Code was added is because all was ok, then application could detect another problem:
532   setResultCode(resultCode);
533   // Fix:
534   fix();
535   LOGDEBUG(
536     std::string msg = "Completed answer:\n";
537     msg += asXMLString();
538     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
539   );
540 }
541
542
543 //------------------------------------------------------------------------------
544 //--------------------------------------------------------------- Message::fix()
545 //------------------------------------------------------------------------------
546 void Message::fix() throw() {
547   // Dictionary stack command:
548   const stack::Command *stackCommand = getStackCommand();
549
550   if(!stackCommand) {
551     LOGDEBUG(anna::Logger::debug("No dictionary command reference found. Cannot fix.", ANNA_FILE_LOCATION));
552     // Try to get to the first place the Session-ID (if exists) because...
553     // RFC 6733: All messages pertaining to a specific session MUST include only one Session-Id AVP ...
554     //           ... When present, the Session-Id SHOULD appear immediately following the Diameter header
555     avp_iterator it = Avp::avp_find(a_avps, helpers::base::AVPID__Session_Id, 1 /* one and only */);
556
557     if(it != avp_end()) {
558       int sessionPos = (*it).first;
559       Avp *first = (*avp_begin()).second;
560       a_avps[0] = (*it).second; // Session-Id
561       a_avps[sessionPos] = first;
562       LOGDEBUG(anna::Logger::debug("Session-Id has been manually fixed to the first place", ANNA_FILE_LOCATION));
563     }
564
565     return;
566   }
567
568   Avp::fix(a_avps, (find_container&)a_finds, a_insertionPositionForChilds, stackCommand->avprule_begin(), stackCommand->avprule_end());
569 }
570
571
572 //------------------------------------------------------------------------------
573 //------------------------------------------------------------- Message::valid()
574 //------------------------------------------------------------------------------
575 bool Message::valid(Message *ptrAnswer) const throw(anna::RuntimeException) {
576   // OAM
577   OamModule &oamModule = OamModule::instantiate();
578   // Dictionary stack command:
579   const stack::Command *stackCommand = getStackCommand();
580   // Only build answer for a request:
581   Message *answer = isRequest() ? ptrAnswer : NULL;
582
583   if(answer) answer->setHeaderToAnswer(*this);
584
585   if(!stackCommand) {
586     // OAM
587     std::string me = anna::diameter::functions::commandIdAsPairString(a_id);
588     oamModule.activateAlarm(OamModule::Alarm::MessageValidation__UnknownOperation__s__UnableToValidate, STRING_WITH_QUOTATION_MARKS__C_STR(me));
589     oamModule.count(OamModule::Counter::MessageValidation__UnknownOperationUnableToValidate);
590
591     if(answer) answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_COMMAND_UNSUPPORTED);
592
593     getEngine()->validationAnomaly(anna::functions::asString("Unknown operation %s. Unable to validate", STRING_WITH_QUOTATION_MARKS__C_STR(me)));
594     return false;
595   }
596
597   // Parent information:
598   parent_t me;
599   me.setMessage(a_id, stackCommand->getName().c_str());
600
601   //////////////////////////////
602   // Flags coherence checking //
603   //////////////////////////////
604   int rc;
605   bool result = flagsOK(rc);
606
607   if(!result) {
608     // OAM & Depth management
609     oamModule.activateAlarm(OamModule::Alarm::MessageValidation__Operation__s__HaveIncoherentFlags__d__, STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags);
610     oamModule.count(OamModule::Counter::MessageValidation__OperationHaveIncoherentFlags);
611
612     if(answer) answer->setResultCode(rc);
613
614     getEngine()->validationAnomaly(anna::functions::asString("Operation %s have incoherent flags (%d)", STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags));
615   }
616
617   ////////////////////
618   // Level checking //
619   ////////////////////
620   result = Avp::validLevel(a_avps, stackCommand->avprule_begin(), stackCommand->avprule_end(), getEngine(), me, answer) && result;
621
622   ////////////////////////
623   // Childrens checking //
624   ////////////////////////
625   for(const_avp_iterator it = avp_begin(); it != avp_end(); it++)
626     result = ((*it).second->valid(me, answer)) && result;
627
628   return result;
629 }
630
631
632 //------------------------------------------------------------------------------
633 //-------------------------------------------------------------- Message::code()
634 //------------------------------------------------------------------------------
635 const anna::DataBlock & Message::code() throw(anna::RuntimeException) {
636   // Pre-Validation
637   Engine::ValidationMode::_v vmode = getEngine()->getValidationMode();
638
639   if((vmode == Engine::ValidationMode::BeforeEncoding) || (vmode == Engine::ValidationMode::Always)) {
640     if(!valid())
641       throw anna::RuntimeException("Try to encode an invalid message. See previous report on warning-level traces", ANNA_FILE_LOCATION);
642   }
643
644   // Pre-Fixing
645   Engine::FixMode::_v fmode = getEngine()->getFixMode();
646
647   if((fmode == Engine::FixMode::BeforeEncoding) || (fmode == Engine::FixMode::Always)) fix();
648
649   // Trace
650   LOGDEBUG(
651     std::string trace = "Message to code:\n";
652     trace += asXMLString();
653     anna::Logger::debug(trace, ANNA_FILE_LOCATION);
654   );
655   // Memory allocation
656   U24 length = getLength();
657   a_forCode.clear();
658   a_forCode.allocate(length);
659   char* buffer = (char*)a_forCode.getData();
660   // Version and length
661   buffer[0] = (S8) a_version;
662   buffer[1] = (S8)(length >> 16);
663   buffer[2] = (S8)(length >> 8);
664   buffer[3] = (S8) length;
665   // Flags and code
666   buffer[4] = (S8) a_flags;
667   buffer[5] = (S8)(a_id.first >> 16);
668   buffer[6] = (S8)(a_id.first >> 8);
669   buffer[7] = (S8) a_id.first;
670   // Application Id
671   buffer[8] = (S8)(a_applicationId >> 24);
672   buffer[9] = (S8)(a_applicationId >> 16);
673   buffer[10] = (S8)(a_applicationId >> 8);
674   buffer[11] = (S8) a_applicationId;
675   // Hob by hop
676   buffer[12] = (S8)(a_hopByHop >> 24);
677   buffer[13] = (S8)(a_hopByHop >> 16);
678   buffer[14] = (S8)(a_hopByHop >> 8);
679   buffer[15] = (S8) a_hopByHop;
680   // End to end
681   buffer[16] = (S8)(a_endToEnd >> 24);
682   buffer[17] = (S8)(a_endToEnd >> 16);
683   buffer[18] = (S8)(a_endToEnd >> 8);
684   buffer[19] = (S8) a_endToEnd;
685   // Data start position:
686   int startDataPos = HeaderLength;
687
688   if(startDataPos == length) {
689     LOGDEBUG(anna::Logger::debug("There is no Avps to encode (only-header message)", ANNA_FILE_LOCATION));
690   } else {
691     // Data part:
692     S8 * dataPart = buffer + startDataPos;
693     int dataBytes; // not used but could be useful for checking (length - startDataPos)
694     // Each avp encoding will remain padding octets depending on format. In order to
695     //  code avps colection (each avp will be multiple of 4) we clean the entire buffer
696     //  to ensure padding (easier than custom-made for each format):
697     memset(dataPart, 0, length - startDataPos); // no estoy seguro de que el clear del DataBlock haga esto...
698
699     for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
700       Avp::avp(it)->code(dataPart, dataBytes);
701       dataPart = dataPart + 4 * REQUIRED_WORDS(dataBytes);
702     }
703   }
704
705   // Trace
706   LOGDEBUG(
707     std::string trace = "DataBlock encoded:\n";
708     trace += a_forCode.asString();
709 //      trace += "\nAs continuous hexadecimal string:\n";
710 //      trace += anna::functions::asHexString(a_forCode);
711     anna::Logger::debug(trace, ANNA_FILE_LOCATION);
712   );
713   return a_forCode;
714 }
715
716
717 //------------------------------------------------------------------------------
718 //----------------------------------------------------- Message::fromXMLString()
719 //------------------------------------------------------------------------------
720 void Message::fromXMLString(const std::string &xmlString) throw(anna::RuntimeException) {
721   LOGDEBUG(anna::Logger::debug("Reading diameter message from xml string representation", ANNA_FILE_LOCATION));
722   anna::xml::DocumentMemory xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy)
723   const anna::xml::Node *rootNode;
724   xmlDocument.initialize(xmlString.c_str());
725   rootNode = xmlDocument.parse(getEngine()->getDTD()); // Parsing: fail here if xml violates dtd
726   LOGDEBUG(anna::Logger::debug("Read OK from XML string representation", ANNA_FILE_LOCATION));
727   fromXML(rootNode);
728 }
729
730
731 //------------------------------------------------------------------------------
732 //----------------------------------------------------------- Message::fromXML()
733 //------------------------------------------------------------------------------
734 void Message::fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeException) {
735   // <!ATTLIST message version CDATA #IMPLIED name CDATA #IMPLIED code CDATA #IMPLIED flags CDATA #IMPLIED p-bit (yes | no) #IMPLIED e-bit (yes | no) #IMPLIED t-bit (yes | no) #IMPLIED application-id CDATA #REQUIRED hop-by-hop-id CDATA #IMPLIED end-by-end-id CDATA #IMPLIED>
736   const anna::xml::Attribute *version, *name, *code, *flags, *pbit, *ebit, *tbit, *appid, *hbh, *ete;
737   version = messageNode->getAttribute("version", false /* no exception */);
738   name = messageNode->getAttribute("name", false /* no exception */);
739   code = messageNode->getAttribute("code", false /* no exception */);
740   flags = messageNode->getAttribute("flags", false /* no exception */);
741   pbit = messageNode->getAttribute("p-bit", false /* no exception */);
742   ebit = messageNode->getAttribute("e-bit", false /* no exception */);
743   tbit = messageNode->getAttribute("t-bit", false /* no exception */);
744   appid = messageNode->getAttribute("application-id"); // required
745   hbh = messageNode->getAttribute("hop-by-hop-id", false /* no exception */);
746   ete = messageNode->getAttribute("end-by-end-id", false /* no exception */);
747   int i_aux;
748   unsigned int u_aux;
749
750   // Clear the message
751   clear();
752
753   if(version) {
754     i_aux = version->getIntegerValue();
755
756     if(i_aux < 0 || i_aux > 256) {
757       std::string msg = "Error processing avp <version '"; msg += version->getValue();
758       msg += "': out of range [0,256]";
759       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
760     }
761
762     a_version = i_aux;
763   }
764
765   // Application-id
766   // This is called before any operation which needs to know about the stack elements (this could set the dictionary)
767   setApplicationId(appid->getIntegerValue());
768
769   // Dictionary
770   const stack::Dictionary * dictionary = getEngine()->getDictionary();
771   const stack::Command *stackCommand = NULL;
772
773   // Compact mode
774   if(name) {
775     if(!dictionary) {
776       std::string msg = "Error processing command <name '"; msg += name->getValue();
777       msg += "'>: no dictionary available. Load one or use <'code' + 'flags'> instead of <'name'>";
778       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
779     }
780
781     stackCommand = dictionary->getCommand(name->getValue());
782
783     if(!stackCommand) {
784       std::string msg = "Error processing command <name '"; msg += name->getValue();
785       msg += "'>: no command found for this identifier at available dictionary";
786       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
787     }
788   }
789
790   // Check attributes exclusiveness
791   if(name) {  // compact mode
792     if(code || flags) {
793       std::string msg = "Error processing command <name '"; msg += name->getValue();
794       msg += "'>: message attributes <'code' + 'flags'> are not allowed if <'name'> is provided";
795       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
796     }
797
798     setId(stackCommand->getId(), false /* don't clear */);
799     // 'P', 'E' and 'T' flags:
800     bool activateP = pbit ? (pbit->getValue() == "yes") : false;
801     bool activateE = ebit ? (ebit->getValue() == "yes") : false;
802     bool activateT = tbit ? (tbit->getValue() == "yes") : false;
803
804     if(activateP) a_flags |= PBitMask;
805
806     if(activateE) a_flags |= EBitMask;
807
808     if(activateT) a_flags |= TBitMask;
809   } else {
810     std::string s_code = code ? code->getValue() : "?";
811     std::string s_flags = flags ? flags->getValue() : "?";
812
813     if(!code || !flags) {
814       std::string msg = "Error processing command <code '"; msg += s_code;
815       msg += "' + flags '"; msg += s_flags;
816       msg += "'>: both must be provided if <'name'> don't";
817       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
818     }
819
820     if(pbit || ebit || tbit) {
821       std::string msg = "Error processing command <code '"; msg += s_code;
822       msg += "' + flags '"; msg += s_flags;
823       msg += "'>: neither of 'p-bit', 'e-bit' or 't-bit' fields are allowed if those are present";
824       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
825     }
826
827     // Code check
828     i_aux = code->getIntegerValue();
829
830     if(i_aux < 0) {
831       std::string msg = "Error processing command <code '"; msg += s_code;
832       msg += "': negative values are not allowed";
833       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
834     }
835
836     U24 u_code = i_aux;
837     // Flags check
838     i_aux = flags->getIntegerValue();
839
840     if(i_aux < 0 || i_aux > 256) {
841       std::string msg = "Error processing command <flags '"; msg += s_flags;
842       msg += "': out of range [0,256]";
843       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
844     }
845
846     a_flags = i_aux;
847     int flagsBCK = a_flags;
848     // Final assignments
849     a_id = CommandId(u_code, requestBit() /* based on a_flags */);
850     // Flags could have been updated regarding dictionary, but during parsing we must respect xml file:
851     a_flags = flagsBCK;
852   }
853
854   // Hob-by-hop-id
855   if(hbh) {
856     u_aux = hbh->getIntegerValue();
857
858     /*
859     if(u_aux < 0) {
860       std::string msg = "Error processing command <hop-by-hop-id '"; msg += hbh->getValue();
861       msg += "': negative values are not allowed";
862       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
863     }
864     */
865   } else u_aux = 0;
866
867   setHopByHop(u_aux);
868
869   // End-to-end-id
870   if(ete) {
871     u_aux = ete->getIntegerValue();
872
873     /*
874     if(u_aux < 0) {
875       std::string msg = "Error processing command <end-to-end-id '"; msg += ete->getValue();
876       msg += "': negative values are not allowed";
877       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
878     }
879     */
880   } else u_aux = 0;
881
882   setEndToEnd(u_aux);
883   // Childrens
884   Avp *avp;
885
886   for(anna::xml::Node::const_child_iterator it = messageNode->child_begin(); it != messageNode->child_end(); it++) {
887     std::string nodeName = (*it)->getName();
888
889     if(nodeName != "avp") {
890       std::string msg = "Unsupported message child node name '"; msg += nodeName;
891       msg += "': use 'avp'";
892       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
893     }
894
895     try {
896       avp =  getEngine()->createAvp(NULL);
897       avp -> fromXML(*it);
898     } catch(anna::RuntimeException &ex) {
899       getEngine()->releaseAvp(avp);
900       throw ex;
901     }
902
903     addAvp(avp);
904   }
905 }
906
907
908 //------------------------------------------------------------------------------
909 //----------------------------------------------------------- Message::loadXML()
910 //------------------------------------------------------------------------------
911 void Message::loadXML(const std::string & xmlPathFile) throw(anna::RuntimeException) {
912   LOGDEBUG(
913     std::string trace = "Loading diameter message from file '";
914     trace += xmlPathFile;
915     trace += "'";
916     anna::Logger::debug(trace, ANNA_FILE_LOCATION);
917   );
918   anna::xml::DocumentFile xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy)
919   const anna::xml::Node *rootNode;
920   xmlDocument.initialize(xmlPathFile.c_str()); // fail here is i/o error
921   rootNode = xmlDocument.parse(getEngine()->getDTD()); // Parsing: fail here if xml violates dtd
922   LOGDEBUG(
923     std::string trace = "Loaded XML file (";
924     trace += xmlPathFile;
925     trace += "):\n";
926     trace += anna::xml::Compiler().apply(rootNode);
927     anna::Logger::debug(trace, ANNA_FILE_LOCATION);
928   );
929   fromXML(rootNode);
930 }
931
932
933 //------------------------------------------------------------------------------
934 //------------------------------------------------------------- Message::asXML()
935 //------------------------------------------------------------------------------
936 anna::xml::Node* Message::asXML(anna::xml::Node* parent) const throw() {
937   // <!ATTLIST message version CDATA #IMPLIED name CDATA #IMPLIED code CDATA #IMPLIED flags CDATA #IMPLIED application-id CDATA #REQUIRED hop-by-hop-id CDATA #IMPLIED end-by-end-id CDATA #IMPLIED>
938   anna::xml::Node* result = parent->createChild("message");
939   // Dictionary stack command:
940   const stack::Command *stackCommand = getStackCommand();
941   bool compactMode = stackCommand /*&& flagsOK()*/;
942   result->createAttribute("version", anna::functions::asString((int)a_version));
943
944   if(compactMode) {
945     result->createAttribute("name", stackCommand->getName());
946
947     if(proxiableBit()) result->createAttribute("p-bit", "yes");
948
949     if(errorBit()) result->createAttribute("e-bit", "yes");
950
951     if(potentiallyReTransmittedMessageBit()) result->createAttribute("t-bit", "yes");
952   } else {
953     result->createAttribute("code", a_id.first);
954     result->createAttribute("flags", (int)a_flags);
955   }
956
957   result->createAttribute("application-id", anna::functions::asString(a_applicationId));
958   result->createAttribute("hop-by-hop-id", anna::functions::asString(a_hopByHop));
959   result->createAttribute("end-by-end-id", anna::functions::asString(a_endToEnd));
960
961   // Avps:
962   for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
963     Avp::avp(it)->asXML(result);
964   }
965
966   return result;
967 }
968
969
970 //------------------------------------------------------------------------------
971 //------------------------------------------------------- Message::asXMLString()
972 //------------------------------------------------------------------------------
973 std::string Message::asXMLString() const throw() {
974   anna::xml::Node root("root");
975   return anna::xml::Compiler().apply(asXML(&root));
976 }
977
978
979 //------------------------------------------------------------------------------
980 //------------------------------------------------------------ Message::isLike()
981 //------------------------------------------------------------------------------
982 bool Message::isLike(const std::string &pattern) const throw() {
983   anna::RegularExpression re(pattern);
984   return re.isLike(asXMLString());
985 }