diff options
Diffstat (limited to 'toxav/toxrtp.c')
-rwxr-xr-x | toxav/toxrtp.c | 878 |
1 files changed, 878 insertions, 0 deletions
diff --git a/toxav/toxrtp.c b/toxav/toxrtp.c new file mode 100755 index 00000000..2363deea --- /dev/null +++ b/toxav/toxrtp.c | |||
@@ -0,0 +1,878 @@ | |||
1 | /** toxrtp.c | ||
2 | * | ||
3 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
4 | * | ||
5 | * This file is part of Tox. | ||
6 | * | ||
7 | * Tox is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation, either version 3 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * Tox is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
19 | * | ||
20 | * | ||
21 | * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or | ||
22 | * my email: eniz_vukovic@hotmail.com | ||
23 | */ | ||
24 | |||
25 | #ifdef HAVE_CONFIG_H | ||
26 | #include "config.h" | ||
27 | #endif /* HAVE_CONFIG_H */ | ||
28 | |||
29 | #include "toxrtp.h" | ||
30 | #include <assert.h> | ||
31 | #include <limits.h> | ||
32 | #include <pthread.h> | ||
33 | |||
34 | #include "../toxcore/util.h" | ||
35 | #include "../toxcore/network.h" | ||
36 | #include "../toxcore/net_crypto.h" | ||
37 | #include "../toxcore/Messenger.h" | ||
38 | |||
39 | #define PAYLOAD_ID_VALUE_OPUS 1 | ||
40 | #define PAYLOAD_ID_VALUE_VP8 2 | ||
41 | |||
42 | #define MAX_SEQU_NUM 65535 | ||
43 | |||
44 | #define size_32 4 | ||
45 | |||
46 | #define inline__ inline __attribute__((always_inline)) | ||
47 | |||
48 | |||
49 | #define ADD_FLAG_VERSION(_h, _v) do { ( _h->flags ) &= 0x3F; ( _h->flags ) |= ( ( ( _v ) << 6 ) & 0xC0 ); } while(0) | ||
50 | #define ADD_FLAG_PADDING(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xDF; ( _h->flags ) |= ( ( ( _v ) << 5 ) & 0x20 ); } while(0) | ||
51 | #define ADD_FLAG_EXTENSION(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xEF;( _h->flags ) |= ( ( ( _v ) << 4 ) & 0x10 ); } while(0) | ||
52 | #define ADD_FLAG_CSRCC(_h, _v) do { ( _h->flags ) &= 0xF0; ( _h->flags ) |= ( ( _v ) & 0x0F ); } while(0) | ||
53 | #define ADD_SETTING_MARKER(_h, _v) do { if ( _v > 1 ) _v = 1; ( _h->marker_payloadt ) &= 0x7F; ( _h->marker_payloadt ) |= ( ( ( _v ) << 7 ) /*& 0x80 */ ); } while(0) | ||
54 | #define ADD_SETTING_PAYLOAD(_h, _v) do { if ( _v > 127 ) _v = 127; ( _h->marker_payloadt ) &= 0x80; ( _h->marker_payloadt ) |= ( ( _v ) /* & 0x7F */ ); } while(0) | ||
55 | |||
56 | #define GET_FLAG_VERSION(_h) (( _h->flags & 0xd0 ) >> 6) | ||
57 | #define GET_FLAG_PADDING(_h) (( _h->flags & 0x20 ) >> 5) | ||
58 | #define GET_FLAG_EXTENSION(_h) (( _h->flags & 0x10 ) >> 4) | ||
59 | #define GET_FLAG_CSRCC(_h) ( _h->flags & 0x0f ) | ||
60 | #define GET_SETTING_MARKER(_h) (( _h->marker_payloadt ) >> 7) | ||
61 | #define GET_SETTING_PAYLOAD(_h) ((_h->marker_payloadt) & 0x7f) | ||
62 | |||
63 | |||
64 | |||
65 | /** | ||
66 | * @brief Checks if message came in late. | ||
67 | * | ||
68 | * @param session Control session. | ||
69 | * @param msg The message. | ||
70 | * @return int | ||
71 | * @retval -1 The message came in order. | ||
72 | * @retval 0 The message came late. | ||
73 | */ | ||
74 | inline__ int check_late_message (RTPSession* session, RTPMessage* msg) | ||
75 | { | ||
76 | /* | ||
77 | * Check Sequence number. If this new msg has lesser number then the session->rsequnum | ||
78 | * it shows that the message came in late. Also check timestamp to be 100% certain. | ||
79 | * | ||
80 | */ | ||
81 | return ( msg->header->sequnum < session->rsequnum && msg->header->timestamp < session->timestamp ) ? 0 : -1; | ||
82 | } | ||
83 | |||
84 | |||
85 | /** | ||
86 | * @brief Increases nonce value by 'target' | ||
87 | * | ||
88 | * @param nonce The nonce | ||
89 | * @param target The target | ||
90 | * @return void | ||
91 | */ | ||
92 | inline__ void increase_nonce(uint8_t* nonce, uint16_t target) | ||
93 | { | ||
94 | uint16_t _nonce_counter = ((uint16_t)( | ||
95 | (((uint16_t) nonce [crypto_box_NONCEBYTES - 1]) << 8 ) | | ||
96 | (((uint16_t) nonce [crypto_box_NONCEBYTES - 2]) ))); | ||
97 | |||
98 | /* Check overflow */ | ||
99 | if (_nonce_counter > USHRT_MAX - target ) { /* 2 bytes are not long enough */ | ||
100 | int _it = 3; | ||
101 | while ( _it <= crypto_box_NONCEBYTES ) _it += ++nonce[crypto_box_NONCEBYTES - _it] ? crypto_box_NONCEBYTES : 1; | ||
102 | |||
103 | _nonce_counter = _nonce_counter - (USHRT_MAX - target ); /* Assign the rest of it */ | ||
104 | } else { /* Increase nonce */ | ||
105 | |||
106 | _nonce_counter+= target; | ||
107 | } | ||
108 | |||
109 | /* Assign the 8 last bytes */ | ||
110 | |||
111 | nonce [crypto_box_NONCEBYTES - 1] = (uint8_t) (_nonce_counter >> 8); | ||
112 | nonce [crypto_box_NONCEBYTES - 2] = (uint8_t) (_nonce_counter); | ||
113 | } | ||
114 | |||
115 | |||
116 | /** | ||
117 | * @brief Speaks for it self. | ||
118 | * | ||
119 | */ | ||
120 | static const uint32_t payload_table[] = | ||
121 | { | ||
122 | 8000, 8000, 8000, 8000, 8000, 8000, 16000, 8000, 8000, 8000, /* 0-9 */ | ||
123 | 44100, 44100, 0, 0, 90000, 8000, 11025, 22050, 0, 0, /* 10-19 */ | ||
124 | 0, 0, 0, 0, 0, 90000, 90000, 0, 90000, 0, /* 20-29 */ | ||
125 | 0, 90000, 90000, 90000, 90000, 0, 0, 0, 0, 0, /* 30-39 */ | ||
126 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40-49 */ | ||
127 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50-59 */ | ||
128 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60-69 */ | ||
129 | PAYLOAD_ID_VALUE_OPUS, PAYLOAD_ID_VALUE_VP8, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-79 */ | ||
130 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80-89 */ | ||
131 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90-99 */ | ||
132 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 100-109 */ | ||
133 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 110-119 */ | ||
134 | 0, 0, 0, 0, 0, 0, 0, 0 /* 120-127 */ | ||
135 | }; | ||
136 | |||
137 | |||
138 | /** | ||
139 | * @brief Extracts header from payload. | ||
140 | * | ||
141 | * @param payload The payload. | ||
142 | * @param length The size of payload. | ||
143 | * @return RTPHeader* Extracted header. | ||
144 | * @retval NULL Error occurred while extracting header. | ||
145 | */ | ||
146 | RTPHeader* extract_header ( const uint8_t* payload, size_t length ) | ||
147 | { | ||
148 | if ( !payload ) { | ||
149 | return NULL; | ||
150 | } | ||
151 | |||
152 | const uint8_t* _it = payload; | ||
153 | |||
154 | RTPHeader* _retu = calloc(sizeof(RTPHeader), 1); | ||
155 | assert(_retu); | ||
156 | |||
157 | _retu->flags = *_it; ++_it; | ||
158 | |||
159 | /* This indicates if the first 2 bytes are valid. | ||
160 | * Now it my happen that this is out of order but | ||
161 | * it cuts down chances of parsing some invalid value | ||
162 | */ | ||
163 | if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ){ | ||
164 | /* Deallocate */ | ||
165 | free(_retu); | ||
166 | return NULL; | ||
167 | } | ||
168 | |||
169 | /* | ||
170 | * Added a check for the size of the header little sooner so | ||
171 | * I don't need to parse the other stuff if it's bad | ||
172 | */ | ||
173 | uint8_t _cc = GET_FLAG_CSRCC ( _retu ); | ||
174 | uint32_t _length = 12 /* Minimum header len */ + ( _cc * 4 ); | ||
175 | |||
176 | if ( length < _length ) { | ||
177 | /* Deallocate */ | ||
178 | free(_retu); | ||
179 | return NULL; | ||
180 | } | ||
181 | |||
182 | if ( _cc > 0 ) { | ||
183 | _retu->csrc = calloc ( sizeof ( uint32_t ), _cc ); | ||
184 | assert(_retu->csrc); | ||
185 | |||
186 | } else { /* But this should not happen ever */ | ||
187 | /* Deallocate */ | ||
188 | free(_retu); | ||
189 | return NULL; | ||
190 | } | ||
191 | |||
192 | |||
193 | _retu->marker_payloadt = *_it; ++_it; | ||
194 | _retu->length = _length; | ||
195 | |||
196 | _retu->timestamp = ( ( uint32_t ) * _it << 24 ) | | ||
197 | ( ( uint32_t ) * ( _it + 1 ) << 16 ) | | ||
198 | ( ( uint32_t ) * ( _it + 2 ) << 8 ) | | ||
199 | ( * ( _it + 3 ) ) ; | ||
200 | |||
201 | _it += 4; | ||
202 | |||
203 | _retu->ssrc = ( ( uint32_t ) * _it << 24 ) | | ||
204 | ( ( uint32_t ) * ( _it + 1 ) << 16 ) | | ||
205 | ( ( uint32_t ) * ( _it + 2 ) << 8 ) | | ||
206 | ( ( uint32_t ) * ( _it + 3 ) ) ; | ||
207 | |||
208 | |||
209 | size_t _x; | ||
210 | for ( _x = 0; _x < _cc; _x++ ) { | ||
211 | _it += 4; | ||
212 | _retu->csrc[_x] = ( ( uint32_t ) * _it << 24 ) | | ||
213 | ( ( uint32_t ) * ( _it + 1 ) << 16 ) | | ||
214 | ( ( uint32_t ) * ( _it + 2 ) << 8 ) | | ||
215 | ( ( uint32_t ) * ( _it + 3 ) ) ; | ||
216 | } | ||
217 | |||
218 | return _retu; | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * @brief Extracts external header from payload. Must be called AFTER extract_header()! | ||
223 | * | ||
224 | * @param payload The ITERATED payload. | ||
225 | * @param length The size of payload. | ||
226 | * @return RTPExtHeader* Extracted extension header. | ||
227 | * @retval NULL Error occurred while extracting extension header. | ||
228 | */ | ||
229 | RTPExtHeader* extract_ext_header ( const uint8_t* payload, size_t length ) | ||
230 | { | ||
231 | const uint8_t* _it = payload; | ||
232 | |||
233 | RTPExtHeader* _retu = calloc(sizeof(RTPExtHeader), 1); | ||
234 | assert(_retu); | ||
235 | |||
236 | uint16_t _ext_length = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it += 2; | ||
237 | |||
238 | if ( length < ( _ext_length * sizeof(uint32_t) ) ) { | ||
239 | return NULL; | ||
240 | } | ||
241 | |||
242 | _retu->length = _ext_length; | ||
243 | _retu->type = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it -= 2; | ||
244 | |||
245 | _retu->table = calloc(sizeof(uint32_t), _ext_length ); | ||
246 | assert(_retu->table); | ||
247 | |||
248 | uint32_t* _table = _retu->table; | ||
249 | size_t _i; | ||
250 | for ( _i = 0; _i < _ext_length; _i++ ) { | ||
251 | _it += 4; | ||
252 | _table[_i] = ( ( uint32_t ) * _it << 24 ) | | ||
253 | ( ( uint32_t ) * ( _it + 1 ) << 16 ) | | ||
254 | ( ( uint32_t ) * ( _it + 2 ) << 8 ) | | ||
255 | ( ( uint32_t ) * ( _it + 3 ) ) ; | ||
256 | } | ||
257 | |||
258 | return _retu; | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * @brief Adds header to payload. Make sure _payload_ has enough space. | ||
263 | * | ||
264 | * @param header The header. | ||
265 | * @param payload The payload. | ||
266 | * @return uint8_t* Iterated position. | ||
267 | */ | ||
268 | uint8_t* add_header ( RTPHeader* header, uint8_t* payload ) | ||
269 | { | ||
270 | uint8_t _cc = GET_FLAG_CSRCC ( header ); | ||
271 | |||
272 | uint8_t* _it = payload; | ||
273 | |||
274 | |||
275 | /* Add sequence number first */ | ||
276 | *_it = ( header->sequnum >> 8 ); ++_it; | ||
277 | *_it = ( header->sequnum ); ++_it; | ||
278 | |||
279 | *_it = header->flags; ++_it; | ||
280 | *_it = header->marker_payloadt; ++_it; | ||
281 | |||
282 | |||
283 | uint32_t _timestamp = header->timestamp; | ||
284 | *_it = ( _timestamp >> 24 ); ++_it; | ||
285 | *_it = ( _timestamp >> 16 ); ++_it; | ||
286 | *_it = ( _timestamp >> 8 ); ++_it; | ||
287 | *_it = ( _timestamp ); ++_it; | ||
288 | |||
289 | uint32_t _ssrc = header->ssrc; | ||
290 | *_it = ( _ssrc >> 24 ); ++_it; | ||
291 | *_it = ( _ssrc >> 16 ); ++_it; | ||
292 | *_it = ( _ssrc >> 8 ); ++_it; | ||
293 | *_it = ( _ssrc ); | ||
294 | |||
295 | uint32_t *_csrc = header->csrc; | ||
296 | size_t _x; | ||
297 | for ( _x = 0; _x < _cc; _x++ ) { | ||
298 | ++_it; | ||
299 | *_it = ( _csrc[_x] >> 24 ); ++_it; | ||
300 | *_it = ( _csrc[_x] >> 16 ); ++_it; | ||
301 | *_it = ( _csrc[_x] >> 8 ); ++_it; | ||
302 | *_it = ( _csrc[_x] ); | ||
303 | } | ||
304 | |||
305 | return _it; | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * @brief Adds extension header to payload. Make sure _payload_ has enough space. | ||
310 | * | ||
311 | * @param header The header. | ||
312 | * @param payload The payload. | ||
313 | * @return uint8_t* Iterated position. | ||
314 | */ | ||
315 | uint8_t* add_ext_header ( RTPExtHeader* header, uint8_t* payload ) | ||
316 | { | ||
317 | uint8_t* _it = payload; | ||
318 | |||
319 | *_it = ( header->length >> 8 ); _it++; | ||
320 | *_it = ( header->length ); _it++; | ||
321 | |||
322 | *_it = ( header->type >> 8 ); ++_it; | ||
323 | *_it = ( header->type ); | ||
324 | |||
325 | size_t x; | ||
326 | |||
327 | uint32_t* _hd_ext = header->table; | ||
328 | for ( x = 0; x < header->length; x++ ) { | ||
329 | ++_it; | ||
330 | *_it = ( _hd_ext[x] >> 24 ); ++_it; | ||
331 | *_it = ( _hd_ext[x] >> 16 ); ++_it; | ||
332 | *_it = ( _hd_ext[x] >> 8 ); ++_it; | ||
333 | *_it = ( _hd_ext[x] ); | ||
334 | } | ||
335 | |||
336 | return _it; | ||
337 | } | ||
338 | |||
339 | /** | ||
340 | * @brief Builds header from control session values. | ||
341 | * | ||
342 | * @param session Control session. | ||
343 | * @return RTPHeader* Created header. | ||
344 | */ | ||
345 | RTPHeader* build_header ( RTPSession* session ) | ||
346 | { | ||
347 | RTPHeader* _retu; | ||
348 | _retu = calloc ( sizeof * _retu, 1 ); | ||
349 | assert(_retu); | ||
350 | |||
351 | ADD_FLAG_VERSION ( _retu, session->version ); | ||
352 | ADD_FLAG_PADDING ( _retu, session->padding ); | ||
353 | ADD_FLAG_EXTENSION ( _retu, session->extension ); | ||
354 | ADD_FLAG_CSRCC ( _retu, session->cc ); | ||
355 | ADD_SETTING_MARKER ( _retu, session->marker ); | ||
356 | ADD_SETTING_PAYLOAD ( _retu, session->payload_type ); | ||
357 | |||
358 | _retu->sequnum = session->sequnum; | ||
359 | _retu->timestamp = ((uint32_t)(current_time() / 1000)); /* micro to milli */ | ||
360 | _retu->ssrc = session->ssrc; | ||
361 | |||
362 | if ( session->cc > 0 ) { | ||
363 | _retu->csrc = calloc(sizeof(uint32_t), session->cc); | ||
364 | assert(_retu->csrc); | ||
365 | |||
366 | int i; | ||
367 | |||
368 | for ( i = 0; i < session->cc; i++ ) { | ||
369 | _retu->csrc[i] = session->csrc[i]; | ||
370 | } | ||
371 | } else { | ||
372 | _retu->csrc = NULL; | ||
373 | } | ||
374 | |||
375 | _retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 ); | ||
376 | |||
377 | return _retu; | ||
378 | } | ||
379 | |||
380 | |||
381 | /** | ||
382 | * @brief Parses data into RTPMessage struct. Stores headers separately from the payload data | ||
383 | * and so the length variable is set accordingly. _sequnum_ argument is | ||
384 | * passed by the handle_packet() since it's parsed already. | ||
385 | * | ||
386 | * @param session Control session. | ||
387 | * @param sequnum Sequence number that's parsed from payload in handle_packet() | ||
388 | * @param data Payload data. | ||
389 | * @param length Payload size. | ||
390 | * @return RTPMessage* | ||
391 | * @retval NULL Error occurred. | ||
392 | */ | ||
393 | RTPMessage* msg_parse ( RTPSession* session, uint16_t sequnum, const uint8_t* data, uint32_t length ) | ||
394 | { | ||
395 | assert( length != -1); | ||
396 | |||
397 | RTPMessage* _retu = calloc(sizeof(RTPMessage), 1); | ||
398 | assert(_retu); | ||
399 | |||
400 | _retu->header = extract_header ( data, length ); /* It allocates memory and all */ | ||
401 | |||
402 | if ( !_retu->header ){ | ||
403 | free(_retu); | ||
404 | return NULL; | ||
405 | } | ||
406 | _retu->header->sequnum = sequnum; | ||
407 | |||
408 | _retu->length = length - _retu->header->length; | ||
409 | |||
410 | uint16_t _from_pos = _retu->header->length - 2 /* Since sequ num is excluded */ ; | ||
411 | |||
412 | |||
413 | if ( GET_FLAG_EXTENSION ( _retu->header ) ) { | ||
414 | _retu->ext_header = extract_ext_header ( data + _from_pos, length ); | ||
415 | if ( _retu->ext_header ){ | ||
416 | _retu->length -= ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); | ||
417 | _from_pos += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); | ||
418 | } else { | ||
419 | free (_retu->ext_header); | ||
420 | free (_retu->header); | ||
421 | free (_retu); | ||
422 | return NULL; | ||
423 | } | ||
424 | } else { | ||
425 | _retu->ext_header = NULL; | ||
426 | } | ||
427 | |||
428 | /* Get the payload */ | ||
429 | _retu->data = calloc ( sizeof ( uint8_t ), _retu->length ); | ||
430 | assert(_retu->data); | ||
431 | |||
432 | memcpy ( _retu->data, data + _from_pos, length - _from_pos ); | ||
433 | |||
434 | _retu->next = NULL; | ||
435 | |||
436 | |||
437 | if ( session && check_late_message ( session, _retu) < 0 ){ | ||
438 | session->rsequnum = _retu->header->sequnum; | ||
439 | session->timestamp = _retu->header->timestamp; | ||
440 | } | ||
441 | |||
442 | return _retu; | ||
443 | } | ||
444 | |||
445 | /** | ||
446 | * @brief Callback for networking core. | ||
447 | * | ||
448 | * @param object RTPSession object. | ||
449 | * @param ip_port Where the message comes from. | ||
450 | * @param data Message data. | ||
451 | * @param length Message length. | ||
452 | * @return int | ||
453 | * @retval -1 Error occurred. | ||
454 | * @retval 0 Success. | ||
455 | */ | ||
456 | int rtp_handle_packet ( void* object, IP_Port ip_port, uint8_t* data, uint32_t length ) | ||
457 | { | ||
458 | RTPSession* _session = object; | ||
459 | RTPMessage* _msg; | ||
460 | |||
461 | if ( !_session ) | ||
462 | return -1; | ||
463 | |||
464 | uint8_t _plain[MAX_UDP_PACKET_SIZE]; | ||
465 | |||
466 | uint16_t _sequnum = ( ( uint16_t ) data[1] << 8 ) | data[2]; | ||
467 | |||
468 | /* Clculate the right nonce */ | ||
469 | uint8_t _calculated[crypto_box_NONCEBYTES]; | ||
470 | memcpy(_calculated, _session->decrypt_nonce, crypto_box_NONCEBYTES); | ||
471 | increase_nonce ( _calculated, _sequnum ); | ||
472 | |||
473 | /* Decrypt message */ | ||
474 | int _decrypted_length = decrypt_data_symmetric( | ||
475 | (uint8_t*)_session->decrypt_key, _calculated, data + 3, length - 3, _plain ); | ||
476 | |||
477 | /* This packet is either not encrypted properly or late | ||
478 | */ | ||
479 | if ( -1 == _decrypted_length ){ | ||
480 | |||
481 | /* If this is the case, then the packet is most likely late. | ||
482 | * Try with old nonce cycle. | ||
483 | */ | ||
484 | if ( _session->rsequnum < _sequnum ) { | ||
485 | _decrypted_length = decrypt_data_symmetric( | ||
486 | (uint8_t*)_session->decrypt_key, _session->nonce_cycle, data + 3, length - 3, _plain ); | ||
487 | |||
488 | if ( !_decrypted_length ) return -1; /* This packet is not encrypted properly */ | ||
489 | |||
490 | /* Otherwise, if decryption is ok with new cycle, set new cycle | ||
491 | */ | ||
492 | } else { | ||
493 | increase_nonce ( _calculated, MAX_SEQU_NUM ); | ||
494 | _decrypted_length = decrypt_data_symmetric( | ||
495 | (uint8_t*)_session->decrypt_key, _calculated, data + 3, length - 3, _plain ); | ||
496 | |||
497 | if ( !_decrypted_length ) return -1; /* This is just an error */ | ||
498 | |||
499 | /* A new cycle setting. */ | ||
500 | memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_box_NONCEBYTES); | ||
501 | memcpy(_session->decrypt_nonce, _calculated, crypto_box_NONCEBYTES); | ||
502 | } | ||
503 | } | ||
504 | |||
505 | _msg = msg_parse ( NULL, _sequnum, _plain, _decrypted_length ); | ||
506 | |||
507 | if ( !_msg ) | ||
508 | return -1; | ||
509 | |||
510 | /* Hopefully this goes well | ||
511 | * NOTE: Is this even used? | ||
512 | */ | ||
513 | memcpy(&_msg->from, &ip_port, sizeof(tox_IP_Port)); | ||
514 | |||
515 | /* Check if message came in late */ | ||
516 | if ( check_late_message(_session, _msg) < 0 ) { /* Not late */ | ||
517 | _session->rsequnum = _msg->header->sequnum; | ||
518 | _session->timestamp = _msg->header->timestamp; | ||
519 | } | ||
520 | |||
521 | pthread_mutex_lock(&_session->mutex); | ||
522 | |||
523 | if ( _session->last_msg ) { | ||
524 | _session->last_msg->next = _msg; | ||
525 | _session->last_msg = _msg; | ||
526 | } else { | ||
527 | _session->last_msg = _session->oldest_msg = _msg; | ||
528 | } | ||
529 | |||
530 | pthread_mutex_unlock(&_session->mutex); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | |||
536 | |||
537 | /** | ||
538 | * @brief Stores headers and payload data in one container ( data ) | ||
539 | * and the length is set accordingly. Returned message is used for sending _only_. | ||
540 | * | ||
541 | * @param session The control session. | ||
542 | * @param data Payload data to send ( This is what you pass ). | ||
543 | * @param length Size of the payload data. | ||
544 | * @return RTPMessage* Created message. | ||
545 | * @retval NULL Error occurred. | ||
546 | */ | ||
547 | RTPMessage* rtp_new_message ( RTPSession* session, const uint8_t* data, uint32_t length ) | ||
548 | { | ||
549 | if ( !session ) | ||
550 | return NULL; | ||
551 | |||
552 | uint8_t* _from_pos; | ||
553 | RTPMessage* _retu = calloc(sizeof(RTPMessage), 1); | ||
554 | assert(_retu); | ||
555 | |||
556 | /* Sets header values and copies the extension header in _retu */ | ||
557 | _retu->header = build_header ( session ); /* It allocates memory and all */ | ||
558 | _retu->ext_header = session->ext_header; | ||
559 | |||
560 | |||
561 | uint32_t _total_length = length + _retu->header->length; | ||
562 | |||
563 | if ( _retu->ext_header ) { | ||
564 | _total_length += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); | ||
565 | /* Allocate Memory for _retu->_data */ | ||
566 | _retu->data = calloc ( sizeof _retu->data, _total_length ); | ||
567 | assert(_retu->data); | ||
568 | |||
569 | _from_pos = add_header ( _retu->header, _retu->data ); | ||
570 | _from_pos = add_ext_header ( _retu->ext_header, _from_pos + 1 ); | ||
571 | } else { | ||
572 | /* Allocate Memory for _retu->_data */ | ||
573 | _retu->data = calloc ( sizeof _retu->data, _total_length ); | ||
574 | assert(_retu->data); | ||
575 | |||
576 | _from_pos = add_header ( _retu->header, _retu->data ); | ||
577 | } | ||
578 | |||
579 | /* | ||
580 | * Parses the extension header into the message | ||
581 | * Of course if any | ||
582 | */ | ||
583 | |||
584 | /* Appends _data on to _retu->_data */ | ||
585 | memcpy ( _from_pos + 1, data, length ); | ||
586 | |||
587 | _retu->length = _total_length; | ||
588 | |||
589 | _retu->next = NULL; | ||
590 | |||
591 | return _retu; | ||
592 | } | ||
593 | |||
594 | |||
595 | /******************************************************************************************************************** | ||
596 | ******************************************************************************************************************** | ||
597 | ******************************************************************************************************************** | ||
598 | ******************************************************************************************************************** | ||
599 | ******************************************************************************************************************** | ||
600 | * | ||
601 | * | ||
602 | * | ||
603 | * PUBLIC API FUNCTIONS IMPLEMENTATIONS | ||
604 | * | ||
605 | * | ||
606 | * | ||
607 | ******************************************************************************************************************** | ||
608 | ******************************************************************************************************************** | ||
609 | ******************************************************************************************************************** | ||
610 | ******************************************************************************************************************** | ||
611 | ********************************************************************************************************************/ | ||
612 | |||
613 | |||
614 | |||
615 | |||
616 | |||
617 | |||
618 | |||
619 | |||
620 | |||
621 | /** | ||
622 | * @brief Release all messages held by session. | ||
623 | * | ||
624 | * @param session The session. | ||
625 | * @return int | ||
626 | * @retval -1 Error occurred. | ||
627 | * @retval 0 Success. | ||
628 | */ | ||
629 | int rtp_release_session_recv ( RTPSession* session ) | ||
630 | { | ||
631 | if ( !session ){ | ||
632 | return -1; | ||
633 | } | ||
634 | |||
635 | RTPMessage* _tmp,* _it; | ||
636 | |||
637 | pthread_mutex_lock(&session->mutex); | ||
638 | |||
639 | for ( _it = session->oldest_msg; _it; _it = _tmp ){ | ||
640 | _tmp = _it->next; | ||
641 | rtp_free_msg( session, _it); | ||
642 | } | ||
643 | |||
644 | session->last_msg = session->oldest_msg = NULL; | ||
645 | |||
646 | pthread_mutex_unlock(&session->mutex); | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | |||
652 | /** | ||
653 | * @brief Get's oldes message in the list. | ||
654 | * | ||
655 | * @param session Where the list is. | ||
656 | * @return RTPMessage* The message. You _must_ call rtp_msg_free() to free it. | ||
657 | * @retval NULL No messages in the list, or no list. | ||
658 | */ | ||
659 | RTPMessage* rtp_recv_msg ( RTPSession* session ) | ||
660 | { | ||
661 | if ( !session ) | ||
662 | return NULL; | ||
663 | |||
664 | RTPMessage* _retu = session->oldest_msg; | ||
665 | |||
666 | pthread_mutex_lock(&session->mutex); | ||
667 | |||
668 | if ( _retu ) | ||
669 | session->oldest_msg = _retu->next; | ||
670 | |||
671 | if ( !session->oldest_msg ) | ||
672 | session->last_msg = NULL; | ||
673 | |||
674 | pthread_mutex_unlock(&session->mutex); | ||
675 | |||
676 | return _retu; | ||
677 | } | ||
678 | |||
679 | |||
680 | /** | ||
681 | * @brief Sends data to _RTPSession::dest | ||
682 | * | ||
683 | * @param session The session. | ||
684 | * @param messenger Tox* object. | ||
685 | * @param data The payload. | ||
686 | * @param length Size of the payload. | ||
687 | * @return int | ||
688 | * @retval -1 On error. | ||
689 | * @retval 0 On success. | ||
690 | */ | ||
691 | int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uint16_t length ) | ||
692 | { | ||
693 | RTPMessage* msg = rtp_new_message (session, data, length); | ||
694 | |||
695 | if ( !msg ) return -1; | ||
696 | |||
697 | uint8_t _send_data [ MAX_UDP_PACKET_SIZE ]; | ||
698 | |||
699 | _send_data[0] = session->prefix; | ||
700 | |||
701 | /* Generate the right nonce */ | ||
702 | uint8_t _calculated[crypto_box_NONCEBYTES]; | ||
703 | memcpy(_calculated, session->encrypt_nonce, crypto_box_NONCEBYTES); | ||
704 | increase_nonce ( _calculated, msg->header->sequnum ); | ||
705 | |||
706 | /* Need to skip 2 bytes that are for sequnum */ | ||
707 | int encrypted_length = encrypt_data_symmetric( | ||
708 | (uint8_t*) session->encrypt_key, _calculated, msg->data + 2, msg->length - 2, _send_data + 3 ); | ||
709 | |||
710 | int full_length = encrypted_length + 3; | ||
711 | |||
712 | _send_data[1] = msg->data[0]; | ||
713 | _send_data[2] = msg->data[1]; | ||
714 | |||
715 | |||
716 | if ( full_length != sendpacket ( ((Messenger*)messenger)->net, *((IP_Port*) &session->dest), _send_data, full_length) ) { | ||
717 | printf("Rtp error: %s\n", strerror(errno)); | ||
718 | return -1; | ||
719 | } | ||
720 | |||
721 | |||
722 | /* Set sequ number */ | ||
723 | if ( session->sequnum >= MAX_SEQU_NUM ) { | ||
724 | session->sequnum = 0; | ||
725 | memcpy(session->encrypt_nonce, _calculated, crypto_box_NONCEBYTES); | ||
726 | } else { | ||
727 | session->sequnum++; | ||
728 | } | ||
729 | |||
730 | rtp_free_msg ( session, msg ); | ||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | |||
735 | /** | ||
736 | * @brief Speaks for it self. | ||
737 | * | ||
738 | * @param session The control session msg belongs to. It can be NULL. | ||
739 | * @param msg The message. | ||
740 | * @return void | ||
741 | */ | ||
742 | void rtp_free_msg ( RTPSession* session, RTPMessage* msg ) | ||
743 | { | ||
744 | free ( msg->data ); | ||
745 | |||
746 | if ( !session ){ | ||
747 | free ( msg->header->csrc ); | ||
748 | if ( msg->ext_header ){ | ||
749 | free ( msg->ext_header->table ); | ||
750 | free ( msg->ext_header ); | ||
751 | } | ||
752 | } else { | ||
753 | if ( session->csrc != msg->header->csrc ) | ||
754 | free ( msg->header->csrc ); | ||
755 | if ( msg->ext_header && session->ext_header != msg->ext_header ) { | ||
756 | free ( msg->ext_header->table ); | ||
757 | free ( msg->ext_header ); | ||
758 | } | ||
759 | } | ||
760 | |||
761 | free ( msg->header ); | ||
762 | free ( msg ); | ||
763 | } | ||
764 | |||
765 | |||
766 | /** | ||
767 | * @brief Must be called before calling any other rtp function. It's used | ||
768 | * to initialize RTP control session. | ||
769 | * | ||
770 | * @param payload_type Type of payload used to send. You can use values in toxmsi.h::MSICallType | ||
771 | * @param messenger Tox* object. | ||
772 | * @param friend_num Friend id. | ||
773 | * @param encrypt_key Speaks for it self. | ||
774 | * @param decrypt_key Speaks for it self. | ||
775 | * @param encrypt_nonce Speaks for it self. | ||
776 | * @param decrypt_nonce Speaks for it self. | ||
777 | * @return RTPSession* Created control session. | ||
778 | * @retval NULL Error occurred. | ||
779 | */ | ||
780 | RTPSession* rtp_init_session ( int payload_type, | ||
781 | Tox* messenger, | ||
782 | int friend_num, | ||
783 | const uint8_t* encrypt_key, | ||
784 | const uint8_t* decrypt_key, | ||
785 | const uint8_t* encrypt_nonce, | ||
786 | const uint8_t* decrypt_nonce | ||
787 | ) | ||
788 | { | ||
789 | Messenger* _messenger_casted = (Messenger*) messenger; | ||
790 | |||
791 | IP_Port _dest = get_friend_ipport(_messenger_casted, friend_num ); | ||
792 | |||
793 | /* This should be enough eh? */ | ||
794 | if ( _dest.port == 0) { | ||
795 | return NULL; | ||
796 | } | ||
797 | |||
798 | RTPSession* _retu = calloc(sizeof(RTPSession), 1); | ||
799 | assert(_retu); | ||
800 | |||
801 | networking_registerhandler(_messenger_casted->net, payload_type, rtp_handle_packet, _retu); | ||
802 | |||
803 | _retu->version = RTP_VERSION; /* It's always 2 */ | ||
804 | _retu->padding = 0; /* If some additional data is needed about the packet */ | ||
805 | _retu->extension = 0; /* If extension to header is needed */ | ||
806 | _retu->cc = 1; /* Amount of contributors */ | ||
807 | _retu->csrc = NULL; /* Container */ | ||
808 | _retu->ssrc = randombytes_random(); | ||
809 | _retu->marker = 0; | ||
810 | _retu->payload_type = payload_table[payload_type]; | ||
811 | |||
812 | _retu->dest = *((tox_IP_Port*)&_dest); | ||
813 | |||
814 | _retu->rsequnum = _retu->sequnum = 1; | ||
815 | |||
816 | _retu->ext_header = NULL; /* When needed allocate */ | ||
817 | _retu->framerate = -1; | ||
818 | _retu->resolution = -1; | ||
819 | |||
820 | _retu->encrypt_key = encrypt_key; | ||
821 | _retu->decrypt_key = decrypt_key; | ||
822 | |||
823 | /* Need to allocate new memory */ | ||
824 | _retu->encrypt_nonce = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->encrypt_nonce); | ||
825 | _retu->decrypt_nonce = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->decrypt_nonce); | ||
826 | _retu->nonce_cycle = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->nonce_cycle); | ||
827 | |||
828 | memcpy(_retu->encrypt_nonce, encrypt_nonce, crypto_box_NONCEBYTES); | ||
829 | memcpy(_retu->decrypt_nonce, decrypt_nonce, crypto_box_NONCEBYTES); | ||
830 | memcpy(_retu->nonce_cycle , decrypt_nonce, crypto_box_NONCEBYTES); | ||
831 | |||
832 | _retu->csrc = calloc(sizeof(uint32_t), 1); | ||
833 | assert(_retu->csrc); | ||
834 | |||
835 | _retu->csrc[0] = _retu->ssrc; /* Set my ssrc to the list receive */ | ||
836 | |||
837 | /* Also set payload type as prefix */ | ||
838 | _retu->prefix = payload_type; | ||
839 | |||
840 | _retu->oldest_msg = _retu->last_msg = NULL; | ||
841 | |||
842 | pthread_mutex_init(&_retu->mutex, NULL); | ||
843 | /* | ||
844 | * | ||
845 | */ | ||
846 | return _retu; | ||
847 | } | ||
848 | |||
849 | |||
850 | /** | ||
851 | * @brief Terminate the session. | ||
852 | * | ||
853 | * @param session The session. | ||
854 | * @param messenger The messenger who owns the session | ||
855 | * @return int | ||
856 | * @retval -1 Error occurred. | ||
857 | * @retval 0 Success. | ||
858 | */ | ||
859 | int rtp_terminate_session ( RTPSession* session, Tox* messenger ) | ||
860 | { | ||
861 | if ( !session ) | ||
862 | return -1; | ||
863 | |||
864 | networking_registerhandler(((Messenger*)messenger)->net, session->prefix, NULL, NULL); | ||
865 | |||
866 | free ( session->ext_header ); | ||
867 | free ( session->csrc ); | ||
868 | free ( session->decrypt_nonce ); | ||
869 | free ( session->encrypt_nonce ); | ||
870 | free ( session->nonce_cycle ); | ||
871 | |||
872 | pthread_mutex_destroy(&session->mutex); | ||
873 | |||
874 | /* And finally free session */ | ||
875 | free ( session ); | ||
876 | |||
877 | return 0; | ||
878 | } \ No newline at end of file | ||