summaryrefslogtreecommitdiff
path: root/toxmsi
diff options
context:
space:
mode:
Diffstat (limited to 'toxmsi')
-rw-r--r--toxmsi/Makefile.inc69
-rw-r--r--toxmsi/phone.h62
-rw-r--r--toxmsi/toxmsi.c835
-rw-r--r--toxmsi/toxmsi.h145
-rw-r--r--toxmsi/toxmsi_event.c214
-rw-r--r--toxmsi/toxmsi_event.h46
-rw-r--r--toxmsi/toxmsi_header.c181
-rw-r--r--toxmsi/toxmsi_header.h99
-rw-r--r--toxmsi/toxmsi_message.c267
-rw-r--r--toxmsi/toxmsi_message.h120
10 files changed, 2038 insertions, 0 deletions
diff --git a/toxmsi/Makefile.inc b/toxmsi/Makefile.inc
new file mode 100644
index 00000000..27678bc0
--- /dev/null
+++ b/toxmsi/Makefile.inc
@@ -0,0 +1,69 @@
1if BUILD_AV
2
3lib_LTLIBRARIES += libtoxmsi.la
4
5libtoxmsi_la_include_HEADERS = \
6 ../toxmsi/toxmsi.h
7
8libtoxmsi_la_includedir = $(includedir)/tox
9
10
11libtoxmsi_la_SOURCES = ../toxmsi/toxmsi.h \
12 ../toxmsi/toxmsi.c \
13 ../toxmsi/toxmsi_message.h \
14 ../toxmsi/toxmsi_message.c \
15 ../toxmsi/toxmsi_header.h \
16 ../toxmsi/toxmsi_header.c \
17 ../toxmsi/toxmsi_event.h \
18 ../toxmsi/toxmsi_event.c \
19 ../toxrtp/tests/test_helper.h \
20 ../toxrtp/tests/test_helper.c
21
22libtoxmsi_la_CFLAGS = -I../toxcore \
23 -I../toxmsi \
24 -I../toxrtp \
25 $(NACL_CFLAGS) \
26 $(PTHREAD_CFLAGS)
27
28libtoxmsi_la_LDFLAGS = $(TOXMSI_LT_LDFLAGS) \
29 $(EXTRA_LT_LDFLAGS) \
30 $(NACL_LDFLAGS) \
31 $(PTHREAD_LIBS)
32
33libtoxmsi_la_LIBS = $(NACL_LIBS)
34
35noinst_PROGRAMS += phone
36
37phone_SOURCES = ../toxmsi/phone.c \
38 ../toxmsi/AV_codec.h \
39 ../toxmsi/AV_codec.c
40
41phone_CFLAGS = -I../toxcore \
42 -I../toxrtp \
43 $(AVFORMAT_CFLAGS) \
44 $(AVCODEC_CFLAGS) \
45 $(AVUTIL_CFLAGS) \
46 $(AVDEVICE_CFLAGS) \
47 $(SWSCALE_CFLAGS) \
48 $(SDL_CFLAGS) \
49 $(OPENAL_CFLAGS) \
50 $(NACL_CFLAGS) \
51 $(OPUS_CFLAGS) \
52 $(PTHREAD_CFLAGS)
53
54
55phone_LDADD = $(PTHREAD_LIBS) \
56 libtoxrtp.la \
57 libtoxmsi.la \
58 $(NACL_LDFLAGS) \
59 $(AVFORMAT_LIBS) \
60 $(AVCODEC_LIBS) \
61 $(AVUTIL_LIBS) \
62 $(AVDEVICE_LIBS) \
63 $(SWSCALE_LIBS) \
64 $(SDL_LIBS) \
65 $(OPENAL_LIBS) \
66 $(NACL_LIBS) \
67 $(OPUS_LIBS)
68
69endif
diff --git a/toxmsi/phone.h b/toxmsi/phone.h
new file mode 100644
index 00000000..d661dcfd
--- /dev/null
+++ b/toxmsi/phone.h
@@ -0,0 +1,62 @@
1#ifndef _PHONE_H_
2#define _PHONE_H_
3
4#include "toxmsi.h"
5#include "../toxrtp/toxrtp.h"
6#include "toxmsi_message.h"
7#include "../toxrtp/toxrtp_message.h"
8#include "../toxrtp/tests/test_helper.h"
9#include <assert.h>
10#include <pthread.h>
11#include "AV_codec.h"
12
13/* Define client version */
14#define _USERAGENT "tox_phone-v.0.2.1"
15
16static pthread_mutex_t _mutex;
17
18#define THREADLOCK() \
19pthread_mutex_lock ( &_mutex );
20
21#define THREADUNLOCK() \
22pthread_mutex_unlock ( &_mutex );
23
24typedef struct phone_s {
25 msi_session_t* _msi;
26
27 rtp_session_t* _rtp_audio;
28 rtp_session_t* _rtp_video;
29
30 uint32_t _frame_rate;
31
32 uint16_t _send_port, _recv_port;
33
34 int _tox_sock;
35
36 pthread_t _medialoop_id;
37 codec_state *cs;
38
39 Networking_Core* _networking;
40} phone_t;
41
42phone_t* initPhone(uint16_t _listen_port, uint16_t _send_port);
43int quitPhone(phone_t* _phone);
44
45/* My recv functions */
46int rtp_handlepacket ( void* _object, tox_IP_Port ip_port, uint8_t* data, uint32_t length );
47int msi_handlepacket ( void* _object, tox_IP_Port ip_port, uint8_t* data, uint32_t length );
48
49/* This is basically representation of networking_poll of toxcore */
50void* phone_receivepacket ( void* _phone );
51
52/* Phones main loop */
53void* phone_poll ( void* _phone );
54
55pthread_t phone_startmain_loop(phone_t* _phone);
56pthread_t phone_startmedia_loop ( phone_t* _phone );
57
58/* Thread handlers */
59void* phone_handle_receive_callback ( void* _p );
60void* phone_handle_media_transport_poll ( void* _hmtc_args_p );
61
62#endif /* _PHONE_H_ */
diff --git a/toxmsi/toxmsi.c b/toxmsi/toxmsi.c
new file mode 100644
index 00000000..38af28fb
--- /dev/null
+++ b/toxmsi/toxmsi.c
@@ -0,0 +1,835 @@
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif /* HAVE_CONFIG_H */
5
6#define _BSD_SOURCE
7
8#include "toxmsi.h"
9#include "toxmsi_event.h"
10#include "toxmsi_message.h"
11#include "../toxrtp/toxrtp_helper.h"
12#include "../toxcore/network.h"
13
14#include <assert.h>
15#include <unistd.h>
16#include <string.h>
17
18#define same(x, y) strcmp((const char*) x, (const char*) y) == 0
19
20typedef enum {
21 error_deadcall = 1, /* has call id but it's from old call */
22 error_id_mismatch, /* non-existing call */
23
24 error_no_callid, /* not having call id */
25 error_no_call, /* no call in session */
26
27 error_busy
28} msi_error_t; /* Error codes */
29
30static inline const uint8_t *stringify_error(msi_error_t _error_code)
31{
32 static const uint8_t* strings[] =
33 {
34 (uint8_t*)"",
35 (uint8_t*)"Using dead call",
36 (uint8_t*)"Call id not set to any call",
37 (uint8_t*)"Call id not available",
38 (uint8_t*)"No active call in session",
39 (uint8_t*)"Callee busy"
40 };
41
42 return strings[_error_code];
43}
44
45static inline const uint8_t *stringify_error_code(msi_error_t _error_code)
46{
47 static const uint8_t* strings[] =
48 {
49 (uint8_t*)"",
50 (uint8_t*)"1",
51 (uint8_t*)"2",
52 (uint8_t*)"3",
53 (uint8_t*)"4",
54 (uint8_t*)"5"
55 };
56
57 return strings[_error_code];
58}
59
60/* ******************* */
61/* --------- GLOBAL FUNCTIONS USED BY THIS FILE --------- */
62
63/* CALLBACKS */
64/*int (*msi_send_message_callback) ( int, uint8_t*, uint32_t ) = NULL;*/
65int ( *msi_send_message_callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) = NULL;
66int ( *msi_recv_message_callback ) ( tox_IP_Port*, uint8_t*, uint32_t* ) = NULL;
67
68MCBTYPE ( *msi_recv_invite_callback ) ( MCBARGS ) = NULL;
69MCBTYPE ( *msi_start_call_callback ) ( MCBARGS ) = NULL;
70MCBTYPE ( *msi_reject_call_callback ) ( MCBARGS ) = NULL;
71MCBTYPE ( *msi_cancel_call_callback ) ( MCBARGS ) = NULL;
72MCBTYPE ( *msi_end_call_callback ) ( MCBARGS ) = NULL;
73
74MCBTYPE ( *msi_ringing_callback ) ( MCBARGS ) = NULL;
75MCBTYPE ( *msi_starting_callback ) ( MCBARGS ) = NULL;
76MCBTYPE ( *msi_ending_callback ) ( MCBARGS ) = NULL;
77MCBTYPE ( *msi_error_callback ) ( MCBARGS ) = NULL;
78
79MCBTYPE ( *msi_timeout_callback ) ( MCBARGS ) = NULL;
80/* End of CALLBACKS */
81
82/*------------------------*/
83/*------------------------*/
84/*------------------------*/
85/*------------------------*/
86/*------------------------*/
87/*------------------------*/
88/*------------------------*/
89/*------------------------*/
90/*------------------------*/
91/*------------------------*/
92/*------------------------*/
93/*------------------------*/
94
95/* REGISTER CALLBACKS */
96/*void msi_register_callback_send(int (*callback) ( int, uint8_t*, uint32_t ) )*/
97void msi_register_callback_send ( int ( *callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) )
98{
99 msi_send_message_callback = callback;
100}
101
102void msi_register_callback_recv ( int ( *callback ) ( tox_IP_Port*, uint8_t*, uint32_t* ) )
103{
104 msi_recv_message_callback = callback;
105}
106
107/* Function to be called when received invite.
108 * This callback is all about what you do with it.
109 * Everything else is done internally.
110 */
111void msi_register_callback_recv_invite ( MCALLBACK )
112{
113 msi_recv_invite_callback = callback;
114}
115
116/* Function to be called when the call is started
117 * This callback is all about what you do with it.
118 * Everything else is done internally.
119 */
120void msi_register_callback_call_started ( MCALLBACK )
121{
122 msi_start_call_callback = callback;
123}
124
125/* Function to be called when call is rejected
126 * This callback is all about what you do with it.
127 * Everything else is done internally.
128 */
129void msi_register_callback_call_rejected ( MCALLBACK )
130{
131 msi_reject_call_callback = callback;
132}
133
134/* Function to be called when call is canceled
135 * This callback is all about what you do with it.
136 * Everything else is done internally.
137 */
138void msi_register_callback_call_canceled ( MCALLBACK )
139{
140 msi_cancel_call_callback = callback;
141}
142
143void msi_register_callback_call_ended ( MCALLBACK )
144{
145 msi_end_call_callback = callback;
146}
147
148
149/* Functions to be called when gotten x response */
150
151void msi_register_callback_recv_ringing ( MCALLBACK )
152{
153 msi_ringing_callback = callback;
154}
155void msi_register_callback_recv_starting ( MCALLBACK )
156{
157 msi_starting_callback = callback;
158}
159void msi_register_callback_recv_ending ( MCALLBACK )
160{
161 msi_ending_callback = callback;
162}
163
164void msi_register_callback_recv_error ( MCALLBACK )
165{
166 msi_error_callback = callback;
167}
168
169/* Timeout */
170void msi_register_callback_requ_timeout ( MCALLBACK )
171{
172 msi_timeout_callback = callback;
173}
174/* END REGISTERING */
175
176/*------------------------*/
177/*------------------------*/
178/*------------------------*/
179/*------------------------*/
180/*------------------------*/
181/*------------------------*/
182/*------------------------*/
183/*------------------------*/
184/*------------------------*/
185/*------------------------*/
186/*------------------------*/
187/*------------------------*/
188
189/* Function for receiving and parsing a message that will be used internally */
190
191msi_msg_t* receive_message ( msi_session_t* _session )
192{
193 assert(_session);
194
195
196 msi_msg_t* _retu = _session->_oldest_msg;
197
198 pthread_mutex_lock ( &_session->_mutex );
199
200 if ( _retu )
201 _session->_oldest_msg = _retu->_next;
202
203 if ( !_session->_oldest_msg )
204 _session->_last_msg = NULL;
205
206 pthread_mutex_unlock ( &_session->_mutex );
207
208 return _retu;
209}
210
211void msi_store_msg ( msi_session_t* _session, msi_msg_t* _msg )
212{
213 assert(_session);
214 assert(_msg);
215
216 pthread_mutex_lock ( &_session->_mutex );
217
218 if ( _session->_last_msg ) {
219 _session->_last_msg->_next = _msg;
220 _session->_last_msg = _msg;
221 } else {
222 _session->_last_msg = _session->_oldest_msg = _msg;
223 }
224
225 pthread_mutex_unlock ( &_session->_mutex );
226}
227
228int msi_send_msg ( msi_session_t* _session, msi_msg_t* _msg )
229{
230 int _status;
231
232 if ( !_session->_call ) /* Which should never happen */
233 return FAILURE;
234
235 msi_msg_set_call_id ( _msg, _session->_call->_id );
236
237 uint8_t _msg_string_final [MSI_MAXMSG_SIZE];
238 t_memset ( _msg_string_final, '\0', MSI_MAXMSG_SIZE );
239
240 _msg_string_final[0] = 69;
241
242 uint8_t* _msg_string = msi_msg_to_string ( _msg );
243
244 size_t _lenght = t_memlen ( _msg_string );
245
246 memcpy ( _msg_string_final + 1, _msg_string, _lenght );
247
248 _lenght += 1;
249
250 _status = ( *msi_send_message_callback ) ( _session->_core_handler, _session->_friend_id, _msg_string_final, _lenght );
251
252 free ( _msg_string );
253
254 return _status;
255}
256
257/* Random stuff */
258void flush_peer_type ( msi_session_t* _session, msi_msg_t* _msg, int _peer_id )
259{
260 if ( _msg->_call_type ) {
261 if ( strcmp ( ( const char* ) _msg->_call_type->_header_value, CT_AUDIO_HEADER_VALUE ) == 0 ) {
262 _session->_call->_type_peer[_peer_id] = type_audio;
263
264 } else if ( strcmp ( ( const char* ) _msg->_call_type->_header_value, CT_VIDEO_HEADER_VALUE ) == 0 ) {
265 _session->_call->_type_peer[_peer_id] = type_video;
266 } else {} /* Error */
267 } else {} /* Error */
268}
269
270int has_call_error ( msi_session_t* _session, msi_msg_t* _msg )
271{
272 msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) );
273
274 if ( !_msg->_call_id ) {
275 msi_msg_set_reason(_msg_error, stringify_error_code(error_no_callid) );
276
277 } else if ( !_session->_call ) {
278 msi_msg_set_reason(_msg_error, stringify_error_code(error_no_call) );
279
280 } else if ( strcmp((const char*)_session->_call->_id, (const char*)_msg->_call_id->_header_value ) != 0 ) {
281 msi_msg_set_reason(_msg_error, stringify_error_code(error_id_mismatch) );
282 }
283
284 if ( _msg_error->_reason ) {
285 msi_send_msg ( _session, _msg_error );
286 msi_free_msg ( _msg_error );
287 return SUCCESS;
288 }
289
290 msi_free_msg ( _msg_error );
291 return FAILURE;
292}
293
294/* --------- END OF GLOBAL FUNCTIONS USED BY THIS FILE --------- */
295
296/*------------------------*/
297/*------------------------*/
298/*------------------------*/
299/*------------------------*/
300/*------------------------*/
301/*------------------------*/
302/*------------------------*/
303/*------------------------*/
304/*------------------------*/
305/*------------------------*/
306/*------------------------*/
307/*------------------------*/
308
309msi_session_t* msi_init_session ( void* _core_handler, const uint8_t* _user_agent )
310{
311 assert(_core_handler);
312 assert(_user_agent);
313
314 msi_session_t* _session = calloc ( sizeof ( msi_session_t ), 1 );
315 assert(_session);
316
317 _session->_oldest_msg = _session->_last_msg = NULL;
318 _session->_core_handler = _core_handler;
319
320 _session->_user_agent = t_strallcpy ( _user_agent );
321 _session->_agent_handler = NULL;
322
323 _session->_key = 0;
324 _session->_call = NULL;
325
326 _session->_frequ = 10000; /* default value? */
327 _session->_call_timeout = 30000; /* default value? */
328
329 /* Use the same frequency */
330 _session->_event_handler = init_event_poll ( _session->_frequ );
331
332 pthread_mutex_init ( &_session->_mutex, NULL );
333
334 return _session;
335}
336
337int msi_terminate_session ( msi_session_t* _session )
338{
339 assert(_session);
340
341 int _status = 0;
342
343 terminate_event_poll ( _session->_event_handler );
344 free ( _session );
345 /* TODO: terminate the rest of the session */
346
347 pthread_mutex_destroy ( &_session->_mutex );
348
349 return _status;
350}
351
352msi_call_t* msi_init_call ( msi_session_t* _session, int _peers, uint32_t _timeoutms )
353{
354 assert(_session);
355 assert(_peers);
356
357 msi_call_t* _call = calloc ( sizeof ( msi_call_t ), 1 );
358 _call->_type_peer = calloc ( sizeof ( call_type ), _peers );
359
360 assert(_call);
361 assert(_call->_type_peer);
362
363 _call->_participants = _peers;
364 _call->_key = _session->_key;
365 _call->_timeoutst = _timeoutms;
366 _call->_outgoing_timer_id = 0;
367
368 return _call;
369}
370
371int msi_terminate_call ( msi_session_t* _session )
372{
373 assert(_session);
374
375 if ( _session->_call->_type_peer )
376 free ( _session->_call->_type_peer );
377
378 cancel_timer_event(_session->_event_handler, _session->_call->_outgoing_timer_id);
379
380 free ( _session->_call );
381
382 _session->_call = NULL;
383
384 return SUCCESS;
385}
386/*------------------------*/
387/*------------------------*/
388/*------------------------*/
389/*------------------------*/
390/*------------------------*/
391/*------------------------*/
392/*------------------------*/
393/*------------------------*/
394/*------------------------*/
395/*------------------------*/
396/*------------------------*/
397/*------------------------*/
398
399/* STATE HANDLERS */
400
401/* REQUESTS */
402int msi_handle_recv_invite ( msi_session_t* _session, msi_msg_t* _msg )
403{
404 assert(_session);
405
406 if ( _session->_call ) {
407 msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) );
408 msi_msg_set_reason(_msg_error, stringify_error_code(error_busy));
409 msi_send_msg(_session, _msg_error);
410 msi_free_msg(_msg_error);
411
412 return 0;
413 }
414 if ( !_msg->_call_id ) {
415 msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) );
416 msi_msg_set_reason(_msg_error, stringify_error_code(error_no_callid));
417 msi_send_msg(_session, _msg_error);
418 msi_free_msg(_msg_error);
419 return 0;
420 }
421
422 _session->_call = msi_init_call ( _session, 1, _session->_call_timeout );
423 t_memcpy(_session->_call->_id, _msg->_call_id->_header_value, _CALL_ID_LEN);
424 _session->_call->_state = call_starting;
425
426 flush_peer_type ( _session, _msg, 0 );
427
428 msi_msg_t* _msg_ringing = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ringing ) );
429 msi_send_msg ( _session, _msg_ringing );
430 msi_free_msg ( _msg_ringing );
431
432 throw_event ( _session->_event_handler, msi_recv_invite_callback, _session );
433 return 1;
434}
435int msi_handle_recv_start ( msi_session_t* _session, msi_msg_t* _msg )
436{
437 assert(_session);
438
439 if ( has_call_error(_session, _msg) == 0 )
440 return 0;
441
442 _session->_call->_state = call_active;
443
444 flush_peer_type ( _session, _msg, 0 );
445
446 throw_event ( _session->_event_handler, msi_start_call_callback, _session );
447 return 1;
448}
449int msi_handle_recv_reject ( msi_session_t* _session, msi_msg_t* _msg )
450{
451 assert(_session);
452
453 if ( has_call_error(_session, _msg) == 0 )
454 return 0;
455
456 msi_msg_t* _msg_end = msi_msg_new ( TYPE_REQUEST, stringify_request ( _end ) );
457 msi_send_msg ( _session, _msg_end );
458 msi_free_msg ( _msg_end );
459
460 throw_event ( _session->_event_handler, msi_reject_call_callback, _session );
461
462 return 1;
463}
464int msi_handle_recv_cancel ( msi_session_t* _session, msi_msg_t* _msg )
465{
466 assert(_session);
467
468 if ( has_call_error(_session, _msg) == 0 )
469 return 0;
470
471 msi_msg_t* _msg_ending = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ending ) );
472 msi_send_msg ( _session, _msg_ending );
473 msi_free_msg ( _msg_ending );
474
475 msi_terminate_call ( _session );
476
477 throw_event ( _session->_event_handler, msi_cancel_call_callback, _session );
478
479 return 1;
480}
481int msi_handle_recv_end ( msi_session_t* _session, msi_msg_t* _msg )
482{
483 assert(_session);
484
485 if ( has_call_error(_session, _msg) == 0 )
486 return 0;
487
488 msi_msg_t* _msg_ending = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ending ) );
489 msi_send_msg ( _session, _msg_ending );
490 msi_free_msg ( _msg_ending );
491
492 msi_terminate_call ( _session );
493
494 throw_event ( _session->_event_handler, msi_end_call_callback, _session );
495
496 return 1;
497}
498/*--------*/
499
500/* RESPONSES */
501int msi_handle_recv_ringing ( msi_session_t* _session, msi_msg_t* _msg )
502{
503 assert(_session);
504
505 if ( has_call_error(_session, _msg) == 0 )
506 return 0;
507
508 throw_event ( _session->_event_handler, msi_ringing_callback, _session );
509
510 return 1;
511}
512int msi_handle_recv_starting ( msi_session_t* _session, msi_msg_t* _msg )
513{
514 assert(_session);
515
516 if ( has_call_error(_session, _msg) == 0 )
517 return 0;
518
519 _session->_call->_state = call_active;
520
521 msi_msg_t* _msg_start = msi_msg_new ( TYPE_REQUEST, stringify_request ( _start ) );
522 msi_send_msg ( _session, _msg_start );
523 msi_free_msg ( _msg_start );
524
525 flush_peer_type ( _session, _msg, 0 );
526
527 throw_event ( _session->_event_handler, msi_starting_callback, _session );
528 cancel_timer_event(_session->_event_handler, _session->_call->_outgoing_timer_id);
529 _session->_call->_outgoing_timer_id = 0;
530
531 return 1;
532}
533int msi_handle_recv_ending ( msi_session_t* _session, msi_msg_t* _msg )
534{
535 assert(_session);
536
537 if ( has_call_error(_session, _msg) == 0 )
538 return 0;
539
540 msi_terminate_call ( _session );
541 throw_event ( _session->_event_handler, msi_ending_callback, _session );
542
543 return 1;
544}
545int msi_handle_recv_error ( msi_session_t* _session, msi_msg_t* _msg )
546{
547 assert(_session);
548 assert(_session->_call);
549
550 /* Handle error accordingly */
551 if ( _msg->_reason ) {
552 _session->_last_error_id = atoi((const char*)_msg->_reason->_header_value);
553 _session->_last_error_str = stringify_error(_session->_last_error_id);
554 }
555
556 msi_terminate_call(_session);
557
558 throw_event ( _session->_event_handler, msi_error_callback, _session );
559
560 return 1;
561}
562/* ------------------ */
563
564MCBTYPE msi_handle_timeout (void* _arg)
565{
566 msi_session_t* _session = _arg;
567 msi_terminate_call(_session);
568
569 (*msi_timeout_callback) (_arg);
570 (*msi_ending_callback) (_arg);
571
572}
573
574/*------------------------*/
575/*------------------------*/
576/*------------------------*/
577/*------------------------*/
578/*------------------------*/
579/*------------------------*/
580/*------------------------*/
581/*------------------------*/
582/*------------------------*/
583/*------------------------*/
584/*------------------------*/
585/*------------------------*/
586
587int msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms )
588{
589 assert(_session);
590
591 if ( !msi_send_message_callback )
592 return 0;
593
594 msi_msg_t* _msg_invite = msi_msg_new ( TYPE_REQUEST, stringify_request ( _invite ) );
595
596 _session->_call = msi_init_call ( _session, 1, _timeoutms ); /* Just one for now */
597 msi_genterate_call_id(_session->_call->_id, _CALL_ID_LEN);
598 _session->_call->_type_local = _call_type;
599 /* Do whatever with message */
600
601 if ( _call_type == type_audio ) {
602 msi_msg_set_call_type ( _msg_invite, ( const uint8_t* ) CT_AUDIO_HEADER_VALUE );
603 } else {
604 msi_msg_set_call_type ( _msg_invite, ( const uint8_t* ) CT_VIDEO_HEADER_VALUE );
605 }
606
607 msi_send_msg ( _session, _msg_invite );
608 msi_free_msg ( _msg_invite );
609
610 _session->_call->_state = call_inviting;
611
612 _session->_call->_outgoing_timer_id = throw_timer_event(_session->_event_handler, msi_handle_timeout, _session, _timeoutms );
613
614 return 1;
615}
616int msi_hangup ( msi_session_t* _session )
617{
618 assert(_session);
619
620 if ( !_session->_call || ( !msi_send_message_callback && _session->_call->_state != call_active ) )
621 return 0;
622
623 msi_msg_t* _msg_ending = msi_msg_new ( TYPE_REQUEST, stringify_request ( _end ) );
624 msi_send_msg ( _session, _msg_ending );
625 msi_free_msg ( _msg_ending );
626
627 return 1;
628}
629
630
631int msi_answer ( msi_session_t* _session, call_type _call_type )
632{
633 assert(_session);
634
635 if ( !msi_send_message_callback || !_session->_call )
636 return 0;
637
638 msi_msg_t* _msg_starting = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _starting ) );
639 _session->_call->_type_local = _call_type;
640
641 if ( _call_type == type_audio ) {
642 msi_msg_set_call_type ( _msg_starting, ( const uint8_t* ) CT_AUDIO_HEADER_VALUE );
643 } else {
644 msi_msg_set_call_type ( _msg_starting, ( const uint8_t* ) CT_VIDEO_HEADER_VALUE );
645 }
646
647 msi_send_msg ( _session, _msg_starting );
648 msi_free_msg ( _msg_starting );
649
650 _session->_call->_state = call_active;
651 return 1;
652}
653int msi_cancel ( msi_session_t* _session )
654{
655 assert(_session);
656
657 if ( !_session->_call || !msi_send_message_callback )
658 return 0;
659
660 msi_msg_t* _msg_cancel = msi_msg_new ( TYPE_REQUEST, stringify_request ( _cancel ) );
661 msi_send_msg ( _session, _msg_cancel );
662 msi_free_msg ( _msg_cancel );
663
664
665
666 return 1;
667}
668int msi_reject ( msi_session_t* _session )
669{
670 assert(_session);
671
672 if ( !_session->_call || !msi_send_message_callback )
673 return 0;
674
675 msi_msg_t* _msg_reject = msi_msg_new ( TYPE_REQUEST, stringify_request ( _reject ) );
676 msi_send_msg ( _session, _msg_reject );
677 msi_free_msg ( _msg_reject );
678
679 return 1;
680}
681
682/*------------------------*/
683/*------------------------*/
684/*------------------------*/
685/*------------------------*/
686/*------------------------*/
687/*------------------------*/
688/*------------------------*/
689/*------------------------*/
690/*------------------------*/
691/*------------------------*/
692/*------------------------*/
693/*------------------------*/
694
695/* OUR MAIN POOL FUNCTION */
696/*
697 * Forks it self to other thread and then handles the session initiation.
698 *
699 * BASIC call flow:
700 *
701 * ALICE BOB
702 * | invite --> |
703 * | |
704 * | <-- ringing |
705 * | |
706 * | <-- starting |
707 * | |
708 * | start --> |
709 * | |
710 * | <-- MEDIA TRANS --> |
711 * | |
712 * | end --> |
713 * | |
714 * | <-- ending |
715 *
716 * Alice calls Bob by sending invite packet.
717 * Bob recvs the packet and sends an ringing packet;
718 * which notifies Alice that her invite is acknowledged.
719 * Ringing screen shown on both sides.
720 * Bob accepts the invite for a call by sending starting packet.
721 * Alice recvs the starting packet and sends the started packet to
722 * inform Bob that she recved the starting packet.
723 * Now the media transmission is established ( i.e. RTP transmission ).
724 * Alice hangs up and sends end packet.
725 * Bob recves the end packet and sends ending packet
726 * as the acknowledgement that the call is ending.
727 *
728 *
729 */
730
731
732/*
733 * Needs a bit more work on the protocol
734 */
735void* msi_poll_stack ( void* _session_p )
736{
737 msi_session_t* _session = ( msi_session_t* ) _session_p;
738 msi_msg_t* _msg = NULL;
739
740 uint32_t* _frequ = &_session->_frequ;
741 while ( _session ) {
742
743 /* At this point it's already parsed */
744 _msg = receive_message ( _session );
745
746 if ( _msg ) {
747
748 if ( _msg->_request ) { /* Handle request */
749
750 const uint8_t* _request_value = _msg->_request->_header_value;
751
752 if ( same ( _request_value, stringify_request ( _invite ) ) ) {
753 msi_handle_recv_invite ( _session, _msg );
754
755 } else if ( same ( _request_value, stringify_request ( _start ) ) ) {
756 msi_handle_recv_start ( _session, _msg );
757
758 } else if ( same ( _request_value, stringify_request ( _cancel ) ) ) {
759 msi_handle_recv_cancel ( _session, _msg );
760
761 } else if ( same ( _request_value, stringify_request ( _reject ) ) ) {
762 msi_handle_recv_reject ( _session, _msg );
763
764 } else if ( same ( _request_value, stringify_request ( _end ) ) ) {
765 msi_handle_recv_end ( _session, _msg );
766 }
767
768 } else if ( _msg->_response ) { /* Handle response */
769
770 const uint8_t* _response_value = _msg->_response->_header_value;
771
772 if ( same ( _response_value, stringify_response ( _ringing ) ) ) {
773 msi_handle_recv_ringing ( _session, _msg );
774
775 } else if ( same ( _response_value, stringify_response ( _starting ) ) ) {
776 msi_handle_recv_starting ( _session, _msg );
777
778 } else if ( same ( _response_value, stringify_response ( _ending ) ) ) {
779 msi_handle_recv_ending ( _session, _msg );
780
781 } else if ( same ( _response_value, stringify_response ( _error ) ) ) {
782 msi_handle_recv_error ( _session, _msg );
783 }
784
785 }
786
787 msi_free_msg ( _msg );
788
789 }
790 usleep ( *_frequ );
791 }
792
793 return NULL;
794}
795
796/*------------------------*/
797/*------------------------*/
798/*------------------------*/
799/*------------------------*/
800/*------------------------*/
801/*------------------------*/
802/*------------------------*/
803/*------------------------*/
804/*------------------------*/
805/*------------------------*/
806/*------------------------*/
807/*------------------------*/
808
809/* Easy way to start the poll */
810
811pthread_t msi_start_main_loop ( msi_session_t* _session, uint32_t _frequms )
812{
813 assert(_session);
814
815 int _status;
816 pthread_t _thread_id;
817
818
819 _session->_frequ = _frequms * 1000;
820
821 _status = pthread_create ( &_thread_id, NULL, msi_poll_stack, _session );
822
823 if ( _status < 0 ) {
824 printf ( "Error while starting main loop: %d, %s\n", errno, strerror ( errno ) );
825 return _status;
826 }
827
828 _status = pthread_detach ( _thread_id );
829
830 if ( _status < 0 ) {
831 printf ( "Error while starting main loop: %d, %s\n", errno, strerror ( errno ) );
832 }
833
834 return _thread_id;
835}
diff --git a/toxmsi/toxmsi.h b/toxmsi/toxmsi.h
new file mode 100644
index 00000000..69d5144a
--- /dev/null
+++ b/toxmsi/toxmsi.h
@@ -0,0 +1,145 @@
1/* msi_initiation.h
2*
3* Has function for session initiation along with session description.
4* It follows the Tox API ( http://wiki.tox.im/index.php/Messaging_Protocol ). !Red!
5*
6*
7* Copyright (C) 2013 Tox project All Rights Reserved.
8*
9* This file is part of Tox.
10*
11* Tox is free software: you can redistribute it and/or modify
12* it under the terms of the GNU General Public License as published by
13* the Free Software Foundation, either version 3 of the License, or
14* (at your option) any later version.
15*
16* Tox is distributed in the hope that it will be useful,
17* but WITHOUT ANY WARRANTY; without even the implied warranty of
18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19* GNU General Public License for more details.
20*
21* You should have received a copy of the GNU General Public License
22* along with Tox. If not, see <http://www.gnu.org/licenses/>.
23*
24*/
25
26
27#ifndef _MSI_IMPL_H_
28#define _MSI_IMPL_H_
29
30#include <inttypes.h>
31#include "../toxcore/tox.h"
32#include <pthread.h>
33
34#define MCBTYPE void
35#define MCBARGS void* _arg
36#define MCALLBACK MCBTYPE(*callback)(void* _arg)
37
38#define MSI_PACKET 69
39
40#define CT_AUDIO_HEADER_VALUE "AUDIO"
41#define CT_VIDEO_HEADER_VALUE "VIDEO"
42
43/* define size for call_id */
44#define _CALL_ID_LEN 12
45
46typedef enum {
47 type_audio = 1,
48 type_video,
49} call_type;
50
51typedef enum {
52 call_inviting, /* when sending call invite */
53 call_starting, /* when getting call invite */
54 call_active,
55 call_hold
56
57} call_state;
58
59typedef int crypto_key;
60
61typedef struct msi_call_s { /* Call info structure */
62 call_state _state;
63 call_type _type_local;
64 call_type* _type_peer; /* Support for conference starts with this */
65 uint8_t _id[_CALL_ID_LEN]; /* Random value identifying the call */
66 crypto_key _key; /* What is the type again? */
67 uint16_t _participants; /* Number of participants */
68 uint32_t _timeoutst; /* Time of the timeout for some action to end; 0 if infinite */
69 int _outgoing_timer_id; /* Timer id */
70
71} msi_call_t;
72
73typedef struct msi_session_s {
74 pthread_mutex_t _mutex;
75
76 crypto_key _key; /* The key */
77
78 /* Call information/handler. ( Maybe only information? ) */
79 msi_call_t* _call;
80
81 /* Storage for message receiving */
82 struct msi_msg_s* _oldest_msg;
83 struct msi_msg_s* _last_msg; /* tail */
84
85 /*int _friend_id;*/
86 tox_IP_Port _friend_id;
87
88 int _last_error_id; /* Determine the last error */
89 const uint8_t* _last_error_str;
90
91 const uint8_t* _user_agent;
92
93 void* _agent_handler; /* Pointer to an object that is handling msi */
94 void* _core_handler; /* Pointer to networking core or to anything that
95 * should handle interaction with core/networking
96 */
97 void* _event_handler; /* Pointer to an object which handles the events */
98
99 uint32_t _frequ;
100 uint32_t _call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
101} msi_session_t;
102
103
104
105msi_session_t* msi_init_session ( void* _core_handler, const uint8_t* _user_agent );
106int msi_terminate_session ( msi_session_t* _session );
107
108pthread_t msi_start_main_loop ( msi_session_t* _session, uint32_t _frequms );
109
110/* Registering callbacks */
111
112/*void msi_register_callback_send(int (*callback) ( int, uint8_t*, uint32_t ) );*/
113void msi_register_callback_send ( int ( *callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) );
114
115/* Callbacks that handle the states */
116void msi_register_callback_call_started ( MCALLBACK );
117void msi_register_callback_call_canceled ( MCALLBACK );
118void msi_register_callback_call_rejected ( MCALLBACK );
119void msi_register_callback_call_ended ( MCALLBACK );
120
121void msi_register_callback_recv_invite ( MCALLBACK );
122void msi_register_callback_recv_ringing ( MCALLBACK );
123void msi_register_callback_recv_starting ( MCALLBACK );
124void msi_register_callback_recv_ending ( MCALLBACK );
125void msi_register_callback_recv_error ( MCALLBACK );
126
127void msi_register_callback_requ_timeout ( MCALLBACK );
128/* -------- */
129
130
131/* Function handling receiving from core */
132/*static int msi_handlepacket ( tox_IP_Port ip_port, uint8_t* _data, uint16_t _lenght ); */
133
134/* functions describing the usage of msi */
135int msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms );
136int msi_hangup ( msi_session_t* _session );
137
138int msi_answer ( msi_session_t* _session, call_type _call_type );
139int msi_cancel ( msi_session_t* _session );
140int msi_reject ( msi_session_t* _session );
141
142int msi_send_msg ( msi_session_t* _session, struct msi_msg_s* _msg );
143void msi_store_msg ( msi_session_t* _session, struct msi_msg_s* _msg );
144
145#endif /* _MSI_IMPL_H_ */
diff --git a/toxmsi/toxmsi_event.c b/toxmsi/toxmsi_event.c
new file mode 100644
index 00000000..d8c0d269
--- /dev/null
+++ b/toxmsi/toxmsi_event.c
@@ -0,0 +1,214 @@
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif /* HAVE_CONFIG_H */
5
6#include <stdlib.h>
7
8#include "toxmsi_event.h"
9
10#include "../toxrtp/toxrtp_helper.h"
11#include <assert.h>
12#include <stdlib.h>
13#include <unistd.h>
14
15static int _unique_id = 1;
16
17/* clear events */
18void clear_events (event_container_t** _event_container, size_t* _counter)
19{
20 assert( *_event_container );
21
22 free(*_event_container);
23 *_event_container = NULL;
24
25 *_counter = 0;
26}
27
28int pop_id ( event_container_t** _event_container, size_t* _counter, int _id )
29{
30 if ( !*_event_container || !*_counter || !_id )
31 return FAILURE;
32
33 event_container_t* _it = *_event_container;
34 int i;
35
36 for ( i = *_counter; i > 0 ; -- i ){
37 if ( _it->_id == _id ) { /* Hit! */
38 break;
39 }
40 ++_it;
41 }
42
43 if ( i ) {
44 for ( ; i > 0; -- i ){ *_it = *(_it + 1); ++_it; }
45 -- (*_counter);
46 *_event_container = realloc(*_event_container, sizeof(event_container_t) * (*_counter)); /* resize */
47
48 if ( *_counter )
49 assert(*_event_container);
50
51 return SUCCESS;
52
53 } else {
54 assert(i);
55 return FAILURE;
56 }
57}
58
59/* main poll for event execution */
60void* event_poll( void* _event_handler_p )
61{
62 event_handler_t* _event_handler = _event_handler_p;
63 uint32_t* _frequms = &_event_handler->_frequms;
64
65
66 while ( _event_handler->_running )
67 {
68
69 if ( _event_handler->_events_count ){
70 pthread_mutex_lock(&_event_handler->_mutex);
71
72 int i;
73 for ( i = 0; i < _event_handler->_events_count; i ++ ){
74 _event_handler->_events[i]._event(_event_handler->_events[i]._event_args);
75
76 }
77 clear_events(&_event_handler->_events, &_event_handler->_events_count);
78
79 pthread_mutex_unlock(&_event_handler->_mutex);
80 }
81
82 if ( _event_handler->_timed_events_count ){
83 pthread_mutex_lock(&_event_handler->_mutex);
84
85 uint32_t _time = t_time();
86
87 if ( _event_handler->_timed_events[0]._timeout < _time ) {
88 _event_handler->_timed_events[0]._event(_event_handler->_timed_events[0]._event_args);
89
90 pop_id(&_event_handler->_timed_events,
91 &_event_handler->_timed_events_count,
92 _event_handler->_timed_events[0]._id);
93 }
94 pthread_mutex_unlock(&_event_handler->_mutex);
95 }
96
97
98 usleep(*_frequms);
99 }
100
101 _event_handler->_running = -1;
102 pthread_exit(NULL);
103}
104
105void push_event ( event_container_t** _container, size_t* _counter, event_t _func, event_arg_t _arg )
106{
107 (*_counter)++;
108 (*_container) = realloc((*_container), sizeof(event_container_t) * (*_counter));
109 assert((*_container) != NULL);
110
111 (*_container[*_counter - 1])._event = _func;
112 (*_container[*_counter - 1])._event_args = _arg;
113 (*_container[*_counter - 1])._timeout = 0;
114 (*_container[*_counter - 1])._id = 0;
115}
116
117void throw_event( void* _event_handler_p, event_t _func, event_arg_t _arg )
118{
119 if ( !_func )
120 return;
121
122 event_handler_t* _event_handler = _event_handler_p;
123
124 pthread_mutex_lock(&_event_handler->_mutex);
125
126 push_event(&_event_handler->_events, &_event_handler->_events_count, _func, _arg);
127
128 pthread_mutex_unlock(&_event_handler->_mutex);
129}
130
131int throw_timer_event ( void* _event_handler_p, event_t _func, event_arg_t _arg, uint32_t _timeout)
132{
133 if ( !_func )
134 return FAILURE;
135
136 event_handler_t* _event_handler = _event_handler_p;
137
138 pthread_mutex_lock(&_event_handler->_mutex);
139
140 push_event(&_event_handler->_timed_events, &_event_handler->_timed_events_count, _func, _arg);
141 size_t _counter = _event_handler->_timed_events_count;
142 _event_handler->_timed_events[_counter - 1]._timeout = _timeout + t_time();
143 _event_handler->_timed_events[_counter - 1]._id = _unique_id; ++_unique_id;
144
145
146 /* reorder */
147 if ( _counter > 1 ) {
148
149 int i = _counter - 1;
150 /* start from behind excluding last added member */
151 event_container_t* _it = &_event_handler->_timed_events[i - 1];
152
153 event_container_t _last_added = _event_handler->_timed_events[i];
154
155 for ( ; i > 0; --i ) {
156 if ( _it->_timeout > _timeout ){
157 *(_it + 1) = *_it;
158 *_it = _last_added; -- _it;
159 }
160 }
161
162 }
163
164 pthread_mutex_unlock(&_event_handler->_mutex);
165
166 return _event_handler->_timed_events[_counter - 1]._id;
167}
168int cancel_timer_event ( void* _event_handler_p, int _id )
169{
170 event_handler_t* _event_handler = _event_handler_p;
171 return pop_id(&_event_handler->_timed_events, &_event_handler->_timed_events_count, _id);
172}
173
174event_handler_t* init_event_poll (uint32_t _frequms)
175{
176 event_handler_t* _retu = calloc(sizeof(event_handler_t), 1);
177 assert(_retu);
178 /* Initialize basic events */
179 _retu->_events = NULL ;
180
181 /* Initialize timed events */
182 _retu->_timed_events = NULL;
183
184 _retu->_frequms = _frequms;
185 _retu->_running = 1;
186 pthread_mutex_init(&_retu->_mutex, NULL);
187
188 pthread_create(&_retu->_thread_id, NULL, event_poll, _retu);
189 int _rc = pthread_detach(_retu->_thread_id);
190 assert(_rc == 0);
191
192 return _retu;
193}
194
195int terminate_event_poll(event_handler_t* _handler)
196{
197 if ( !_handler )
198 return FAILURE;
199
200 _handler->_running = 0;
201 while (_handler->_running != -1); /* Wait for execution */
202
203 if (_handler->_events)
204 clear_events(&_handler->_events, &_handler->_events_count);
205 if (_handler->_events)
206 clear_events(&_handler->_timed_events, &_handler->_timed_events_count);
207
208 pthread_mutex_destroy( &_handler->_mutex );
209
210 free(_handler);
211
212 return SUCCESS;
213}
214
diff --git a/toxmsi/toxmsi_event.h b/toxmsi/toxmsi_event.h
new file mode 100644
index 00000000..032e4df5
--- /dev/null
+++ b/toxmsi/toxmsi_event.h
@@ -0,0 +1,46 @@
1#ifndef _MSI__EVENT_H_
2#define _MSI__EVENT_H_
3
4#include <stddef.h>
5#include <inttypes.h>
6#include <pthread.h>
7
8typedef void* event_arg_t;
9
10typedef void ( *event_t ) ( event_arg_t );
11typedef void ( *timed_event_t ) ( event_arg_t );
12
13typedef struct event_container_s {
14 event_t _event;
15 event_arg_t _event_args;
16 uint32_t _timeout;
17 long long _id;
18
19} event_container_t;
20
21typedef struct event_handler_s {
22 event_container_t* _events;
23 size_t _events_count;
24
25 event_container_t* _timed_events;
26 size_t _timed_events_count;
27
28 uint32_t _frequms;
29 int _running;
30
31 pthread_mutex_t _mutex;
32 pthread_t _thread_id;
33
34} event_handler_t;
35
36event_handler_t* init_event_poll ( uint32_t _frequms );
37int terminate_event_poll ( event_handler_t* _event_handler );
38
39void throw_event ( void* _event_handler_p, event_t _func, event_arg_t _arg );
40
41/* Not yet ready for use */
42int throw_timer_event ( void* _event_handler_p, event_t _func, event_arg_t _arg, uint32_t _timeout);
43int cancel_timer_event ( void* _event_handler_p, int _id );
44
45
46#endif /* _MSI__EVENT_H_ */
diff --git a/toxmsi/toxmsi_header.c b/toxmsi/toxmsi_header.c
new file mode 100644
index 00000000..448ebc7f
--- /dev/null
+++ b/toxmsi/toxmsi_header.c
@@ -0,0 +1,181 @@
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif /* HAVE_CONFIG_H */
5
6#include "toxmsi_message.h"
7#include <string.h>
8#include "../toxrtp/toxrtp_helper.h"
9#include <assert.h>
10#include "../toxcore/Lossless_UDP.h"
11
12#define ALLOC_ADD_DATA(_tempval, _hdrlist, _fielddef, _msgvar, _alloctype) \
13_tempval = msi_search_field(_hdrlist, (const uint8_t*)_fielddef); \
14if ( _tempval ){ \
15 _msgvar = calloc(sizeof(_alloctype), 1); \
16 assert(_msgvar); \
17 _msgvar->_header_value = _tempval; \
18}
19
20uint8_t* msi_search_field ( msi_header_t* _list, const uint8_t* _field )
21{
22 assert(_list);
23 assert(_field);
24
25 msi_header_t* _iterator;
26
27 for ( _iterator = _list;
28 _iterator && strcmp((const char*)_iterator->_header_field, (const char*)_field) != 0;
29 _iterator = _iterator->next );
30
31 if ( _iterator ){
32 return t_strallcpy(_iterator->_header_value);
33 } else return NULL;
34}
35
36int msi_parse_headers ( msi_msg_t* _msg )
37{
38 assert(_msg);
39
40 if ( !_msg->_headers )
41 return FAILURE;
42
43 msi_header_t* _list = _msg->_headers;
44 uint8_t* _field_current;
45
46 ALLOC_ADD_DATA(_field_current, _list, _CALL_ID_FIELD, _msg->_call_id, msi_header_call_id_t)
47 ALLOC_ADD_DATA(_field_current, _list, _VERSION_FIELD, _msg->_version, msi_header_version_t)
48 ALLOC_ADD_DATA(_field_current, _list, _REQUEST_FIELD, _msg->_request, msi_header_request_t)
49 ALLOC_ADD_DATA(_field_current, _list, _RESPONSE_FIELD, _msg->_response, msi_header_response_t)
50 ALLOC_ADD_DATA(_field_current, _list, _FRIENDID_FIELD, _msg->_friend_id, msi_header_friendid_t)
51 ALLOC_ADD_DATA(_field_current, _list, _CALLTYPE_FIELD, _msg->_call_type, msi_header_call_type_t)
52 ALLOC_ADD_DATA(_field_current, _list, _USERAGENT_FIELD, _msg->_user_agent, msi_header_user_agent_t)
53 ALLOC_ADD_DATA(_field_current, _list, _INFO_FIELD, _msg->_info, msi_header_info_t)
54 ALLOC_ADD_DATA(_field_current, _list, _REASON_FIELD, _msg->_reason, msi_header_reason_t)
55
56 /* Since we don't need the raw header anymore remove it */
57 msi_header_t* _temp;
58 while ( _list ){
59 _temp = _list->next;
60 free(_list->_header_field);
61 free(_list->_header_value);
62 free(_list);
63 _list = _temp;
64 }
65
66 _msg->_headers = NULL;
67
68 return SUCCESS;
69}
70
71/*
72 * If you find better way of parsing values let me know
73 */
74msi_header_t* msi_add_new_header ( uint8_t* _value )
75{
76 if ( !_value )
77 return NULL;
78
79 size_t _length = t_memlen(_value);
80
81 if ( !_length ) {
82 return NULL;
83 }
84
85 size_t _first_len = t_strfind(_value, (const uint8_t*)" ");
86 if ( !_first_len ){
87 return NULL;
88 }
89
90 size_t _second_len = (_length - _first_len);
91 if ( !_second_len ){
92 return NULL;
93 }
94
95
96 uint8_t* _identifier = calloc(sizeof (uint8_t), (_first_len + 1) );
97 uint8_t* _data = calloc(sizeof (uint8_t), (_second_len + 1) );
98
99 assert(_identifier);
100 assert(_data);
101
102
103 uint8_t* _p_it = _value;
104 size_t _num_it;
105
106 for ( _num_it = 0; *_p_it != ' '; _num_it++ ){
107 _identifier[_num_it] = *_p_it;
108 ++_p_it;
109 }
110 _identifier[_num_it] = '\0';
111 ++_p_it;
112
113
114 for ( _num_it = 0; *_p_it != '\r'; _num_it++ ){
115 _data[_num_it] = *_p_it;
116 ++_p_it;
117 }
118 _data[_num_it] = '\r';
119 _data[_num_it + 1] = '\0';
120
121 msi_header_t* _retu = calloc(sizeof(msi_header_t), 1);
122 assert(_retu);
123
124 _retu->_header_field = _identifier;
125 _retu->_header_value = _data;
126
127 _retu->next = NULL;
128
129 return _retu;
130}
131
132msi_header_t* msi_parse_raw_data ( const uint8_t* _data )
133{
134 assert(_data);
135
136 uint8_t* _header_string;
137
138 _header_string = (uint8_t*) strtok ((char*)_data, _RAW_TERMINATOR);
139
140 msi_header_t* _head = msi_add_new_header(_header_string);
141 msi_header_t* _it = _head;
142
143 while ( _header_string && _it ){
144
145 _header_string = (uint8_t*) strtok (NULL, _RAW_TERMINATOR);
146 _it->next = msi_add_new_header(_header_string);
147 if ( _it->next ){
148 _it = _it->next;
149 }
150 }
151
152 /* Iterate through list and remove all fault headers if any */
153
154 msi_header_t* _tmp = _it;
155
156 for ( _it = _head; _it; _it = _it->next ){
157
158 if ( !_it->_header_value || !_it->_header_field ) {
159 _tmp ->next = _it->next;
160
161 if ( _it->_header_field )
162 free(_it->_header_field);
163 if ( _it->_header_value )
164 free(_it->_header_value);
165
166 if ( _it == _head ){
167 _head = _head->next;
168 }
169
170 free(_it);
171 _it = _tmp;
172 } else
173 _tmp = _it;
174
175 }
176
177 return _head;
178}
179
180
181
diff --git a/toxmsi/toxmsi_header.h b/toxmsi/toxmsi_header.h
new file mode 100644
index 00000000..599fafa3
--- /dev/null
+++ b/toxmsi/toxmsi_header.h
@@ -0,0 +1,99 @@
1#ifndef _MSI_HEADER_
2#define _MSI_HEADER_
3
4/* Basic format of the unparsed header string
5 * ( No spaces in field allowed )
6 * Version 0.1.1\n\r
7 * Request INVITE\n\r
8 * Response\n\r
9 * Friend-id ( from ip )\n\r
10 * Call-type AUDIO\n\r
11 * User-agent phone-v.1.0.0\n\r
12 */
13
14
15/* define raw header terminator */
16static const char* _RAW_TERMINATOR = "\n\r";
17
18/* define string formats for the identifiers */
19#define _VERSION_FIELD "Version"
20#define _REQUEST_FIELD "Request"
21#define _RESPONSE_FIELD "Response"
22#define _FRIENDID_FIELD "Friend-id"
23#define _CALLTYPE_FIELD "Call-type"
24#define _USERAGENT_FIELD "User-agent"
25#define _INFO_FIELD "INFO"
26#define _REASON_FIELD "Reason"
27#define _CALL_ID_FIELD "Call-id"
28
29#define HEADER_VALUES \
30/*uint8_t* _header_field */ \
31uint8_t* _header_value;
32
33typedef struct msi_header_s { /* raw header list */
34 uint8_t* _header_field;
35 uint8_t* _header_value;
36
37 struct msi_header_s* next;
38
39} msi_header_t;
40
41
42
43typedef struct msi_header_version_s { /* Defines our version */
44 HEADER_VALUES
45
46} msi_header_version_t;
47
48typedef struct msi_header_request_s { /* Defines our request */
49 HEADER_VALUES
50
51} msi_header_request_t;
52
53typedef struct msi_header_response_s { /* Defines our response */
54 HEADER_VALUES
55
56} msi_header_response_t;
57
58typedef struct msi_header_friendid_s { /* Defines source that sent the message */
59 HEADER_VALUES
60
61} msi_header_friendid_t;
62
63typedef struct msi_header_call_type_s { /* Defines the type of the call */
64 HEADER_VALUES
65
66} msi_header_call_type_t;
67
68typedef struct msi_header_user_agent_s { /* Defines the device of the participant */
69 HEADER_VALUES
70
71} msi_header_user_agent_t;
72
73
74typedef struct msi_header_call_id_s { /* Call id that is used to identify the call */
75 HEADER_VALUES
76
77} msi_header_call_id_t;
78
79typedef struct msi_header_info_s { /* Defines informational message header */
80 HEADER_VALUES
81
82} msi_header_info_t;
83
84typedef struct msi_header_reason_s { /* Defines reason mostly for error messages */
85 HEADER_VALUES
86
87} msi_header_reason_t;
88
89struct msi_msg_s;
90
91/*
92 * Parses the header list to header types
93 */
94int msi_parse_headers ( struct msi_msg_s* _msg );
95
96/* Make sure it's null terminated */
97msi_header_t* msi_parse_raw_data ( const uint8_t* _data );
98
99#endif /* _MSI_HEADER_ */
diff --git a/toxmsi/toxmsi_message.c b/toxmsi/toxmsi_message.c
new file mode 100644
index 00000000..72d7ee01
--- /dev/null
+++ b/toxmsi/toxmsi_message.c
@@ -0,0 +1,267 @@
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif /* HAVE_CONFIG_H */
4
5#include "toxmsi_message.h"
6#include <stdlib.h>
7#include <string.h>
8#include "../toxrtp/toxrtp_helper.h"
9#include <assert.h>
10#include <stdlib.h>
11
12#define ALLOCATE_HEADER(_header_type, _var, _m_header_value) \
13_var = calloc( sizeof(_header_type), 1 ); \
14assert(_var); \
15_var->_header_value = t_strallcpy((const uint8_t*)_m_header_value);
16
17#define DEALLOCATE_HEADER(_header) \
18if ( _header && _header->_header_value ) { \
19free( _header->_header_value ); \
20free( _header ); }
21
22#define SET_HEADER(_header_type, _var, _m_header_value) \
23if ( _var ){ \
24free(_var->_header_value); \
25free(_var);} \
26ALLOCATE_HEADER( _header_type, _var, _m_header_value )
27
28
29/* Sets empty message
30 */
31void set_msg ( msi_msg_t* _msg )
32{
33 _msg->_call_type = NULL;
34 _msg->_version = NULL;
35 _msg->_request = NULL;
36 _msg->_response = NULL;
37 _msg->_friend_id = NULL;
38 _msg->_user_agent = NULL;
39 _msg->_call_id = NULL;
40 _msg->_reason = NULL;
41 _msg->_info = NULL;
42 _msg->_next = NULL;
43 _msg->_headers = NULL;
44}
45
46void msi_free_msg ( msi_msg_t* _msg )
47{
48 assert(_msg);
49
50 DEALLOCATE_HEADER(_msg->_call_type);
51 DEALLOCATE_HEADER(_msg->_friend_id);
52 DEALLOCATE_HEADER(_msg->_request);
53 DEALLOCATE_HEADER(_msg->_response);
54 DEALLOCATE_HEADER(_msg->_user_agent);
55 DEALLOCATE_HEADER(_msg->_version);
56 DEALLOCATE_HEADER(_msg->_info);
57 DEALLOCATE_HEADER(_msg->_reason);
58 DEALLOCATE_HEADER(_msg->_call_id);
59
60 free(_msg);
61}
62
63void append_header_to_string ( uint8_t* _dest, const uint8_t* _header_field, const uint8_t* _header_value )
64{
65 assert(_dest);
66 assert(_header_value);
67 assert(_header_field);
68
69 size_t _dest_len = t_memlen(_dest);
70
71 uint8_t* _storage_iterator = _dest + _dest_len;
72 const uint8_t* _header_fit = _header_field;
73 const uint8_t* _header_val = _header_value;
74 const uint8_t* _term_it = (const uint8_t*) _RAW_TERMINATOR;
75
76 while ( *_header_fit ){
77 *_storage_iterator = *_header_fit;
78 ++_header_fit;
79 ++_storage_iterator;
80 }
81
82 *_storage_iterator = ' '; /* place space */
83 ++_storage_iterator;
84
85 while ( *_header_val ){
86 *_storage_iterator = *_header_val;
87 ++_header_val;
88 ++_storage_iterator;
89 }
90
91 while ( *_term_it ){
92 *_storage_iterator = *_term_it;
93 ++_term_it;
94 ++_storage_iterator;
95 }
96}
97
98msi_msg_t* msi_parse_msg ( const uint8_t* _data )
99{
100 assert(_data);
101
102 msi_msg_t* _retu = calloc ( sizeof ( msi_msg_t ), 1 );
103 assert(_retu);
104
105 set_msg(_retu);
106
107 _retu->_headers = msi_parse_raw_data ( _data );
108
109 if ( msi_parse_headers (_retu) == FAILURE ) {
110 msi_free_msg(_retu);
111 return NULL;
112 }
113
114 if ( !_retu->_version || strcmp((const char*)_retu->_version->_header_value, VERSION_STRING) != 0 ){
115 msi_free_msg(_retu);
116 return NULL;
117 }
118
119 return _retu;
120}
121
122
123uint8_t* msi_msg_to_string ( msi_msg_t* _msg )
124{
125 assert(_msg);
126
127 uint8_t* _retu = calloc(sizeof(uint8_t), MSI_MAXMSG_SIZE );
128 assert(_retu);
129
130 t_memset(_retu, '\0', MSI_MAXMSG_SIZE);
131
132 if ( _msg->_version ){
133 append_header_to_string(_retu, (const uint8_t*)_VERSION_FIELD, _msg->_version->_header_value);
134 }
135
136 if ( _msg->_request ){
137 append_header_to_string(_retu, (const uint8_t*)_REQUEST_FIELD, _msg->_request->_header_value);
138 }
139
140 if ( _msg->_response ){
141 append_header_to_string(_retu, (const uint8_t*)_RESPONSE_FIELD, _msg->_response->_header_value);
142 }
143
144 if ( _msg->_friend_id ){
145 append_header_to_string(_retu, (const uint8_t*)_FRIENDID_FIELD, _msg->_friend_id->_header_value);
146 }
147
148 if ( _msg->_call_type ){
149 append_header_to_string(_retu, (const uint8_t*)_CALLTYPE_FIELD, _msg->_call_type->_header_value);
150 }
151
152 if ( _msg->_user_agent ){
153 append_header_to_string(_retu, (const uint8_t*)_USERAGENT_FIELD, _msg->_user_agent->_header_value);
154 }
155
156 if ( _msg->_info ){
157 append_header_to_string(_retu, (const uint8_t*)_INFO_FIELD, _msg->_info->_header_value);
158 }
159
160 if ( _msg->_call_id ){
161 append_header_to_string(_retu, (const uint8_t*)_CALL_ID_FIELD, _msg->_call_id->_header_value);
162 }
163
164 if ( _msg->_reason ){
165 append_header_to_string(_retu, (const uint8_t*)_REASON_FIELD, _msg->_reason->_header_value);
166 }
167
168 return _retu;
169}
170
171msi_msg_t* msi_msg_new ( uint8_t _type, const uint8_t* _typeid )
172{
173 msi_msg_t* _retu = calloc ( sizeof ( msi_msg_t ), 1 );
174 assert(_retu);
175
176 set_msg(_retu);
177
178 if ( _type == TYPE_REQUEST ){
179 ALLOCATE_HEADER( msi_header_request_t, _retu->_request, _typeid )
180 _retu->_response = NULL;
181
182 } else if ( _type == TYPE_RESPONSE ) {
183 ALLOCATE_HEADER( msi_header_response_t, _retu->_response, _typeid )
184 _retu->_request = NULL;
185
186 } else {
187 msi_free_msg(_retu);
188 return NULL;
189 }
190
191
192 ALLOCATE_HEADER( msi_header_version_t, _retu->_version, VERSION_STRING)
193
194 _retu->_friend_id = NULL;
195 _retu->_call_type = NULL;
196 _retu->_user_agent = NULL;
197 _retu->_info = NULL;
198
199 _retu->_next = NULL;
200
201 return _retu;
202}
203
204uint8_t* msi_genterate_call_id ( uint8_t* _storage, size_t _len )
205{
206 assert(_storage);
207
208 static const char _alphanum[] =
209 "0123456789"
210 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
211 "abcdefghijklmnopqrstuvwxyz"; /* avoids warning */
212
213 uint8_t _val = 0;
214 size_t _it;
215
216 /* Generate random values 1-255 */
217 for ( _it = 0; _it < _len; _it ++ ) {
218 while ( !_val ) _val = (uint8_t) _alphanum[ t_random(61) ];
219
220 _storage[_it] = _val;
221 _val = 0;
222 }
223
224 return _storage;
225}
226
227/* HEADER SETTING
228 */
229
230void msi_msg_set_call_type ( msi_msg_t* _msg, const uint8_t* _header_field )
231{
232 assert(_msg);
233 assert(_header_field);
234
235 SET_HEADER(msi_header_call_type_t, _msg->_call_type, _header_field)
236}
237void msi_msg_set_user_agent ( msi_msg_t* _msg, const uint8_t* _header_field )
238{
239 assert(_msg);
240 assert(_header_field);
241
242 SET_HEADER(msi_header_user_agent_t, _msg->_user_agent, _header_field)
243}
244void msi_msg_set_friend_id ( msi_msg_t* _msg, const uint8_t* _header_field )
245{
246 assert(_msg);
247 assert(_header_field);
248
249 SET_HEADER(msi_header_friendid_t, _msg->_friend_id, _header_field)
250}
251void msi_msg_set_info ( msi_msg_t* _msg, const uint8_t* _header_field )
252{
253}
254void msi_msg_set_reason ( msi_msg_t* _msg, const uint8_t* _header_field )
255{
256 assert(_msg);
257 assert(_header_field);
258
259 SET_HEADER(msi_header_reason_t, _msg->_reason, _header_field)
260}
261void msi_msg_set_call_id ( msi_msg_t* _msg, const uint8_t* _header_field )
262{
263 assert(_msg);
264 assert(_header_field);
265
266 SET_HEADER(msi_header_call_id_t, _msg->_call_id, _header_field)
267}
diff --git a/toxmsi/toxmsi_message.h b/toxmsi/toxmsi_message.h
new file mode 100644
index 00000000..87dfccc2
--- /dev/null
+++ b/toxmsi/toxmsi_message.h
@@ -0,0 +1,120 @@
1#ifndef _MSI_MESSAGE_H_
2#define _MSI_MESSAGE_H_
3
4#ifdef HAVE_CONFIG_H
5#include "config.h"
6#endif /* HAVE_CONFIG_H */
7
8#include <inttypes.h>
9#include "../toxcore/network.h"
10#include "../toxcore/tox.h"
11
12#include "toxmsi_header.h"
13
14#define TYPE_REQUEST 1
15#define TYPE_RESPONSE 2
16
17#define VERSION_STRING "0.2.2"
18
19#define MSI_MAXMSG_SIZE 65535
20
21typedef enum {
22 _invite,
23 _start,
24 _cancel,
25 _reject,
26 _end,
27
28} msi_request_t;
29
30static inline const uint8_t *stringify_request(msi_request_t _request)
31{
32 static const uint8_t* strings[] =
33 {
34 (uint8_t*)"INVITE",
35 (uint8_t*)"START",
36 (uint8_t*)"CANCEL",
37 (uint8_t*)"REJECT",
38 (uint8_t*)"END"
39 };
40
41 return strings[_request];
42}
43
44typedef enum {
45 _trying,
46 _ringing,
47 _starting,
48 _ending,
49 _error
50
51} msi_response_t;
52
53static inline const uint8_t *stringify_response(msi_response_t _response)
54{
55 static const uint8_t* strings[] =
56 {
57 (uint8_t*)"trying",
58 (uint8_t*)"ringing",
59 (uint8_t*)"starting",
60 (uint8_t*)"ending",
61 (uint8_t*)"error"
62 };
63
64 return strings[_response];
65}
66
67
68typedef struct msi_msg_s {
69 /* This is the header list which contains unparsed headers */
70 msi_header_t* _headers;
71
72 /* Headers parsed */
73 msi_header_version_t* _version;
74 msi_header_request_t* _request;
75 msi_header_response_t* _response;
76 msi_header_friendid_t* _friend_id;
77 msi_header_call_type_t* _call_type;
78 msi_header_user_agent_t* _user_agent;
79 msi_header_info_t* _info;
80 msi_header_reason_t* _reason;
81 msi_header_call_id_t* _call_id;
82
83 /* Pointer to next member since it's list duuh */
84 struct msi_msg_s* _next;
85
86} msi_msg_t;
87
88
89/*
90 * Parse data received from socket
91 */
92msi_msg_t* msi_parse_msg ( const uint8_t* _data );
93
94/*
95 * Make new message. Arguments: _type: (request, response); _type_field ( value )
96 */
97msi_msg_t* msi_msg_new ( uint8_t _type, const uint8_t* _type_field );
98
99/* Header setting */
100void msi_msg_set_call_type ( msi_msg_t* _msg, const uint8_t* _header_field );
101void msi_msg_set_user_agent ( msi_msg_t* _msg, const uint8_t* _header_field );
102void msi_msg_set_friend_id ( msi_msg_t* _msg, const uint8_t* _header_field );
103void msi_msg_set_info ( msi_msg_t* _msg, const uint8_t* _header_field );
104void msi_msg_set_reason ( msi_msg_t* _msg, const uint8_t* _header_field );
105void msi_msg_set_call_id ( msi_msg_t* _msg, const uint8_t* _header_field );
106
107
108uint8_t* msi_genterate_call_id ( uint8_t* _storage, size_t _len );
109/*
110 * Parses message struct to string.
111 * Allocates memory so don't forget to free it
112 */
113uint8_t* msi_msg_to_string ( msi_msg_t* _msg );
114
115/*
116 * msi_msg_s struct deallocator
117 */
118void msi_free_msg ( msi_msg_t* _msg );
119
120#endif /* _MSI_MESSAGE_H_ */