X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=source%2Fdiameter%2Fcodec%2Ffunctions.cpp;h=f7a0060a3d494900d29bf9c5156d3d9e0525e831;hb=5a6cba5fde2b2f538a7515f8293cc0a8d9589dfa;hp=a8a6348d1b816ec4ec1f2664bf20fb1712506cc1;hpb=4e12ac57e93c052f716a6305ad8fc099c45899d1;p=anna.git diff --git a/source/diameter/codec/functions.cpp b/source/diameter/codec/functions.cpp index a8a6348..f7a0060 100644 --- a/source/diameter/codec/functions.cpp +++ b/source/diameter/codec/functions.cpp @@ -1,37 +1,9 @@ -// ANNA - Anna is Not 'N' Anymore -// -// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo -// -// https://bitbucket.org/testillano/anna -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: eduardo.ramos.testillano@gmail.com -// cisco.tierra@gmail.com +// ANNA - Anna is Not Nothingness Anymore // +// // +// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo // +// // +// See project site at http://redmine.teslayout.com/projects/anna-suite // +// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE // // Local @@ -50,71 +22,136 @@ #include -using namespace anna::diameter::codec; + +namespace anna { +namespace diameter { +namespace codec { +// Preloaded MemoryDTD for function helpers: +anna::xml::DTDMemory MessageDTDMemory(MessageDTD); +} +} +} + + +// Parent struct helper ///////////////////////////////////////////////////////////////////////////// +void anna::diameter::codec::parent::setMessage(const anna::diameter::CommandId & mid, const char *mname) { + MessageId = mid; + if (mname) { + MessageName = mname; + } + else { + MessageName = "Message"; + MessageName += anna::diameter::functions::commandIdAsPairString(mid); + } +} + +void anna::diameter::codec::parent::addAvp(const anna::diameter::AvpId & aid, const char *aname) { + AvpsId.push_back(aid); + std::string name; + if (aname) { + name = aname; + } + else { + name = "Avp"; + name += anna::diameter::functions::avpIdAsPairString(aid); + } + AvpsName.push_back(name); +} + +std::string anna::diameter::codec::parent::asString() const { // "->->...->" + std::string result = MessageName; + for (std::vector::const_iterator it = AvpsName.begin(); it != AvpsName.end(); it++) { + result += "->"; + result += (*it); + } + + return result; +} +///////////////////////////////////////////////////////////////////////////////////////////////////// // getters -anna::diameter::CommandId functions::getCommandId(const anna::DataBlock & db) throw(anna::RuntimeException) { +anna::diameter::CommandId anna::diameter::codec::functions::getCommandId(const anna::DataBlock & db) noexcept(false) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); const char * data = db.getData(); U8 flags = data[4]; U24 code = DECODE3BYTES_INDX_VALUETYPE(data, 5, U24); -// U24 code = (((U24)data[5] << 16) & 0xFF0000) + -// (((U24)data[6] << 8) & 0x00FF00) + -// (((U24)data[7]) & 0x0000FF); + // U24 code = (((U24)data[5] << 16) & 0xFF0000) + + // (((U24)data[6] << 8) & 0x00FF00) + + // (((U24)data[7]) & 0x0000FF); return (anna::diameter::CommandId(code, (flags & Message::RBitMask) != 0x00)); } - -bool functions::isRequest(const anna::DataBlock & db) throw(anna::RuntimeException) { +bool anna::diameter::codec::functions::requestBit(const anna::DataBlock & db) noexcept(false) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); return (((db.getData())[4] & Message::RBitMask) != 0x00); } -anna::diameter::ApplicationId functions::getApplicationId(const anna::DataBlock & db) throw(anna::RuntimeException) { +bool anna::diameter::codec::functions::proxiableBit(const anna::DataBlock & db) noexcept(false) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + return (((db.getData())[4] & Message::PBitMask) != 0x00); +} + +bool anna::diameter::codec::functions::errorBit(const anna::DataBlock & db) noexcept(false) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + return (((db.getData())[4] & Message::EBitMask) != 0x00); +} + +bool anna::diameter::codec::functions::potentiallyReTransmittedMessageBit(const anna::DataBlock & db) noexcept(false) { + if(db.getSize() < Message::HeaderLength) + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + + return (((db.getData())[4] & Message::TBitMask) != 0x00); +} + +anna::diameter::ApplicationId anna::diameter::codec::functions::getApplicationId(const anna::DataBlock & db) noexcept(false) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); const char * appidPtr = db.getData() + 8; anna::diameter::ApplicationId result = DECODE4BYTES_INDX_VALUETYPE(appidPtr, 0, U32); -// anna::diameter::ApplicationId result = (((U32)appidPtr[0] << 24) & 0xFF000000) + -// (((U32)appidPtr[1] << 16) & 0x00FF0000) + -// (((U32)appidPtr[2] << 8) & 0x0000FF00) + -// (((U32)appidPtr[3]) & 0x000000FF); + // anna::diameter::ApplicationId result = (((U32)appidPtr[0] << 24) & 0xFF000000) + + // (((U32)appidPtr[1] << 16) & 0x00FF0000) + + // (((U32)appidPtr[2] << 8) & 0x0000FF00) + + // (((U32)appidPtr[3]) & 0x000000FF); return result; } -anna::diameter::HopByHop functions::getHopByHop(const anna::DataBlock & db) throw(anna::RuntimeException) { +anna::diameter::HopByHop anna::diameter::codec::functions::getHopByHop(const anna::DataBlock & db) noexcept(false) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); const char * hbhPtr = db.getData() + 12; anna::diameter::HopByHop result = DECODE4BYTES_INDX_VALUETYPE(hbhPtr, 0, U32); -// anna::diameter::HopByHop result = (((U32)hbhPtr[0] << 24) & 0xFF000000) + -// (((U32)hbhPtr[1] << 16) & 0x00FF0000) + -// (((U32)hbhPtr[2] << 8) & 0x0000FF00) + -// (((U32)hbhPtr[3]) & 0x000000FF); + // anna::diameter::HopByHop result = (((U32)hbhPtr[0] << 24) & 0xFF000000) + + // (((U32)hbhPtr[1] << 16) & 0x00FF0000) + + // (((U32)hbhPtr[2] << 8) & 0x0000FF00) + + // (((U32)hbhPtr[3]) & 0x000000FF); return result; } -anna::diameter::EndToEnd functions::getEndToEnd(const anna::DataBlock & db) throw(anna::RuntimeException) { +anna::diameter::EndToEnd anna::diameter::codec::functions::getEndToEnd(const anna::DataBlock & db) noexcept(false) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); const char * etePtr = db.getData() + 16; anna::diameter::EndToEnd result = DECODE4BYTES_INDX_VALUETYPE(etePtr, 0, U32); -// anna::diameter::EndToEnd result = (((U32)etePtr[0] << 24) & 0xFF000000) + -// (((U32)etePtr[1] << 16) & 0x00FF0000) + -// (((U32)etePtr[2] << 8) & 0x0000FF00) + -// (((U32)etePtr[3]) & 0x000000FF); + // anna::diameter::EndToEnd result = (((U32)etePtr[0] << 24) & 0xFF000000) + + // (((U32)etePtr[1] << 16) & 0x00FF0000) + + // (((U32)etePtr[2] << 8) & 0x0000FF00) + + // (((U32)etePtr[3]) & 0x000000FF); return result; } -void functions::decodeCommandHeader(const char *start, char & version, U24 & length, char & flags, diameter::CommandId & id, int & appId, int & hbh, int & ete) throw(anna::RuntimeException) { +void anna::diameter::codec::functions::decodeCommandHeader(const char *start, char & version, U24 & length, char & flags, diameter::CommandId & id, int & appId, int & hbh, int & ete) noexcept(false) { if(start == NULL) throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION); @@ -148,7 +185,7 @@ void functions::decodeCommandHeader(const char *start, char & version, U24 & len ete = DECODE4BYTES_INDX_VALUETYPE(start, 16, U32); } -void functions::decodeAVP(const char *start, diameter::AvpId & id, char & flags, int & length, std::string & data) throw(anna::RuntimeException) { +void anna::diameter::codec::functions::decodeAVP(const char *start, diameter::AvpId & id, char & flags, int & length, std::string & data) noexcept(false) { if(start == NULL) throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION); @@ -175,37 +212,42 @@ void functions::decodeAVP(const char *start, diameter::AvpId & id, char & flags, const char *dataPointer = (vendorSpecific ? (start + 12) : (start + 8)); // pointer to data part data.assign(dataPointer, dataLength); LOGLOCAL3( - std::string msg = anna::functions::asString("decodedAVP id (%d,%d), length %d, data length %d, data part 0x%s", - id.first, id.second, length, dataLength, anna::functions::asHexString(anna::DataBlock(dataPointer, dataLength)).c_str()); - anna::Logger::write(anna::Logger::Local3, msg, ANNA_FILE_LOCATION); + std::string msg = anna::functions::asString("decodedAVP id (%d,%d), length %d, data length %d, data part 0x%s", + id.first, id.second, length, dataLength, anna::functions::asHexString(anna::DataBlock(dataPointer, dataLength)).c_str()); + anna::Logger::write(anna::Logger::Local3, msg, ANNA_FILE_LOCATION); ); } -const char * functions::nextAVP(const anna::DataBlock & avpsDB, const char *start) throw(anna::RuntimeException) { +const char * anna::diameter::codec::functions::nextAVP(const char *avpsDB, int avpsLen, const char *start) noexcept(false) { if(start == NULL) throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION); + if(avpsDB == NULL) + throw anna::RuntimeException("NULL provided avpsDB pointer", ANNA_FILE_LOCATION); const char *result; -// LOGDEBUG( -// std::string msg("DataBlock provided to 'nextAVP'"); -// msg += avpsDB.asString(); -// anna::Logger::debug(msg, ANNA_FILE_LOCATION); -// ); + // LOGDEBUG( + // std::string msg("DataBlock provided to 'nextAVP'"); + // msg += avpsDB.asString(); + // anna::Logger::debug(msg, ANNA_FILE_LOCATION); + // ); //int avpLength = (start[5] << 16) + (start[6] << 8) + start[7]; // AVP Length int avpLength = DECODE3BYTES_INDX_VALUETYPE(start, 5, int); result = start + 4 * REQUIRED_WORDS(avpLength); - const char * first = avpsDB.getData(); - int offset = (result - first); + int offset = (result - avpsDB); - if(offset > (avpsDB.getSize() - 1)) - //throw anna::RuntimeException("Start pointer out of boundaries for DataBlock", ANNA_FILE_LOCATION); + if(offset > (avpsLen - 1)) + //throw anna::RuntimeException("Start pointer out of boundaries for block(avpsDB, avpsLen)", ANNA_FILE_LOCATION); return NULL; // (*) return result; } -const char * functions::findAVP(const anna::DataBlock & avpsDB, const diameter::AvpId & id, int n) throw(anna::RuntimeException) { - const char * result = avpsDB.getData(); // first avp +//const char * functions::nextAVP(const anna::DataBlock & avpsDB, const char *start) noexcept(false) { +// return nextAVP(avpsDB.getData(), avpsDB.getSize(), start); +//} + +const char * anna::diameter::codec::functions::findAVP(const char *avpsDB, int avpsLen, const diameter::AvpId & id, int n) noexcept(false) { + const char *result = avpsDB; // first avp int positives = 0; // Decoded avp information: diameter::AvpId _id; @@ -217,14 +259,14 @@ const char * functions::findAVP(const anna::DataBlock & avpsDB, const diameter:: if(_id == id) positives++; while((_id != id) || (positives != n)) { // next search if not found or not ocurrence number reached - result = nextAVP(avpsDB, result); + result = nextAVP(avpsDB, avpsLen, result); if(result == NULL) { // (*) LOGDEBUG( - std::string msg = "AVP "; - msg += anna::diameter::functions::avpIdAsPairString(id); - msg += " not found at DataBlock"; - anna::Logger::debug(msg, ANNA_FILE_LOCATION); + std::string msg = "AVP "; + msg += anna::diameter::functions::avpIdAsPairString(id); + msg += " not found at DataBlock"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); return NULL; } @@ -237,14 +279,17 @@ const char * functions::findAVP(const anna::DataBlock & avpsDB, const diameter:: return result; } +//const char * functions::findAVP(const anna::DataBlock & avpsDB, const diameter::AvpId & id, int n) noexcept(false) { +// return findAVP(avpsDB.getData(), avpsDB.getSize(), id, n); +//} // modifiers -void functions::setHopByHop(anna::DataBlock & db, diameter::HopByHop hbh) throw(anna::RuntimeException) { +void anna::diameter::codec::functions::setHopByHop(anna::DataBlock & db, diameter::HopByHop hbh) noexcept(false) { if(db.getSize() < Message::HeaderLength) { throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); } - static char source[4]; + char source[4]; source[0] = (char)(hbh >> 24); source[1] = (char)(hbh >> 16); source[2] = (char)(hbh >> 8); @@ -253,12 +298,12 @@ void functions::setHopByHop(anna::DataBlock & db, diameter::HopByHop hbh) throw( } -void functions::setEndToEnd(anna::DataBlock & db, diameter::EndToEnd ete) throw(anna::RuntimeException) { +void anna::diameter::codec::functions::setEndToEnd(anna::DataBlock & db, diameter::EndToEnd ete) noexcept(false) { if(db.getSize() < Message::HeaderLength) { throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); } - static char source[4]; + char source[4]; source[0] = (char)(ete >> 24); source[1] = (char)(ete >> 16); source[2] = (char)(ete >> 8); @@ -266,4 +311,40 @@ void functions::setEndToEnd(anna::DataBlock & db, diameter::EndToEnd ete) throw( memcpy((char *)(db.getData() + 16), source, 4); } +void anna::diameter::codec::functions::setPotentiallyReTransmittedMessageBit(const anna::DataBlock & db, bool activate) noexcept(false) { + if(db.getSize() < Message::HeaderLength) { + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + } + + char flags[1]; + flags[0] = *(db.getData() + 4); + if(activate) flags[0] |= Message::TBitMask; else flags[0] &= (~Message::TBitMask); + memcpy((char *)(db.getData() + 4), flags, 1); +} +// XML parsers for diameter messages /////////////////////////////////////////////////////////////////////////// +void anna::diameter::codec::functions::messageXmlDocumentFromXmlFile(anna::xml::DocumentFile &xmlDocument, const std::string & xmlPathFile) noexcept(false) { + LOGDEBUG(anna::Logger::debug(anna::functions::asString("Parsing diameter message from xml file '%s' into xml document", xmlPathFile.c_str()), ANNA_FILE_LOCATION)); + xmlDocument.initialize(xmlPathFile.c_str()); // fail here is i/o error + const anna::xml::Node *rootNode = xmlDocument.parse(MessageDTDMemory); // Parsing: fail here if xml violates dtd + LOGDEBUG( + std::string trace = "Parsing OK from XML file '"; + trace += xmlPathFile; + trace += "':\n"; + trace += anna::xml::Compiler().apply(rootNode); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); +} + +void anna::diameter::codec::functions::messageXmlDocumentFromXmlString(anna::xml::DocumentMemory &xmlDocument, const std::string &xmlString) noexcept(false) { + LOGDEBUG(anna::Logger::debug("Parsing diameter message from xml string representation into xml document", ANNA_FILE_LOCATION)); + xmlDocument.initialize(xmlString.c_str()); + const anna::xml::Node *rootNode = xmlDocument.parse(MessageDTDMemory); // Parsing: fail here if xml violates dtd + LOGDEBUG( + std::string trace = "Parsing OK from XML string representation '"; + trace += xmlString; + trace += "':\n"; + trace += anna::xml::Compiler().apply(rootNode); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); +}