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