summaryrefslogtreecommitdiff
path: root/toxav/rtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/rtp.c')
-rw-r--r--toxav/rtp.c934
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 */
63inline__ 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 */
86inline__ 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 */
105inline__ 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 */
127inline__ 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 */
148inline__ 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 */
166inline__ 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 */
201static 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 */
226RTPHeader *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 */
302RTPExtHeader *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 */
343uint8_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 */
383uint8_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 */
410RTPHeader *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 */
457RTPMessage *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 */
514int 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 */
605RTPMessage *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 */
685int 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 */
715RTPMessage *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 */
747int 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 */
800void 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 */
838RTPSession *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 */
915int 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