diff options
Diffstat (limited to 'toxav/msi.c')
-rw-r--r-- | toxav/msi.c | 111 |
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 | */ |
100 | void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id) | 100 | void 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 | } |
104 | MSISession *msi_new ( Messenger *messenger ) | 106 | MSISession *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 | } |
194 | int msi_hangup ( MSICall* call ) | 201 | int 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 | } |
206 | int msi_answer ( MSICall* call, uint8_t capabilities ) | 217 | int 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 | ||
450 | FAILURE: | 471 | FAILURE: |
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 | } |
458 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ) | 480 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ) |
@@ -517,9 +539,12 @@ MSICall *new_call ( MSISession *session, uint32_t friend_id ) | |||
517 | } | 539 | } |
518 | void kill_call ( MSICall *call ) | 540 | void 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 | ||
544 | CLEAR: | 569 | CLEAR_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 | } |
550 | void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data) | 575 | void 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: | |||
646 | void handle_pop ( MSICall *call, const MSIMessage *msg ) | 707 | void 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 | } |
688 | void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object ) | 747 | void 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 |