summaryrefslogtreecommitdiff
path: root/toxav/toxrtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/toxrtp.c')
-rwxr-xr-xtoxav/toxrtp.c878
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 */
74inline__ 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 */
92inline__ 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 */
120static 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 */
146RTPHeader* 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 */
229RTPExtHeader* 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 */
268uint8_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 */
315uint8_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 */
345RTPHeader* 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 */
393RTPMessage* 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 */
456int 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 */
547RTPMessage* 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 */
629int 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 */
659RTPMessage* 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 */
691int 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 */
742void 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 */
780RTPSession* 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 */
859int 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