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 | |
---|