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