20a02570fb98e7fd936b19411abd800539aa53aa
[anna.git] / source / diameter / helpers / base / functions.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/helpers/defines.hpp>
11 #include <anna/diameter/helpers/base/defines.hpp>
12 #include <anna/diameter/helpers/base/functions.hpp>
13 #include <anna/diameter/codec/Message.hpp>
14 #include <anna/diameter/codec/functions.hpp>
15 #include <anna/config/defines.hpp> // general types, decoding helpers (DECODE[2/3/4]BYTES_INDX_VALUETYPE), etc.
16
17 #include <anna/core/functions.hpp>
18 #include <anna/core/DataBlock.hpp>
19 #include <anna/core/util/Tokenizer.hpp>
20
21 // STL
22 #include <string>
23
24 using namespace anna;
25 using namespace anna::diameter::codec;
26 using namespace anna::diameter::helpers::base;
27
28 // getters
29 U32 anna::diameter::helpers::base::functions::getResultCode(const anna::DataBlock & db) throw(anna::RuntimeException) {
30   if(db.getSize() < Message::HeaderLength)
31     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
32
33   //anna::DataBlock avpsDB(db.getData() + Message::HeaderLength, db.getSize() - Message::HeaderLength);
34   //const char * resultCodePtr = anna::diameter::codec::functions::findAVP(avpsDB, AVPID__Result_Code);
35
36   const char *avpsDB = db.getData() + Message::HeaderLength;
37   int avpsLen = db.getSize() - Message::HeaderLength;
38   const char * resultCodePtr = anna::diameter::codec::functions::findAVP(avpsDB, avpsLen, AVPID__Result_Code);
39
40   if(resultCodePtr == NULL)
41     throw anna::RuntimeException("Result-Code AVP not found in DataBlock provided", ANNA_FILE_LOCATION);
42
43   // Decoded avp information:
44   AvpId _id;
45   char _flags;
46   int _length;
47   std::string _data;
48   anna::diameter::codec::functions::decodeAVP(resultCodePtr, _id, _flags, _length, _data);
49   // Result:
50   U32 result = DECODE4BYTES_INDX_VALUETYPE(_data, 0, U32);
51   return result;
52 }
53
54
55
56 void anna::diameter::helpers::base::functions::decodeSessionId(const std::string &sessionId,
57     std::string &diameterIdentity, U32 &high, U32 &low, std::string &optional) throw(anna::RuntimeException) {
58 // RFC 3588:
59 //
60 //      8.8.  Session-Id AVP
61 //
62 //         The Session-Id AVP (AVP Code 263) is of type UTF8String and is used
63 //         to identify a specific session (see Section 8).  All messages
64 //         pertaining to a specific session MUST include only one Session-Id AVP
65 //         and the same value MUST be used throughout the life of a session.
66 //         When present, the Session-Id SHOULD appear immediately following the
67 //         Diameter Header (see Section 3).
68 //
69 //         The Session-Id MUST be globally and eternally unique, as it is meant
70 //         to uniquely identify a user session without reference to any other
71 //         information, and may be needed to correlate historical authentication
72 //         information with accounting information.  The Session-Id includes a
73 //         mandatory portion and an implementation-defined portion; a
74 //         recommended format for the implementation-defined portion is outlined
75 //         below.
76 //
77 //         The Session-Id MUST begin with the sender's identity encoded in the
78 //         DiameterIdentity type (see Section 4.4).  The remainder of the
79 //         Session-Id is delimited by a ";" character, and MAY be any sequence
80 //         that the client can guarantee to be eternally unique; however, the
81 //         following format is recommended, (square brackets [] indicate an
82 //         optional element):
83 //
84 //         <DiameterIdentity>;<high 32 bits>;<low 32 bits>[;<optional value>]
85 //
86 //         <high 32 bits> and <low 32 bits> are decimal representations of the
87 //         high and low 32 bits of a monotonically increasing 64-bit value.  The
88 //         64-bit value is rendered in two part to simplify formatting by 32-bit
89 //         processors.  At startup, the high 32 bits of the 64-bit value MAY be
90 //         initialized to the time, and the low 32 bits MAY be initialized to
91 //         zero.  This will for practical purposes eliminate the possibility of
92 //         overlapping Session-Ids after a reboot, assuming the reboot process
93 //         takes longer than a second.  Alternatively, an implementation MAY
94 //         keep track of the increasing value in non-volatile memory.
95 //
96 //         <optional value> is implementation specific but may include a modem's
97 //         device Id, a layer 2 address, timestamp, etc.
98 //
99 //         Example, in which there is no optional value:
100 //            accesspoint7.acme.com;1876543210;523
101 //
102 //         Example, in which there is an optional value:
103 //            accesspoint7.acme.com;1876543210;523;mobile@200.1.1.88
104 //
105 //         The Session-Id is created by the Diameter application initiating the
106 //         session, which in most cases is done by the client.  Note that a
107 //         Session-Id MAY be used for both the authorization and accounting
108 //         commands of a given application.
109   anna::Tokenizer sid;
110   sid.apply(sessionId, ";");
111
112   if(sid.size() < 3)
113     throw anna::RuntimeException("Session-Id AVP has wrong format: at least three semicolons ';' must be included", ANNA_FILE_LOCATION);
114
115   anna::Tokenizer::const_iterator tok_min(sid.begin());
116   anna::Tokenizer::const_iterator tok_max(sid.end());
117   anna::Tokenizer::const_iterator tok_iter = tok_min;
118   diameterIdentity = anna::Tokenizer::data(tok_iter); tok_iter++;
119   std::string s_high = anna::Tokenizer::data(tok_iter); tok_iter++;
120   std::string s_low = anna::Tokenizer::data(tok_iter); tok_iter++;
121   optional = ((tok_iter != tok_max) ? (anna::Tokenizer::data(tok_iter)) : "");
122   high = (U32)atoi(s_high.c_str());
123   low = (U32)atoi(s_low.c_str());
124 }
125
126
127 std::string anna::diameter::helpers::base::functions::getSessionId(const anna::DataBlock & db,
128     std::string &diameterIdentity, U32 &high, U32 &low, std::string &optional) throw(anna::RuntimeException) {
129   if(db.getSize() < Message::HeaderLength)
130     throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION);
131
132   //anna::DataBlock avpsDB(db.getData() + Message::HeaderLength, db.getSize() - Message::HeaderLength);
133   //const char * sessionIdPtr = anna::diameter::codec::functions::findAVP(avpsDB, AVPID__Session_Id);
134   const char *avpsDB = db.getData() + Message::HeaderLength;
135   int avpsLen = db.getSize() - Message::HeaderLength;
136   const char * sessionIdPtr = anna::diameter::codec::functions::findAVP(avpsDB, avpsLen, AVPID__Session_Id);
137
138
139   if(sessionIdPtr == NULL)
140     throw anna::RuntimeException("Session-Id AVP not found in DataBlock provided", ANNA_FILE_LOCATION);
141
142   // Decoded avp information:
143   AvpId _id;
144   char _flags;
145   int _length;
146   std::string result;
147   anna::diameter::codec::functions::decodeAVP(sessionIdPtr, _id, _flags, _length, result);
148   // Aditional helper data:
149   decodeSessionId(result.c_str(), diameterIdentity, high, low, optional);
150   return result;
151 }
152