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