summaryrefslogtreecommitdiff
path: root/toxav/msi.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/msi.c')
-rw-r--r--toxav/msi.c111
1 files changed, 87 insertions, 24 deletions
diff --git a/toxav/msi.c b/toxav/msi.c
index f179a7ab..ac900dac 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -99,7 +99,9 @@ void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint1
99 */ 99 */
100void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id) 100void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id)
101{ 101{
102 pthread_mutex_lock(session->mutex);
102 session->callbacks[id] = callback; 103 session->callbacks[id] = callback;
104 pthread_mutex_unlock(session->mutex);
103} 105}
104MSISession *msi_new ( Messenger *messenger ) 106MSISession *msi_new ( Messenger *messenger )
105{ 107{
@@ -163,15 +165,19 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_
163{ 165{
164 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); 166 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
165 167
168 pthread_mutex_lock(session->mutex);
166 if (get_call(session, friend_id) != NULL) { 169 if (get_call(session, friend_id) != NULL) {
167 LOGGER_ERROR("Already in a call"); 170 LOGGER_ERROR("Already in a call");
171 pthread_mutex_unlock(session->mutex);
168 return -1; 172 return -1;
169 } 173 }
170 174
171 (*call) = new_call ( session, friend_id ); 175 (*call) = new_call ( session, friend_id );
172 176
173 if ( *call == NULL ) 177 if ( *call == NULL ) {
178 pthread_mutex_unlock(session->mutex);
174 return -1; 179 return -1;
180 }
175 181
176 (*call)->self_capabilities = capabilities; 182 (*call)->self_capabilities = capabilities;
177 183
@@ -180,7 +186,7 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_
180 186
181 msg.capabilities.exists = true; 187 msg.capabilities.exists = true;
182 msg.capabilities.value = capabilities; 188 msg.capabilities.value = capabilities;
183 189
184 msg.vfpsz.exists = true; 190 msg.vfpsz.exists = true;
185 msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE); 191 msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE);
186 192
@@ -189,28 +195,37 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_
189 (*call)->state = msi_CallRequesting; 195 (*call)->state = msi_CallRequesting;
190 196
191 LOGGER_DEBUG("Invite sent"); 197 LOGGER_DEBUG("Invite sent");
198 pthread_mutex_unlock(session->mutex);
192 return 0; 199 return 0;
193} 200}
194int msi_hangup ( MSICall* call ) 201int msi_hangup ( MSICall* call )
195{ 202{
196 LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_id); 203 LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_id);
197 204
205 MSISession* session = call->session;
206 pthread_mutex_lock(session->mutex);
207
198 MSIMessage msg; 208 MSIMessage msg;
199 msg_init(&msg, requ_pop); 209 msg_init(&msg, requ_pop);
200 210
201 send_message ( call->session->messenger, call->friend_id, &msg ); 211 send_message ( session->messenger, call->friend_id, &msg );
202 212
203 kill_call(call); 213 kill_call(call);
214 pthread_mutex_unlock(session->mutex);
204 return 0; 215 return 0;
205} 216}
206int msi_answer ( MSICall* call, uint8_t capabilities ) 217int msi_answer ( MSICall* call, uint8_t capabilities )
207{ 218{
208 LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id); 219 LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id);
209 220
221 MSISession* session = call->session;
222 pthread_mutex_lock(session->mutex);
223
210 if ( call->state != msi_CallRequested ) { 224 if ( call->state != msi_CallRequested ) {
211 /* Though sending in invalid state will not cause anything wierd 225 /* Though sending in invalid state will not cause anything wierd
212 * Its better to not do it like a maniac */ 226 * Its better to not do it like a maniac */
213 LOGGER_ERROR("Call is in invalid state!"); 227 LOGGER_ERROR("Call is in invalid state!");
228 pthread_mutex_unlock(session->mutex);
214 return -1; 229 return -1;
215 } 230 }
216 231
@@ -225,9 +240,10 @@ int msi_answer ( MSICall* call, uint8_t capabilities )
225 msg.vfpsz.exists = true; 240 msg.vfpsz.exists = true;
226 msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE); 241 msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE);
227 242
228 send_message ( call->session->messenger, call->friend_id, &msg ); 243 send_message ( session->messenger, call->friend_id, &msg );
229 244
230 call->state = msi_CallActive; 245 call->state = msi_CallActive;
246 pthread_mutex_unlock(session->mutex);
231 247
232 return 0; 248 return 0;
233} 249}
@@ -235,6 +251,9 @@ int msi_change_capabilities( MSICall* call, uint8_t capabilities )
235{ 251{
236 LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_id); 252 LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_id);
237 253
254 MSISession* session = call->session;
255 pthread_mutex_lock(session->mutex);
256
238 if ( call->state != msi_CallActive ) { 257 if ( call->state != msi_CallActive ) {
239 /* Sending capabilities change can cause error on other side if 258 /* Sending capabilities change can cause error on other side if
240 * the call is not active since we don't send header 'vfpsz'. 259 * the call is not active since we don't send header 'vfpsz'.
@@ -244,6 +263,7 @@ int msi_change_capabilities( MSICall* call, uint8_t capabilities )
244 * like new. TODO: explain this better 263 * like new. TODO: explain this better
245 */ 264 */
246 LOGGER_ERROR("Call is in invalid state!"); 265 LOGGER_ERROR("Call is in invalid state!");
266 pthread_mutex_unlock(session->mutex);
247 return -1; 267 return -1;
248 } 268 }
249 269
@@ -257,6 +277,7 @@ int msi_change_capabilities( MSICall* call, uint8_t capabilities )
257 277
258 send_message ( call->session->messenger, call->friend_id, &msg ); 278 send_message ( call->session->messenger, call->friend_id, &msg );
259 279
280 pthread_mutex_unlock(session->mutex);
260 return 0; 281 return 0;
261} 282}
262 283
@@ -316,7 +337,7 @@ int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length )
316 337
317 case IDError: 338 case IDError:
318 CHECK_SIZE(it, size_constraint, 1); 339 CHECK_SIZE(it, size_constraint, 1);
319 CHECK_ENUM_HIGH(it, msi_ErrUndisclosed); 340 CHECK_ENUM_HIGH(it, msi_EUndisclosed);
320 SET_UINT8(it, dest->error); 341 SET_UINT8(it, dest->error);
321 break; 342 break;
322 343
@@ -440,7 +461,7 @@ int invoke_callback(MSICall* call, MSICallbackID cb)
440 if ( call->session->callbacks[cb] ) { 461 if ( call->session->callbacks[cb] ) {
441 LOGGER_DEBUG("Invoking callback function: %d", cb); 462 LOGGER_DEBUG("Invoking callback function: %d", cb);
442 if ( call->session->callbacks[cb] ( call->session->av, call ) != 0 ) { 463 if ( call->session->callbacks[cb] ( call->session->av, call ) != 0 ) {
443 LOGGER_WARNING("Callback handling failed, sending error"); 464 LOGGER_WARNING("Callback state handling failed, sending error");
444 goto FAILURE; 465 goto FAILURE;
445 } 466 }
446 467
@@ -449,10 +470,11 @@ int invoke_callback(MSICall* call, MSICallbackID cb)
449 470
450FAILURE: 471FAILURE:
451 /* If no callback present or error happened while handling, 472 /* If no callback present or error happened while handling,
452 * an error message will be send to friend 473 * an error message will be sent to friend
453 */ 474 */
454 475
455 call->error = msi_HandleError; 476 if (call->error == msi_ENone)
477 call->error = msi_EHandle;
456 return -1; 478 return -1;
457} 479}
458static MSICall *get_call ( MSISession *session, uint32_t friend_id ) 480static MSICall *get_call ( MSISession *session, uint32_t friend_id )
@@ -517,9 +539,12 @@ MSICall *new_call ( MSISession *session, uint32_t friend_id )
517} 539}
518void kill_call ( MSICall *call ) 540void kill_call ( MSICall *call )
519{ 541{
542 /* Assume that session mutex is locked */
520 if ( call == NULL ) 543 if ( call == NULL )
521 return; 544 return;
522 545
546 LOGGER_DEBUG("Killing call: %p", call);
547
523 MSISession* session = call->session; 548 MSISession* session = call->session;
524 549
525 MSICall* prev = call->prev; 550 MSICall* prev = call->prev;
@@ -529,23 +554,23 @@ void kill_call ( MSICall *call )
529 prev->next = next; 554 prev->next = next;
530 else if (next) 555 else if (next)
531 session->calls_head = next->friend_id; 556 session->calls_head = next->friend_id;
532 else goto CLEAR; 557 else goto CLEAR_CONTAINER;
533 558
534 if (next) 559 if (next)
535 next->prev = prev; 560 next->prev = prev;
536 else if (prev) 561 else if (prev)
537 session->calls_tail = prev->friend_id; 562 session->calls_tail = prev->friend_id;
538 else goto CLEAR; 563 else goto CLEAR_CONTAINER;
539 564
540 session->calls[call->friend_id] = NULL; 565 session->calls[call->friend_id] = NULL;
541 free(call); 566 free(call);
542 return; 567 return;
543 568
544CLEAR: 569CLEAR_CONTAINER:
545 session->calls_head = session->calls_tail = 0; 570 session->calls_head = session->calls_tail = 0;
546 free(session->calls); 571 free(session->calls);
547 session->calls = NULL;
548 free(call); 572 free(call);
573 session->calls = NULL;
549} 574}
550void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data) 575void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data)
551{ 576{
@@ -556,13 +581,17 @@ void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data)
556 case 0: { /* Friend is now offline */ 581 case 0: { /* Friend is now offline */
557 LOGGER_DEBUG("Friend %d is now offline", friend_id); 582 LOGGER_DEBUG("Friend %d is now offline", friend_id);
558 583
584 pthread_mutex_lock(session->mutex);
559 MSICall* call = get_call(session, friend_id); 585 MSICall* call = get_call(session, friend_id);
560 586
561 if (call == NULL) 587 if (call == NULL) {
588 pthread_mutex_unlock(session->mutex);
562 return; 589 return;
590 }
563 591
564 invoke_callback(call, msi_OnPeerTimeout); /* Failure is ignored */ 592 invoke_callback(call, msi_OnPeerTimeout); /* Failure is ignored */
565 kill_call(call); 593 kill_call(call);
594 pthread_mutex_unlock(session->mutex);
566 } 595 }
567 break; 596 break;
568 597
@@ -580,18 +609,17 @@ void handle_push ( MSICall *call, const MSIMessage *msg )
580 609
581 if (!msg->capabilities.exists) { 610 if (!msg->capabilities.exists) {
582 LOGGER_WARNING("Session: %p Invalid capabilities on 'push'"); 611 LOGGER_WARNING("Session: %p Invalid capabilities on 'push'");
583 call->error = msi_InvalidMessage; 612 call->error = msi_EInvalidMessage;
584 goto FAILURE; 613 goto FAILURE;
585 } 614 }
586 615
587 if (call->state != msi_CallActive) { 616 if (call->state != msi_CallActive) {
588 if (!msg->vfpsz.exists) { 617 if (!msg->vfpsz.exists) {
589 LOGGER_WARNING("Session: %p Invalid vfpsz on 'push'"); 618 LOGGER_WARNING("Session: %p Invalid vfpsz on 'push'");
590 call->error = msi_InvalidMessage; 619 call->error = msi_EInvalidMessage;
591 goto FAILURE; 620 goto FAILURE;
592 } 621 }
593 622
594 /* Sending video frame piece size is ignored when call is active */
595 call->peer_vfpsz = ntohs(msg->vfpsz.value); 623 call->peer_vfpsz = ntohs(msg->vfpsz.value);
596 } 624 }
597 625
@@ -610,6 +638,38 @@ void handle_push ( MSICall *call, const MSIMessage *msg )
610 } break; 638 } break;
611 639
612 case msi_CallActive: { 640 case msi_CallActive: {
641 if (msg->vfpsz.exists) {
642 /* If peer sended video frame piece size
643 * while the call is already active it's probable
644 * that he is trying to re-call us while the call
645 * is not terminated on our side. We can assume that
646 * in this case we can automatically answer the re-call.
647 */
648 if (call->peer_vfpsz != ntohs(msg->vfpsz.value)) {
649 LOGGER_WARNING("Friend sent invalid parameters for re-call");
650 call->error = msi_EInvalidParam;
651 invoke_callback(call, msi_OnError);
652 goto FAILURE;
653 }
654
655 LOGGER_INFO("Friend is recalling us");
656
657 MSIMessage msg;
658 msg_init(&msg, requ_push);
659
660 msg.capabilities.exists = true;
661 msg.capabilities.value = call->self_capabilities;
662
663 msg.vfpsz.exists = true;
664 msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE);
665
666 send_message ( call->session->messenger, call->friend_id, &msg );
667
668 /* If peer changed capabilities during re-call they will
669 * be handled accordingly during the next step
670 */
671 }
672
613 /* Only act if capabilities changed */ 673 /* Only act if capabilities changed */
614 if ( call->peer_capabilities != msg->capabilities.value) { 674 if ( call->peer_capabilities != msg->capabilities.value) {
615 LOGGER_INFO("Friend is changing capabilities"); 675 LOGGER_INFO("Friend is changing capabilities");
@@ -629,6 +689,7 @@ void handle_push ( MSICall *call, const MSIMessage *msg )
629 689
630 if ( invoke_callback(call, msi_OnStart) == -1 ) 690 if ( invoke_callback(call, msi_OnStart) == -1 )
631 goto FAILURE; 691 goto FAILURE;
692
632 } break; 693 } break;
633 694
634 case msi_CallRequested: { 695 case msi_CallRequested: {
@@ -646,7 +707,7 @@ FAILURE:
646void handle_pop ( MSICall *call, const MSIMessage *msg ) 707void handle_pop ( MSICall *call, const MSIMessage *msg )
647{ 708{
648 assert(call); 709 assert(call);
649 710
650 LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_id); 711 LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_id);
651 712
652 /* callback errors are ignored */ 713 /* callback errors are ignored */
@@ -682,8 +743,6 @@ void handle_pop ( MSICall *call, const MSIMessage *msg )
682 } 743 }
683 744
684 kill_call ( call ); 745 kill_call ( call );
685
686 return;
687} 746}
688void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object ) 747void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object )
689{ 748{
@@ -694,30 +753,34 @@ void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint1
694 753
695 if ( msg_parse_in ( &msg, data, length ) == -1 ) { 754 if ( msg_parse_in ( &msg, data, length ) == -1 ) {
696 LOGGER_WARNING("Error parsing message"); 755 LOGGER_WARNING("Error parsing message");
697 send_error(m, friend_id, msi_InvalidMessage); 756 send_error(m, friend_id, msi_EInvalidMessage);
698 return; 757 return;
699 } else { 758 } else {
700 LOGGER_DEBUG("Successfully parsed message"); 759 LOGGER_DEBUG("Successfully parsed message");
701 } 760 }
702 761
762 pthread_mutex_lock(session->mutex);
703 MSICall *call = get_call(session, friend_id); 763 MSICall *call = get_call(session, friend_id);
704 764
705 if (call == NULL) { 765 if (call == NULL) {
706 if (msg.request.value != requ_push) { 766 if (msg.request.value != requ_push) {
707 send_error(m, friend_id, msi_StrayMessage); 767 send_error(m, friend_id, msi_EStrayMessage);
768 pthread_mutex_unlock(session->mutex);
708 return; 769 return;
709 } 770 }
710 771
711 call = new_call(session, friend_id); 772 call = new_call(session, friend_id);
712 if (call == NULL) { 773 if (call == NULL) {
713 send_error(m, friend_id, msi_SystemError); 774 send_error(m, friend_id, msi_ESystem);
775 pthread_mutex_unlock(session->mutex);
714 return; 776 return;
715 } 777 }
716 } 778 }
717 779
718 780 if (msg.request.value == requ_push)
719 if (msg.request.value == requ_push)
720 handle_push(call, &msg); 781 handle_push(call, &msg);
721 else 782 else
722 handle_pop(call, &msg); /* always kills the call */ 783 handle_pop(call, &msg); /* always kills the call */
784
785 pthread_mutex_unlock(session->mutex);
723} \ No newline at end of file 786} \ No newline at end of file