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