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