summaryrefslogtreecommitdiff
path: root/toxav/rtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/rtp.c')
-rw-r--r--toxav/rtp.c908
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 */
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 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 */
200static 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 */
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; ++_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 */
297RTPExtHeader* 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 */
334uint8_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 */
368uint8_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 */
391RTPHeader* 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 */
438RTPMessage* 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 */
492int 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 */
583RTPMessage* 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 */
663int 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 */
693RTPMessage* 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 */
725int 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 */
778void 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 */
814RTPSession* 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 */
889int 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