summaryrefslogtreecommitdiff
path: root/toxav/msi.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/msi.c')
-rw-r--r--toxav/msi.c703
1 files changed, 345 insertions, 358 deletions
diff --git a/toxav/msi.c b/toxav/msi.c
index c1342950..cc855613 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -33,9 +33,11 @@
33#include <string.h> 33#include <string.h>
34#include <stdlib.h> 34#include <stdlib.h>
35#include <stdbool.h> 35#include <stdbool.h>
36#include <assert.h>
36 37
37#define MSI_MAXMSG_SIZE 256 38#define MSI_MAXMSG_SIZE 256
38 39
40/* TODO send error on any calloc or etc */
39 41
40/** 42/**
41 * Protocol: 43 * Protocol:
@@ -63,14 +65,13 @@ typedef enum {
63typedef enum { 65typedef enum {
64 resp_ringing, 66 resp_ringing,
65 resp_starting, 67 resp_starting,
66 resp_error,
67} MSIResponse; 68} MSIResponse;
68 69
69 70
70#define GENERIC_HEADER(header, val_type) \ 71#define GENERIC_HEADER(header, val_type) \
71typedef struct { \ 72typedef struct { \
72val_type value; \ 73 val_type value; \
73bool exists; \ 74 bool exists; \
74} MSIHeader##header 75} MSIHeader##header
75 76
76 77
@@ -92,7 +93,207 @@ typedef struct {
92} MSIMessage; 93} MSIMessage;
93 94
94 95
95static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length ) 96int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length );
97uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length );
98int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg );
99int send_error ( Messenger* m, uint32_t friend_id, MSIError error );
100static void invoke_callback(MSICall* call, MSICallbackID cb);
101static MSICall *get_call ( MSISession *session, uint32_t friend_id );
102MSICall *new_call ( MSISession *session, uint32_t friend_id );
103void kill_call ( MSICall *call );
104void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data);
105int handle_recv_invite ( MSICall *call, const MSIMessage *msg );
106int handle_recv_start ( MSICall *call, const MSIMessage *msg );
107int handle_recv_reject ( MSICall *call, const MSIMessage *msg );
108int handle_recv_end ( MSICall *call, const MSIMessage *msg );
109int handle_recv_ringing ( MSICall *call, const MSIMessage *msg );
110int handle_recv_starting ( MSICall *call, const MSIMessage *msg );
111int handle_recv_error ( MSICall *call, const MSIMessage *msg );
112void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object );
113
114
115/**
116 * Public functions
117 */
118void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id)
119{
120 session->callbacks[id] = callback;
121}
122MSISession *msi_new ( Messenger *messenger )
123{
124 if (messenger == NULL) {
125 LOGGER_ERROR("Could not init session on empty messenger!");
126 return NULL;
127 }
128
129 MSISession *retu = calloc ( sizeof ( MSISession ), 1 );
130
131 if (retu == NULL) {
132 LOGGER_ERROR("Allocation failed! Program might misbehave!");
133 return NULL;
134 }
135
136 if (create_recursive_mutex(retu->mutex) != 0) {
137 LOGGER_ERROR("Failed to init mutex! Program might misbehave");
138 free(retu);
139 return NULL;
140 }
141
142 retu->messenger = messenger;
143
144 m_callback_msi_packet(messenger, handle_msi_packet, retu );
145
146 /* This is called when remote terminates session */
147 m_callback_connectionstatus_internal_av(messenger, on_peer_status, retu);
148
149 LOGGER_DEBUG("New msi session: %p ", retu);
150 return retu;
151}
152int msi_kill ( MSISession *session )
153{
154 if (session == NULL) {
155 LOGGER_ERROR("Tried to terminate non-existing session");
156 return -1;
157 }
158
159 m_callback_msi_packet((struct Messenger *) session->messenger, NULL, NULL);
160 pthread_mutex_lock(session->mutex);
161
162 if (session->calls) {
163 MSIMessage msg_end;
164 msg_end.request.exists = true;
165 msg_end.request.value = requ_end;
166
167 MSICall* it = get_call(session, session->calls_head);
168 for (; it; it = it->next) {
169 send_message(session->messenger, it->friend_id, &msg_end);
170 kill_call(it); /* This will eventually free session->calls */
171 }
172 }
173
174 pthread_mutex_unlock(session->mutex);
175 pthread_mutex_destroy(session->mutex);
176
177 LOGGER_DEBUG("Terminated session: %p", session);
178 free ( session );
179 return 0;
180}
181int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities )
182{
183 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
184
185 if (get_call(session, friend_id) != NULL) {
186 LOGGER_ERROR("Already in a call");
187 return -1;
188 }
189
190 (*call) = new_call ( session, friend_id );
191
192 if ( *call == NULL )
193 return -1;
194
195 (*call)->self_capabilities = capabilities;
196
197 MSIMessage msg_invite;
198 msg_invite.request.exists = true;
199 msg_invite.request.value = requ_invite;
200
201 msg_invite.capabilities.exists = true;
202 msg_invite.capabilities.value = capabilities;
203
204 msg_invite.mvfsz.exists = true;
205 msg_invite.mvfsz.value = htons(D_MVFSZ);
206
207 msg_invite.mvfpsz.exists = true;
208 msg_invite.mvfpsz.value = htons(D_MVFPSZ);
209
210 send_message ( (*call)->session->messenger, (*call)->friend_id, &msg_invite );
211
212 (*call)->state = msi_CallRequesting;
213
214 LOGGER_DEBUG("Invite sent");
215 return 0;
216}
217int msi_hangup ( MSICall* call )
218{
219 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index);
220
221 MSIMessage msg_end;
222 msg_end.request.exists = true;
223 msg_end.request.value = requ_end;
224 send_message ( call->session->messenger, call->friend_id, &msg_end );
225
226 kill_call(call);
227 return 0;
228}
229int msi_answer ( MSICall* call, uint8_t capabilities )
230{
231 LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id);
232
233 if ( call->state != msi_CallRequested ) {
234 LOGGER_ERROR("Call is in invalid state!");
235 return -1;
236 }
237
238 call->self_capabilities = capabilities;
239
240 MSIMessage msg_starting;
241 msg_starting.response.exists = true;
242 msg_starting.response.value = resp_starting;
243
244 msg_starting.capabilities.exists = true;
245 msg_starting.capabilities.value = capabilities;
246
247 msg_starting.mvfsz.exists = true;
248 msg_starting.mvfsz.value = htons(D_MVFSZ);
249
250 msg_starting.mvfpsz.exists = true;
251 msg_starting.mvfpsz.value = htons(D_MVFPSZ);
252
253 send_message ( call->session->messenger, call->friend_id, &msg_starting );
254
255 return 0;
256}
257int msi_reject ( MSICall* call )
258{
259 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
260
261 if ( call->state != msi_CallRequested ) {
262 LOGGER_ERROR("Call is in invalid state!");
263 return -1;
264 }
265
266 MSIMessage msg_reject;
267 msg_reject.request.exists = true;
268 msg_reject.request.value = requ_reject;
269
270 send_message ( call->session->messenger, call->friend_id, &msg_reject );
271
272 return 0;
273}
274int msi_change_csettings( MSICall* call, uint8_t capabilities )
275{
276 call->self_capabilities = capabilities;
277
278 MSIMessage msg_invite;
279 msg_invite.request.exists = true;
280 msg_invite.request.value = requ_invite;
281
282 msg_invite.capabilities.exists = true;
283 msg_invite.capabilities.value = capabilities;
284
285 send_message ( call->session->messenger, call->friend_id, &msg_invite );
286
287 return 0;
288}
289
290
291
292/**
293 * Private functions
294 */
295
296int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length )
96{ 297{
97 /* Parse raw data received from socket into MSIMessage struct */ 298 /* Parse raw data received from socket into MSIMessage struct */
98 299
@@ -116,10 +317,7 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length
116 } while(0) 317 } while(0)
117 318
118 319
119 if ( dest == NULL ) { 320 assert(dest);
120 LOGGER_ERROR("Could not parse message: no storage!");
121 return -1;
122 }
123 321
124 if ( length == 0 || data[length - 1] ) { /* End byte must have value 0 */ 322 if ( length == 0 || data[length - 1] ) { /* End byte must have value 0 */
125 LOGGER_ERROR("Invalid end byte"); 323 LOGGER_ERROR("Invalid end byte");
@@ -139,7 +337,7 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length
139 337
140 case IDResponse: 338 case IDResponse:
141 CHECK_SIZE(it, size_constraint, 1); 339 CHECK_SIZE(it, size_constraint, 1);
142 CHECK_ENUM_HIGH(it, resp_error); 340 CHECK_ENUM_HIGH(it, resp_starting);
143 SET_UINT8(it, dest->response); 341 SET_UINT8(it, dest->response);
144 it += 3; 342 it += 3;
145 break; 343 break;
@@ -179,22 +377,13 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length
179#undef SET_UINT8 377#undef SET_UINT8
180#undef SET_UINT16 378#undef SET_UINT16
181} 379}
182 380uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length )
183static uint8_t *parse_header ( MSIHeaderID id, uint8_t *dest, const void *value,
184 uint8_t value_len, uint16_t *length )
185{ 381{
186 /* Parse a single header for sending */ 382 /* Parse a single header for sending */
383 assert(dest);
384 assert(value);
385 assert(value_len);
187 386
188 if ( dest == NULL ) {
189 LOGGER_ERROR("No destination space!");
190 return NULL;
191 }
192
193 if (value == NULL || value_len == 0) {
194 LOGGER_ERROR("Empty header value");
195 return NULL;
196 }
197
198 *dest = id; 387 *dest = id;
199 dest ++; 388 dest ++;
200 *dest = value_len; 389 *dest = value_len;
@@ -206,20 +395,10 @@ static uint8_t *parse_header ( MSIHeaderID id, uint8_t *dest, const void *value,
206 395
207 return dest + value_len; /* Set to next position ready to be written */ 396 return dest + value_len; /* Set to next position ready to be written */
208} 397}
209 398int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg )
210
211
212static void call_invoke_callback(MSICall* call, MSICallbackID cb)
213{
214 if ( call->session->callbacks[cb] ) {
215 LOGGER_DEBUG("Invoking callback function: %d", cb);
216 call->session->callbacks[cb] ( call->session->agent_handler, call );
217 }
218}
219
220static int call_send_message ( MSICall *call, const MSIMessage *msg )
221{ 399{
222 /* Parse and send message */ 400 /* Parse and send message */
401 assert(m);
223 402
224 uint8_t parsed [MSI_MAXMSG_SIZE]; 403 uint8_t parsed [MSI_MAXMSG_SIZE];
225 404
@@ -228,33 +407,33 @@ static int call_send_message ( MSICall *call, const MSIMessage *msg )
228 407
229 if (msg->request.exists) { 408 if (msg->request.exists) {
230 uint8_t cast = msg->request.value; 409 uint8_t cast = msg->request.value;
231 it = parse_header(IDRequest, it, &cast, 410 it = msg_parse_header_out(IDRequest, it, &cast,
232 sizeof(cast), &size); 411 sizeof(cast), &size);
233 } 412 }
234 413
235 if (msg->response.exists) { 414 if (msg->response.exists) {
236 uint8_t cast = msg->response.value; 415 uint8_t cast = msg->response.value;
237 it = parse_header(IDResponse, it, &cast, 416 it = msg_parse_header_out(IDResponse, it, &cast,
238 sizeof(cast), &size); 417 sizeof(cast), &size);
239 } 418 }
240 419
241 if (msg->error.exists) { 420 if (msg->error.exists) {
242 it = parse_header(IDError, it, &msg->error.value, 421 it = msg_parse_header_out(IDError, it, &msg->error.value,
243 sizeof(msg->error.value), &size); 422 sizeof(msg->error.value), &size);
244 } 423 }
245 424
246 if (msg->capabilities.exists) { 425 if (msg->capabilities.exists) {
247 it = parse_header(IDCapabilities, it, &msg->capabilities.value, 426 it = msg_parse_header_out(IDCapabilities, it, &msg->capabilities.value,
248 sizeof(msg->capabilities.value), &size); 427 sizeof(msg->capabilities.value), &size);
249 } 428 }
250 429
251 if (msg->mvfsz.exists) { 430 if (msg->mvfsz.exists) {
252 it = parse_header(IDMVFSZ, it, &msg->mvfsz.value, 431 it = msg_parse_header_out(IDMVFSZ, it, &msg->mvfsz.value,
253 sizeof(msg->mvfsz.value), &size); 432 sizeof(msg->mvfsz.value), &size);
254 } 433 }
255 434
256 if (msg->mvfpsz.exists) { 435 if (msg->mvfpsz.exists) {
257 it = parse_header(IDMVFPSZ, it, &msg->mvfpsz.value, 436 it = msg_parse_header_out(IDMVFPSZ, it, &msg->mvfpsz.value,
258 sizeof(msg->mvfpsz.value), &size); 437 sizeof(msg->mvfpsz.value), &size);
259 } 438 }
260 439
@@ -266,47 +445,50 @@ static int call_send_message ( MSICall *call, const MSIMessage *msg )
266 return -1; 445 return -1;
267 } 446 }
268 447
269 if ( m_msi_packet(call->session->messenger_handle, call->friend_id, parsed, size) ) { 448 if ( m_msi_packet(m, friend_id, parsed, size) ) {
270 LOGGER_DEBUG("Sent message"); 449 LOGGER_DEBUG("Sent message");
271 return 0; 450 return 0;
272 } 451 }
273 452
274 return -1; 453 return -1;
275} 454}
276 455int send_error ( Messenger* m, uint32_t friend_id, MSIError error )
277static int call_send_error ( MSICall *call, MSIError error )
278{ 456{
279 /* Send error message */ 457 /* Send error message */
458 assert(m);
280 459
281 if (!call) { 460 LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_id);
282 LOGGER_WARNING("Cannot handle error on 'null' call");
283 return -1;
284 }
285
286 LOGGER_DEBUG("Sending error: %d to friend: %d", error, call->friend_id);
287 461
288 MSIMessage msg_error; 462 MSIMessage msg_error;
289 msg_error.response.exists = true;
290 msg_error.response.value = resp_error;
291 463
292 msg_error.error.exists = true; 464 msg_error.error.exists = true;
293 msg_error.error.value = error; 465 msg_error.error.value = error;
294 466
295 call_send_message ( call, &msg_error ); 467 send_message ( m, friend_id, &msg_error );
296 return 0; 468 return 0;
297} 469}
298 470static void invoke_callback(MSICall* call, MSICallbackID cb)
299 471{
472 assert(call);
473
474 if ( call->session->callbacks[cb] ) {
475 LOGGER_DEBUG("Invoking callback function: %d", cb);
476 call->session->callbacks[cb] ( call->session->av, call );
477 }
478}
300static MSICall *get_call ( MSISession *session, uint32_t friend_id ) 479static MSICall *get_call ( MSISession *session, uint32_t friend_id )
301{ 480{
481 assert(session);
482
302 if (session->calls == NULL || session->calls_tail < friend_id) 483 if (session->calls == NULL || session->calls_tail < friend_id)
303 return NULL; 484 return NULL;
304 485
305 return session->calls[friend_id]; 486 return session->calls[friend_id];
306} 487}
307 488MSICall *new_call ( MSISession *session, uint32_t friend_id )
308static MSICall *new_call ( MSISession *session, uint32_t friend_id )
309{ 489{
490 assert(session);
491
310 MSICall *rc = calloc(sizeof(MSICall), 1); 492 MSICall *rc = calloc(sizeof(MSICall), 1);
311 493
312 if (rc == NULL) 494 if (rc == NULL)
@@ -353,8 +535,7 @@ static MSICall *new_call ( MSISession *session, uint32_t friend_id )
353 session->calls[friend_id] = rc; 535 session->calls[friend_id] = rc;
354 return rc; 536 return rc;
355} 537}
356 538void kill_call ( MSICall *call )
357static void kill_call ( MSICall *call )
358{ 539{
359 if ( call == NULL ) 540 if ( call == NULL )
360 return; 541 return;
@@ -386,22 +567,21 @@ CLEAR:
386 session->calls = NULL; 567 session->calls = NULL;
387 free(call); 568 free(call);
388} 569}
389 570void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data)
390
391
392static void on_remote_connection_change(Messenger *messenger, int friend_id, uint8_t status, void *session_p)
393{ 571{
394 (void)messenger; 572 (void)m;
395 MSISession *session = session_p; 573 MSISession *session = data;
396 574
397 switch ( status ) { 575 switch ( status ) {
398 case 0: { /* Went offline */ 576 case 0: { /* Friend is now offline */
577 LOGGER_DEBUG("Friend %d is now offline", friend_id);
578
399 MSICall* call = get_call(session, friend_id); 579 MSICall* call = get_call(session, friend_id);
400 580
401 if (call == NULL) 581 if (call == NULL)
402 return; 582 return;
403 583
404 call_invoke_callback(call, msi_OnPeerTimeout); 584 invoke_callback(call, msi_OnPeerTimeout);
405 kill_call(call); 585 kill_call(call);
406 } 586 }
407 break; 587 break;
@@ -410,16 +590,9 @@ static void on_remote_connection_change(Messenger *messenger, int friend_id, uin
410 break; 590 break;
411 } 591 }
412} 592}
413 593int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
414
415
416/********** Request handlers **********/
417static int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
418{ 594{
419 if ( call == NULL ) { 595 assert(call);
420 LOGGER_WARNING("Session: %p Handling 'invite' on no call");
421 return -1;
422 }
423 596
424 MSISession* session = call->session; 597 MSISession* session = call->session;
425 598
@@ -427,19 +600,7 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
427 600
428 if (!msg->capabilities.exists) { 601 if (!msg->capabilities.exists) {
429 LOGGER_WARNING("Session: %p Invalid capabilities on 'invite'"); 602 LOGGER_WARNING("Session: %p Invalid capabilities on 'invite'");
430 /* TODO send error */ 603 call->error = msi_InvalidMessage;
431 return -1;
432 }
433
434 if (!msg->mvfsz.exists) {
435 LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'");
436 /* TODO send error */
437 return -1;
438 }
439
440 if (!msg->mvfpsz.exists) {
441 LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'");
442 /* TODO send error */
443 return -1; 604 return -1;
444 } 605 }
445 606
@@ -456,14 +617,32 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
456 617
457 LOGGER_DEBUG("Glare detected!"); 618 LOGGER_DEBUG("Glare detected!");
458 619
459 call->peer_capabilities = msg->capabilities; 620 if (!msg->mvfsz.exists) {
621 LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'");
622 call->error = msi_InvalidMessage;
623 return -1;
624 }
625
626 if (!msg->mvfpsz.exists) {
627 LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'");
628 call->error = msi_InvalidMessage;
629 return -1;
630 }
631
632 call->peer_capabilities = msg->capabilities.value;
460 633
461 call->peer_mvfsz = ntohs(msg->mvfsz.value); 634 call->peer_mvfsz = ntohs(msg->mvfsz.value);
462 call->peer_mvfpsz = ntohs(msg->mvfpsz.value); 635 call->peer_mvfpsz = ntohs(msg->mvfpsz.value);
463 636
637 if (call->peer_mvfsz > call->peer_mvfpsz) {
638 LOGGER_WARNING("Session: %p mvfsz param greater than mvfpsz on 'invite'");
639 call->error = msi_InvalidParam;
640 return -1;
641 }
642
464 /* Send response */ 643 /* Send response */
465 response.response.value = resp_starting; 644 response.response.value = resp_starting;
466 call_send_message ( call, &response ); 645 send_message ( call->session->messenger, call->friend_id, &response );
467 646
468 return 0; 647 return 0;
469 } else if ( call->state == msi_CallActive ) { 648 } else if ( call->state == msi_CallActive ) {
@@ -473,21 +652,33 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
473 */ 652 */
474 LOGGER_DEBUG("Peer is changing capabilities"); 653 LOGGER_DEBUG("Peer is changing capabilities");
475 654
476 call->peer_capabilities = msg->capabilities;
477
478 call->peer_mvfsz = ntohs(msg->mvfsz.value);
479 call->peer_mvfpsz = ntohs(msg->mvfpsz.value);
480
481 /* Send response */ 655 /* Send response */
482 response.response.value = resp_starting; 656 response.response.value = resp_starting;
483 call_send_message ( call, &response ); 657 send_message ( call->session->messenger, call->friend_id, &response );
484 658
659 if ( call->peer_capabilities != msg->capabilities.value) {
660 /* Only invoke callback if capabilities changed */
661 call->peer_capabilities = msg->capabilities.value;
662 invoke_callback(call, msi_OnCapabilities);
663 }
485 664
486 call_invoke_callback(call, msi_OnCapabilities);
487 return 0; 665 return 0;
488 } 666 }
489 667
490 call->peer_capabilities = msg->capabilities; 668
669 if (!msg->mvfsz.exists) {
670 LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'");
671 call->error = msi_InvalidMessage;
672 return -1;
673 }
674
675 if (!msg->mvfpsz.exists) {
676 LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'");
677 call->error = msi_InvalidMessage;
678 return -1;
679 }
680
681 call->peer_capabilities = msg->capabilities.value;
491 682
492 call->peer_mvfsz = ntohs(msg->mvfsz.value); 683 call->peer_mvfsz = ntohs(msg->mvfsz.value);
493 call->peer_mvfpsz = ntohs(msg->mvfpsz.value); 684 call->peer_mvfpsz = ntohs(msg->mvfpsz.value);
@@ -496,23 +687,19 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
496 687
497 /* Send response */ 688 /* Send response */
498 response.response.value = resp_ringing; 689 response.response.value = resp_ringing;
499 call_send_message ( call, &response ); 690 send_message ( call->session->messenger, call->friend_id, &response );
500 691
501 692
502 call_invoke_callback(call, msi_OnInvite); 693 invoke_callback(call, msi_OnInvite);
503 return 0; 694 return 0;
504} 695}
505 696int handle_recv_start ( MSICall *call, const MSIMessage *msg )
506static int handle_recv_start ( MSICall *call, const MSIMessage *msg )
507{ 697{
508 if ( call == NULL ) { 698 assert(call);
509 LOGGER_WARNING("Session: %p Handling 'start' on no call");
510 return -1;
511 }
512 699
513 if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { 700 if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) {
514 LOGGER_WARNING("Session: %p Invalid call state on 'start'"); 701 LOGGER_WARNING("Session: %p Invalid call state on 'start'");
515 /* TODO send error */ 702 call->error = msi_InvalidState;
516 return -1; 703 return -1;
517 } 704 }
518 705
@@ -521,105 +708,88 @@ static int handle_recv_start ( MSICall *call, const MSIMessage *msg )
521 LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id ); 708 LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id );
522 709
523 call->state = msi_CallActive; 710 call->state = msi_CallActive;
524 call_invoke_callback(call, msi_OnStart); 711 invoke_callback(call, msi_OnStart);
525 712
526 return 0; 713 return 0;
527} 714}
528 715int handle_recv_reject ( MSICall *call, const MSIMessage *msg )
529static int handle_recv_reject ( MSICall *call, const MSIMessage *msg )
530{ 716{
531 if ( call == NULL ) { 717 assert(call);
532 LOGGER_WARNING("Session: %p Handling 'start' on no call");
533 return -1;
534 }
535 718
536 (void)msg; 719 (void)msg;
537 720
538 if ( call->state != msi_CallRequesting ) { 721 if ( call->state != msi_CallRequesting ) {
539 LOGGER_WARNING("Session: %p Invalid call state on 'reject'"); 722 LOGGER_WARNING("Session: %p Invalid call state on 'reject'");
540 /* TODO send error */ 723 call->error = msi_InvalidState;
541 return -1; 724 return -1;
542 } 725 }
543 726
544 LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id); 727 LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id);
545 728
546 call_invoke_callback(call, msi_OnReject); 729 invoke_callback(call, msi_OnReject);
547 kill_call(call); 730 kill_call(call);
548 731
549 return 0; 732 return 0;
550} 733}
551 734int handle_recv_end ( MSICall *call, const MSIMessage *msg )
552static int handle_recv_end ( MSICall *call, const MSIMessage *msg )
553{ 735{
554 (void)msg; 736 assert(call);
555 737
556 if ( call == NULL ) { 738 (void)msg;
557 LOGGER_WARNING("Session: %p Handling 'start' on no call");
558 return -1;
559 }
560 739
561 LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id); 740 LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id);
562 741
563 call_invoke_callback(call, msi_OnEnd); 742 invoke_callback(call, msi_OnEnd);
564 kill_call ( call ); 743 kill_call ( call );
565 744
566 return 0; 745 return 0;
567} 746}
568 747int handle_recv_ringing ( MSICall *call, const MSIMessage *msg )
569/********** Response handlers **********/
570static int handle_recv_ringing ( MSICall *call, const MSIMessage *msg )
571{ 748{
572 if ( call == NULL ) { 749 assert(call);
573 LOGGER_WARNING("Session: %p Handling 'start' on no call");
574 return -1;
575 }
576 750
577 (void)msg; 751 (void)msg;
578 752
579 if ( call->state != msi_CallRequesting ) { 753 if ( call->state != msi_CallRequesting ) {
580 LOGGER_WARNING("Session: %p Invalid call state on 'ringing'"); 754 LOGGER_WARNING("Session: %p Invalid call state on 'ringing'");
581 /* TODO send error */ 755 call->error = msi_InvalidState;
582 return -1; 756 return -1;
583 } 757 }
584 758
585 LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id ); 759 LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id );
586 760
587 call_invoke_callback(call, msi_OnRinging); 761 invoke_callback(call, msi_OnRinging);
588 return 0; 762 return 0;
589} 763}
590 764int handle_recv_starting ( MSICall *call, const MSIMessage *msg )
591static int handle_recv_starting ( MSICall *call, const MSIMessage *msg )
592{ 765{
593 if ( call == NULL ) { 766 assert(call);
594 LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call");
595 return 0;
596 }
597 767
598 if ( call->state == msi_CallActive ) { 768 if ( call->state == msi_CallActive ) {
599 LOGGER_DEBUG("Capabilities change confirmed"); 769 LOGGER_DEBUG("Capabilities change confirmed");
600 return 0; 770 return 0;
601 } else if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { 771 } else if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) {
602 LOGGER_WARNING("Session: %p Invalid call state on 'starting'"); 772 LOGGER_WARNING("Session: %p Invalid call state on 'starting'");
603 /* TODO send error */ 773 call->error = msi_InvalidState;
604 return -1; 774 return -1;
605 } 775 }
606 776
607 if (call->state == msi_CallRequesting) { 777 if (call->state == msi_CallRequesting) {
608 if (!msg->capabilities.exists) { 778 if (!msg->capabilities.exists) {
609 LOGGER_WARNING("Session: %p Invalid capabilities on 'starting'"); 779 LOGGER_WARNING("Session: %p Invalid capabilities on 'starting'");
610 /* TODO send error */ 780 call->error = msi_InvalidParam;
611 return -1; 781 return -1;
612 } 782 }
613 783
614 if (!msg->mvfsz.exists) { 784 if (!msg->mvfsz.exists) {
615 LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); 785 LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'");
616 /* TODO send error */ 786 call->error = msi_InvalidParam;
617 return -1; 787 return -1;
618 } 788 }
619 789
620 if (!msg->mvfpsz.exists) { 790 if (!msg->mvfpsz.exists) {
621 LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); 791 LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'");
622 /* TODO send error */ 792 call->error = msi_InvalidParam;
623 return -1; 793 return -1;
624 } 794 }
625 795
@@ -628,8 +798,15 @@ static int handle_recv_starting ( MSICall *call, const MSIMessage *msg )
628 call->peer_mvfsz = ntohs(msg->mvfsz.value); 798 call->peer_mvfsz = ntohs(msg->mvfsz.value);
629 call->peer_mvfpsz = ntohs(msg->mvfpsz.value); 799 call->peer_mvfpsz = ntohs(msg->mvfpsz.value);
630 800
801
802 if (call->peer_mvfsz > call->peer_mvfpsz) {
803 LOGGER_WARNING("Session: %p mvfsz param greater than mvfpsz on 'invite'");
804 call->error = msi_InvalidParam;
805 return -1;
806 }
807
631 call->state = msi_CallActive; 808 call->state = msi_CallActive;
632 call_invoke_callback(call, msi_OnStart); 809 invoke_callback(call, msi_OnStart);
633 } 810 }
634 /* Otherwise it's a glare case so don't start until 'start' is recved */ 811 /* Otherwise it's a glare case so don't start until 'start' is recved */
635 812
@@ -637,65 +814,55 @@ static int handle_recv_starting ( MSICall *call, const MSIMessage *msg )
637 MSIMessage msg_start; 814 MSIMessage msg_start;
638 msg_start.request.exists = true; 815 msg_start.request.exists = true;
639 msg_start.request.value = requ_start; 816 msg_start.request.value = requ_start;
640 call_send_message ( call, &msg_start ); 817 send_message ( call->session->messenger, call->friend_id, &msg_start );
641 818
642 return 0; 819 return 0;
643} 820}
644 821int handle_recv_error ( MSICall *call, const MSIMessage *msg )
645static int handle_recv_error ( MSICall *call, const MSIMessage *msg )
646{ 822{
647 if ( call == NULL ) { 823 assert(call);
648 LOGGER_WARNING("Handling 'error' on non-existing call!");
649 return -1;
650 }
651 824
652 LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id ); 825 LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id );
826
827 call->error = msg->error.value;
828 invoke_callback(call, msi_OnError);
653 829
654 call_invoke_callback(call, msi_OnError); 830 return 0;
655
656 /* TODO Handle error accordingly */
657
658 return -1;
659} 831}
660 832void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object )
661static void handle_msi_packet ( Messenger *messenger, int friend_id, const uint8_t *data,
662 uint16_t length, void *object )
663{ 833{
664 LOGGER_DEBUG("Got msi message"); 834 LOGGER_DEBUG("Got msi message");
665 835
666 /* Unused */
667 (void)messenger;
668
669 MSISession *session = object; 836 MSISession *session = object;
670 MSIMessage msg; 837 MSIMessage msg;
838
839 int rc = 0;
671 840
672 if ( parse_input ( &msg, data, length ) == -1 ) { 841 if ( msg_parse_in ( &msg, data, length ) == -1 ) {
673 LOGGER_WARNING("Error parsing message"); 842 LOGGER_WARNING("Error parsing message");
843 send_error(m, friend_id, msi_InvalidMessage);
674 return; 844 return;
675 } else { 845 } else {
676 LOGGER_DEBUG("Successfully parsed message"); 846 LOGGER_DEBUG("Successfully parsed message");
677 } 847 }
678 848
679 pthread_mutex_lock(session->mutex);
680
681 MSICall *call = get_call(session, friend_id); 849 MSICall *call = get_call(session, friend_id);
682 850
683 if (call == NULL) { 851 if (call == NULL) {
684 if (msg.request != requ_invite) { 852 if (msg.request.value != requ_invite) {
685 /* TODO send error */ 853 send_error(m, friend_id, msi_StrayMessage);
686 return; 854 return;
687 } 855 }
688 856
689 call = new_call(session, friend_id); 857 call = new_call(session, friend_id);
690 if (call == NULL) { 858 if (call == NULL) {
691 /* TODO send error */ 859 send_error(m, friend_id, msi_SystemError);
692 return; 860 return;
693 } 861 }
694 } 862 }
695 863
696 864
697 /* Now handle message */ 865 /* Now handle message */
698 int rc = 0;
699 if ( msg.request.exists ) { /* Handle request */ 866 if ( msg.request.exists ) { /* Handle request */
700 switch (msg.request.value) { 867 switch (msg.request.value) {
701 case requ_invite: 868 case requ_invite:
@@ -723,201 +890,21 @@ static void handle_msi_packet ( Messenger *messenger, int friend_id, const uint8
723 case resp_starting: 890 case resp_starting:
724 rc = handle_recv_starting ( call, &msg ); 891 rc = handle_recv_starting ( call, &msg );
725 break; 892 break;
726
727 case resp_error:
728 rc = handle_recv_error ( call, &msg );
729 break;
730 } 893 }
894 } else if (msg.error.exists) {
895 handle_recv_error ( call, &msg );
896 rc = -1;
731 } else { 897 } else {
732 LOGGER_WARNING("Invalid message: no resp nor requ headers"); 898 LOGGER_WARNING("Invalid message; none of the request, response or error!");
733 /* TODO send error */ 899 call->error = msi_InvalidMessage;
734 rc = -1; 900 rc = -1;
735 } 901 }
736 902
737 if (rc == -1)
738 kill_call(call);
739 903
740 pthread_mutex_unlock(session->mutex); 904 if (rc == -1) {
741} 905 if (call->error != msi_ErrorNone)
742 906 send_error(m, friend_id, call->error);
743
744
745/********** User functions **********/
746void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id)
747{
748 session->callbacks[id] = callback;
749}
750
751MSISession *msi_new ( Messenger *messenger )
752{
753 if (messenger == NULL) {
754 LOGGER_ERROR("Could not init session on empty messenger!");
755 return NULL;
756 }
757
758 MSISession *retu = calloc ( sizeof ( MSISession ), 1 );
759
760 if (retu == NULL) {
761 LOGGER_ERROR("Allocation failed! Program might misbehave!");
762 return NULL;
763 }
764
765 if (create_recursive_mutex(retu->mutex) != 0) {
766 LOGGER_ERROR("Failed to init mutex! Program might misbehave");
767 free(retu);
768 return NULL;
769 }
770
771 retu->messenger_handle = messenger;
772
773 m_callback_msi_packet(messenger, handle_msi_packet, retu );
774
775 /* This is called when remote terminates session */
776 m_callback_connectionstatus_internal_av(messenger, on_remote_connection_change, retu);
777
778 LOGGER_DEBUG("New msi session: %p ", retu);
779 return retu;
780}
781
782int msi_kill ( MSISession *session )
783{
784 if (session == NULL) {
785 LOGGER_ERROR("Tried to terminate non-existing session");
786 return -1;
787 }
788
789 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL);
790 pthread_mutex_lock(session->mutex);
791
792 if (session->calls) {
793 MSIMessage msg_end;
794 msg_end.request.exists = true;
795 msg_end.request.value = requ_end;
796 907
797 MSICall* it = get_call(session, session->calls_head); 908 kill_call(call);
798 for (; it; it = it->next) {
799 call_send_message(it, &msg_end);
800 kill_call(it); /* This will eventually free session->calls */
801 }
802 }
803
804 pthread_mutex_unlock(session->mutex);
805 pthread_mutex_destroy(session->mutex);
806
807 LOGGER_DEBUG("Terminated session: %p", session);
808 free ( session );
809 return 0;
810}
811
812int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities )
813{
814 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
815
816 if (get_call(session, friend_id) != NULL) {
817 LOGGER_ERROR("Already in a call");
818 return -1;
819 }
820
821 *call = new_call ( session, friend_id );
822
823 if ( *call == NULL )
824 return -1;
825
826 *call->self_capabilities = capabilities;
827
828 MSIMessage msg_invite;
829 msg_invite.request.exists = true;
830 msg_invite.request.value = requ_invite;
831
832 msg_invite.capabilities.exists = true;
833 msg_invite.capabilities.value = capabilities;
834
835 msg_invite.mvfsz.exists = true;
836 msg_invite.mvfsz.value = htons(D_MVFSZ);
837
838 msg_invite.mvfpsz.exists = true;
839 msg_invite.mvfpsz.value = htons(D_MVFPSZ);
840
841 call_send_message ( *call, &msg_invite );
842
843 *call->state = msi_CallRequesting;
844
845 LOGGER_DEBUG("Invite sent");
846 return 0;
847}
848
849int msi_hangup ( MSICall* call )
850{
851 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index);
852
853 MSIMessage msg_end;
854 msg_end.request.exists = true;
855 msg_end.request.value = requ_end;
856 call_send_message ( call, &msg_end );
857
858 kill_call(call);
859 return 0;
860}
861
862int msi_answer ( MSICall* call, uint8_t capabilities )
863{
864 LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id);
865
866 if ( call->state != msi_CallRequested ) {
867 LOGGER_ERROR("Call is in invalid state!");
868 return -1;
869 }
870
871 call->self_capabilities = capabilities;
872
873 MSIMessage msg_starting;
874 msg_starting.response.exists = true;
875 msg_starting.response.value = resp_starting;
876
877 msg_starting.capabilities.exists = true;
878 msg_starting.capabilities.value = capabilities;
879
880 msg_starting.mvfsz.exists = true;
881 msg_starting.mvfsz.value = htons(D_MVFSZ);
882
883 msg_starting.mvfpsz.exists = true;
884 msg_starting.mvfpsz.value = htons(D_MVFPSZ);
885
886 call_send_message ( call, &msg_starting );
887
888 return 0;
889}
890
891int msi_reject ( MSICall* call )
892{
893 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
894
895 if ( call->state != msi_CallRequested ) {
896 LOGGER_ERROR("Call is in invalid state!");
897 return -1;
898 } 909 }
899
900 MSIMessage msg_reject;
901 msg_reject.request.exists = true;
902 msg_reject.request.value = requ_reject;
903
904 call_send_message ( call, &msg_reject );
905
906 return 0;
907} 910}
908
909int msi_change_csettings( MSICall* call, uint8_t capabilities )
910{
911 call->self_capabilities = capabilities;
912
913 MSIMessage msg_invite;
914 msg_invite.request.exists = true;
915 msg_invite.request.value = requ_invite;
916
917 msg_invite.capabilities.exists = true;
918 msg_invite.capabilities.value = capabilities;
919
920 call_send_message ( *call, &msg_invite );
921
922 return 0;
923} \ No newline at end of file