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