[22] | 1 | #include <arpa/inet.h> |
---|
| 2 | #include "gen_classes.h" |
---|
| 3 | |
---|
| 4 | namespace t3devlib { namespace gen { |
---|
| 5 | |
---|
| 6 | // ISUP codec |
---|
| 7 | |
---|
| 8 | // ISUP is going to be difficult to encode and decode for the following reasons: |
---|
| 9 | // • the bit order for the transmission is reversed: the LSB is sent first. |
---|
| 10 | // This will cause some difficulties since the order of the fields in the |
---|
| 11 | // TTCN-3 types follows the order of transmission, not the order in memory |
---|
| 12 | // (note that there are lots of fields that are less than 8-bit long). |
---|
| 13 | // Consequently the codec generator cannot be used directly to |
---|
| 14 | // encode/decode the message (since it processes the order of the buffer in |
---|
| 15 | // the memory order -> MSB first) |
---|
| 16 | // • numeric fields that span across multiple bytes are not always encoded in |
---|
| 17 | // the same order |
---|
| 18 | // ∘ eg. the 'Network Number Indicator' and the 'Network Identity' are both |
---|
| 19 | // encoded in DCB but the digits are not ordered in the same way: |
---|
| 20 | // ‣ the NNI 1234 is encoded as "\x21\x43" |
---|
| 21 | // ‣ the NI 1234 is encoded as "\x12\x34" |
---|
| 22 | // ∘ for some fields the byte order is not given: eg. |
---|
| 23 | // • Call Identity in the Call Reference parameter |
---|
| 24 | // • Diagnostics in the Cause Indicator parameter |
---|
| 25 | // • Local Reference in the Connection request parameter |
---|
| 26 | // ‣ -> in which order is it assumed to be in the test suite ? |
---|
| 27 | // ‣ when the order is given, then the Most Signifiant Byte comes first |
---|
| 28 | // -> then we should assume that this is the default order |
---|
| 29 | // |
---|
| 30 | // Design strategy |
---|
| 31 | // |
---|
| 32 | // Knowing that ISUP messages are a concatenation of a lot of small fields |
---|
| 33 | // (less than 8 bit), the coding/decoding task will be complex since it will |
---|
| 34 | // be necessary to align correctly each field. Then care about the order of |
---|
| 35 | // the bits. |
---|
| 36 | // |
---|
| 37 | // Some consideration should be taken to ease the work |
---|
| 38 | // • The two issues above should be handled separately: one part of the codec |
---|
| 39 | // will deal with the concatenation/alignment of fields and the other one |
---|
| 40 | // will deal with the order of the bits in the fields. |
---|
| 41 | // • For all the alignement/concatenation requirements, we should rely on the |
---|
| 42 | // capabilities of the codec generator. It has already been validated for |
---|
| 43 | // such a task. In order to handle the fields in the same order as in the |
---|
| 44 | // transmission, it will be necessary to reverse the order of the bits in |
---|
| 45 | // the whole buffer before decoding and after encoding. After decoding and |
---|
| 46 | // before encoding, it will also be necessary to reverse the bits an all |
---|
| 47 | // the fields and sub-fields in the TTCN-3 structure. However since this |
---|
| 48 | // order differs from one field to another, it better to merge this part |
---|
| 49 | // with the next task below. |
---|
| 50 | // • The second part of the codec is to order the bits in the field correctly |
---|
| 51 | // according to the properties of the field being encoded/decoded. There |
---|
| 52 | // are some general rules, but lots of fields will have to be handled on a |
---|
| 53 | // case per case basis. |
---|
| 54 | |
---|
| 55 | |
---|
| 56 | |
---|
| 57 | // reverse the order of the bits in the buffer between the current position |
---|
| 58 | // and the current end marker |
---|
| 59 | void buffer_reverse_remaining_bytes (Variable* var, Buffer& buffer) throw (DecodeError) |
---|
| 60 | { |
---|
| 61 | if ((buffer.GetPosition() % 8) | (buffer.GetBitsLeft() % 8)) |
---|
| 62 | throw DecodeError (var, "Unaligned data"); |
---|
| 63 | |
---|
| 64 | //TODO: optimise |
---|
| 65 | for (int i = buffer.GetPosition() ; i < buffer.GetEndMarker() ; i+=8) |
---|
| 66 | { |
---|
| 67 | unsigned char c = buffer.GetValueBin()[i/8]; |
---|
| 68 | unsigned char r = 0; |
---|
| 69 | |
---|
| 70 | for (int j=8 ; j ; j--) { |
---|
| 71 | r = (r << 1) | (c & 1); |
---|
| 72 | c = c >> 1; |
---|
| 73 | } |
---|
| 74 | buffer.Replace (i, &r, 8); |
---|
| 75 | } |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | // reverse the order of the bits in every bitstring in the message |
---|
| 79 | //TODO: reverse the octetstrings too |
---|
| 80 | void reverse_all_bitstrings (Variable& var) |
---|
| 81 | { |
---|
| 82 | switch (var.GetBaseType()) { |
---|
| 83 | case Variable::btRecord: |
---|
| 84 | case Variable::btSet: { |
---|
| 85 | RecordSet& rs = static_cast<RecordSet&> (var); |
---|
| 86 | for (int i=rs.GetSize()-1 ; i>=0 ; i--) { |
---|
| 87 | if (rs.IsPresent (i)) |
---|
| 88 | reverse_all_bitstrings (*rs.GetField(i)); |
---|
| 89 | } |
---|
| 90 | break; |
---|
| 91 | } |
---|
| 92 | case Variable::btRecordOf: |
---|
| 93 | case Variable::btSetOf: { |
---|
| 94 | RecordOfSetOf& rs = static_cast<RecordOfSetOf&> (var); |
---|
| 95 | for (int i=rs.GetSize()-1 ; i>=0 ; i--) { |
---|
| 96 | reverse_all_bitstrings (*rs.GetField(i)); |
---|
| 97 | } |
---|
| 98 | break; |
---|
| 99 | } |
---|
| 100 | case Variable::btUnion: |
---|
| 101 | reverse_all_bitstrings (*static_cast<Union&> (var).GetField()); |
---|
| 102 | break; |
---|
| 103 | |
---|
| 104 | case Variable::btBitstring: |
---|
| 105 | goto reverse_bitstring; |
---|
| 106 | |
---|
| 107 | default: |
---|
| 108 | ; |
---|
| 109 | } |
---|
| 110 | return; |
---|
| 111 | |
---|
| 112 | reverse_bitstring: |
---|
| 113 | Bitstring& bs = static_cast<Bitstring&>(var); |
---|
| 114 | |
---|
| 115 | unsigned char buff[16]; // should be big enough |
---|
| 116 | assert (bs.GetLength() < 16*8); |
---|
| 117 | |
---|
| 118 | const unsigned char* src = bs.GetValueBin(); |
---|
| 119 | unsigned char* dst = buff + (bs.GetLength() / 8); |
---|
| 120 | int k = bs.GetLength() % 8; |
---|
| 121 | |
---|
| 122 | // process pack of 8 bits |
---|
| 123 | int i; |
---|
| 124 | for (i=bs.GetLength() ; i>8 ; i-=8, src++) |
---|
| 125 | { |
---|
| 126 | unsigned char c = *src; |
---|
| 127 | |
---|
| 128 | for (int j=8 ; j ; j--) { |
---|
| 129 | if (k == 0) { |
---|
| 130 | dst--; |
---|
| 131 | k = 8; |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | *dst = (*dst >> 1) | (c & 0x80); |
---|
| 135 | c = c << 1; |
---|
| 136 | } |
---|
| 137 | } |
---|
| 138 | |
---|
| 139 | // process the remaining bits |
---|
| 140 | { |
---|
| 141 | unsigned char c = *src; |
---|
| 142 | |
---|
| 143 | for ( ; i>0 ; i--) { |
---|
| 144 | if (k == 0) { |
---|
| 145 | dst--; |
---|
| 146 | k = 8; |
---|
| 147 | } |
---|
| 148 | |
---|
| 149 | *dst = (*dst >> 1) | (c & 0x80); |
---|
| 150 | c = c << 1; |
---|
| 151 | } |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | bs.SetValueBin (buff, bs.GetLength()); |
---|
| 155 | } |
---|
| 156 | |
---|
| 157 | // read a bistring and return its value with all the bits reversed |
---|
| 158 | int get_reverse_value (const Bitstring& bs) |
---|
| 159 | { |
---|
| 160 | unsigned char buff[sizeof(uint32_t)]; // should be big enough (assume we have 32 bits for int) |
---|
| 161 | assert (bs.GetLength() < sizeof(uint32_t)*8); |
---|
| 162 | memset (buff, 0, sizeof(uint32_t)); |
---|
| 163 | |
---|
| 164 | const unsigned char* src = bs.GetValueBin(); |
---|
| 165 | unsigned char* dst = buff + (bs.GetLength() / 8); |
---|
| 166 | int k = bs.GetLength() % 8; |
---|
| 167 | |
---|
| 168 | // process pack of 8 bits |
---|
| 169 | int i; |
---|
| 170 | for (i=bs.GetLength() ; i>8 ; i-=8, src++) |
---|
| 171 | { |
---|
| 172 | unsigned char c = *src; |
---|
| 173 | |
---|
| 174 | for (int j=8 ; j ; j--) { |
---|
| 175 | if (k == 0) { |
---|
| 176 | dst--; |
---|
| 177 | k = 8; |
---|
| 178 | } |
---|
| 179 | |
---|
| 180 | *dst = (*dst >> 1) | (c & 0x80); |
---|
| 181 | c = c << 1; |
---|
| 182 | } |
---|
| 183 | } |
---|
| 184 | |
---|
| 185 | // process the remaining bits |
---|
| 186 | { |
---|
| 187 | unsigned char c = *src; |
---|
| 188 | |
---|
| 189 | for ( ; i>0 ; i--) { |
---|
| 190 | if (k == 0) { |
---|
| 191 | dst--; |
---|
| 192 | k = 8; |
---|
| 193 | } |
---|
| 194 | |
---|
| 195 | *dst = (*dst >> 1) | (c & 0x80); |
---|
| 196 | c = c << 1; |
---|
| 197 | } |
---|
| 198 | } |
---|
| 199 | |
---|
| 200 | uint32_t result = ntohl (*reinterpret_cast<uint32_t*> (buff)); |
---|
| 201 | return result >> ((sizeof(int)*8) - bs.GetLength()); |
---|
| 202 | } |
---|
| 203 | |
---|
| 204 | // map used to resolve the message type in ISUP_BICC_MSG |
---|
| 205 | class IsupMsgTypeMap |
---|
| 206 | { |
---|
| 207 | public: |
---|
| 208 | static int GetBiccField (int msg_type) |
---|
| 209 | { |
---|
| 210 | std::map<int, int>::iterator it = msInstance.mMap.find (msg_type); |
---|
| 211 | |
---|
| 212 | return (it != msInstance.mMap.end()) ? it->second : msInstance.mUnknown; |
---|
| 213 | } |
---|
| 214 | |
---|
| 215 | private: |
---|
| 216 | IsupMsgTypeMap() |
---|
| 217 | { |
---|
| 218 | mMap[1] = ISUP_BICC_MSG::id_iAM_MSG; |
---|
| 219 | |
---|
| 220 | mUnknown = ISUP_BICC_MSG::id_uNKNOWN_MSG; |
---|
| 221 | } |
---|
| 222 | |
---|
| 223 | static IsupMsgTypeMap msInstance; |
---|
| 224 | |
---|
| 225 | std::map<int, int> mMap; |
---|
| 226 | int mUnknown; |
---|
| 227 | }; |
---|
| 228 | IsupMsgTypeMap IsupMsgTypeMap::msInstance; |
---|
| 229 | |
---|
| 230 | void ISUP_BICC_MSG::PreDecode (Buffer& buffer) throw (DecodeError) |
---|
| 231 | { |
---|
| 232 | int position = buffer.GetPosition(); |
---|
| 233 | |
---|
| 234 | // read ahead one byte to get the message type |
---|
| 235 | Unsigned msg_type(8); |
---|
| 236 | msg_type.Decode (buffer); |
---|
| 237 | SetHypChosenId (IsupMsgTypeMap::GetBiccField (msg_type.GetValue())); |
---|
| 238 | |
---|
| 239 | buffer.SetPosition(position); |
---|
| 240 | } |
---|
| 241 | |
---|
| 242 | void IAM_MSG::PreDecode (Buffer& buffer) throw (DecodeError) |
---|
| 243 | { |
---|
| 244 | buffer_reverse_remaining_bytes (this, buffer); |
---|
| 245 | } |
---|
| 246 | |
---|
| 247 | void IAM_MSG::PostDecode (Buffer& buffer) throw (DecodeError) |
---|
| 248 | { |
---|
| 249 | reverse_all_bitstrings (*this); |
---|
| 250 | buffer_reverse_remaining_bytes (this, buffer); |
---|
| 251 | } |
---|
| 252 | |
---|
| 253 | void IAM_MSG::PostDecode (Buffer& buffer, DecodeError& e) throw (DecodeError) |
---|
| 254 | { |
---|
| 255 | reverse_all_bitstrings (*this); |
---|
| 256 | |
---|
| 257 | // dump the error here |
---|
| 258 | // because there is an issue w/ propagating the exceptions in t3devkit |
---|
| 259 | e.Dump (std::cerr); |
---|
| 260 | throw DecodeIgnoreMessage (this); |
---|
| 261 | } |
---|
| 262 | |
---|
| 263 | void CDN_PAR_lv::PreDecode (Buffer& buffer) throw (DecodeError) |
---|
| 264 | { |
---|
| 265 | int position = buffer.GetPosition(); |
---|
| 266 | Bit8 len; |
---|
| 267 | len.Decode(buffer); |
---|
| 268 | SetHypLength (get_reverse_value (len) * 8); |
---|
| 269 | |
---|
| 270 | buffer.SetPosition (position); |
---|
| 271 | } |
---|
| 272 | |
---|
| 273 | |
---|
| 274 | }} // namespace t3devlib::gen |
---|
| 275 | |
---|