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