diff options
Diffstat (limited to 'toxcore/tox.c')
-rw-r--r-- | toxcore/tox.c | 338 |
1 files changed, 291 insertions, 47 deletions
diff --git a/toxcore/tox.c b/toxcore/tox.c index 5e2f14d2..0234fbf3 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c | |||
@@ -34,9 +34,19 @@ typedef struct Messenger Tox; | |||
34 | #include "Messenger.h" | 34 | #include "Messenger.h" |
35 | #include "group.h" | 35 | #include "group.h" |
36 | #include "logger.h" | 36 | #include "logger.h" |
37 | #include "net_crypto.h" | ||
37 | 38 | ||
38 | #include "../toxencryptsave/defines.h" | 39 | #include "../toxencryptsave/defines.h" |
39 | 40 | ||
41 | #include <errno.h> | ||
42 | #if !defined(HAVE_LIBEV) && !defined(HAVE_LIBEVENT) | ||
43 | #if defined (WIN32) || defined(_WIN32) || defined(__WIN32__) | ||
44 | #include <winsock2.h> | ||
45 | #else | ||
46 | #include <sys/select.h> | ||
47 | #endif /* WIN32 || _WIN32 || __WIN32__ */ | ||
48 | #endif /* !HAVE_LIBEV && !HAVE_LIBEVENT */ | ||
49 | |||
40 | #define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}} | 50 | #define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}} |
41 | 51 | ||
42 | #if TOX_HASH_LENGTH != CRYPTO_SHA256_SIZE | 52 | #if TOX_HASH_LENGTH != CRYPTO_SHA256_SIZE |
@@ -71,6 +81,12 @@ typedef struct Messenger Tox; | |||
71 | #error TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH | 81 | #error TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH |
72 | #endif | 82 | #endif |
73 | 83 | ||
84 | #if defined(HAVE_LIBEV) || defined(HAVE_LIBEVENT) | ||
85 | typedef struct { | ||
86 | Tox *tox; | ||
87 | void *user_data; | ||
88 | } Event_Arg; | ||
89 | #endif | ||
74 | 90 | ||
75 | bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch) | 91 | bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch) |
76 | { | 92 | { |
@@ -203,6 +219,8 @@ void tox_kill(Tox *tox) | |||
203 | } | 219 | } |
204 | 220 | ||
205 | Messenger *m = tox; | 221 | Messenger *m = tox; |
222 | |||
223 | tox_loop_stop(tox); | ||
206 | kill_groupchats((Group_Chats *)m->conferences_object); | 224 | kill_groupchats((Group_Chats *)m->conferences_object); |
207 | kill_messenger(m); | 225 | kill_messenger(m); |
208 | } | 226 | } |
@@ -342,68 +360,261 @@ void tox_iterate(Tox *tox, void *user_data) | |||
342 | do_groupchats((Group_Chats *)m->conferences_object, user_data); | 360 | do_groupchats((Group_Chats *)m->conferences_object, user_data); |
343 | } | 361 | } |
344 | 362 | ||
345 | uint32_t tox_fd_count(Tox *tox) | 363 | void tox_callback_loop_begin(Tox *tox, tox_loop_begin_cb *callback) |
346 | { | 364 | { |
365 | if (tox == NULL) { | ||
366 | return; | ||
367 | } | ||
368 | |||
347 | Messenger *m = tox; | 369 | Messenger *m = tox; |
348 | return 1 + m->net_crypto->tcp_c->tcp_connections_length; | 370 | m->loop_begin_cb = callback; |
349 | } | 371 | } |
350 | 372 | ||
351 | /** | 373 | void tox_callback_loop_end(Tox *tox, tox_loop_end_cb *callback) |
352 | * Gathers a list of every network FD activity is expected on | ||
353 | * @param sockets an array of size tox_fd_count() | ||
354 | */ | ||
355 | uint32_t tox_fds(Tox *tox, uint32_t *sockets, uint32_t max_sockets) | ||
356 | { | 374 | { |
375 | if (tox == NULL) { | ||
376 | return; | ||
377 | } | ||
378 | |||
357 | Messenger *m = tox; | 379 | Messenger *m = tox; |
358 | int count = 0; | 380 | m->loop_end_cb = callback; |
381 | } | ||
359 | 382 | ||
360 | if (max_sockets >= 1) { | 383 | #ifdef HAVE_LIBEV |
361 | sockets[count] = m->net->sock; | 384 | static void tox_stop_loop_cb(struct ev_loop *dispatcher, ev_async *listener, int events) |
362 | max_sockets--; | 385 | { |
363 | count++; | 386 | if (dispatcher == NULL || listener == NULL) { |
387 | return; | ||
364 | } | 388 | } |
365 | 389 | ||
366 | TCP_Connections *conns = m->net_crypto->tcp_c; | 390 | Event_Arg *tmp = (Event_Arg *) listener->data; |
367 | int x; | 391 | Messenger *m = tmp->tox; |
368 | 392 | ||
369 | for (x = 0; x < conns->tcp_connections_length; x++) { | 393 | if (ev_is_active(&m->net->sock_listener.listener) || ev_is_pending(&m->net->sock_listener.listener)) { |
370 | if (max_sockets == 0) { | 394 | ev_io_stop(dispatcher, &m->net->sock_listener.listener); |
371 | break; | 395 | } |
372 | } | ||
373 | 396 | ||
374 | TCP_con *conn = &conns->tcp_connections[x]; | 397 | uint32_t len = tcp_connections_length(m->net_crypto->tcp_c); |
375 | sockets[count] = conn->connection->sock; | 398 | |
376 | count++; | 399 | for (uint32_t i = 0; i < len; i++) { |
377 | max_sockets--; | 400 | const TCP_con *conn = tcp_connections_connection_at(m->net_crypto->tcp_c, i); |
401 | |||
402 | if (ev_is_active(&conn->connection->sock_listener.listener) | ||
403 | || ev_is_pending(&conn->connection->sock_listener.listener)) { | ||
404 | ev_io_stop(dispatcher, &conn->connection->sock_listener.listener); | ||
405 | } | ||
378 | } | 406 | } |
379 | 407 | ||
380 | return count; | 408 | ev_async_stop(dispatcher, listener); |
409 | |||
410 | ev_break(dispatcher, EVBREAK_ALL); | ||
381 | } | 411 | } |
382 | 412 | ||
383 | void tox_callback_loop_begin(Tox *tox, tox_loop_begin_cb *callback) | 413 | static void tox_do_iterate(struct ev_loop *dispatcher, ev_io *sock_listener, int events) |
384 | { | 414 | { |
385 | Messenger *m = tox; | 415 | if (dispatcher == NULL || sock_listener == NULL) { |
386 | m->loop_begin_cb = callback; | 416 | return; |
417 | } | ||
418 | |||
419 | Event_Arg *tmp = (Event_Arg *) sock_listener->data; | ||
420 | Messenger *m = tmp->tox; | ||
421 | |||
422 | if (m->loop_begin_cb) { | ||
423 | m->loop_begin_cb(m, tmp->user_data); | ||
424 | } | ||
425 | |||
426 | tox_iterate(tmp->tox, tmp->user_data); | ||
427 | |||
428 | if (!ev_is_active(&m->net->sock_listener.listener) && !ev_is_pending(&m->net->sock_listener.listener)) { | ||
429 | m->net->sock_listener.dispatcher = dispatcher; | ||
430 | ev_io_init(&m->net->sock_listener.listener, tox_do_iterate, m->net->sock, EV_READ); | ||
431 | m->net->sock_listener.listener.data = sock_listener->data; | ||
432 | ev_io_start(dispatcher, &m->net->sock_listener.listener); | ||
433 | } | ||
434 | |||
435 | uint32_t len = tcp_connections_length(m->net_crypto->tcp_c); | ||
436 | |||
437 | for (uint32_t i = 0; i < len; i++) { | ||
438 | const TCP_con *conn = tcp_connections_connection_at(m->net_crypto->tcp_c, i); | ||
439 | |||
440 | if (!ev_is_active(&conn->connection->sock_listener.listener) | ||
441 | && !ev_is_pending(&conn->connection->sock_listener.listener)) { | ||
442 | conn->connection->sock_listener.dispatcher = dispatcher; | ||
443 | ev_io_init(&conn->connection->sock_listener.listener, tox_do_iterate, conn->connection->sock, EV_READ); | ||
444 | conn->connection->sock_listener.listener.data = sock_listener->data; | ||
445 | ev_io_start(m->dispatcher, &conn->connection->sock_listener.listener); | ||
446 | } | ||
447 | } | ||
448 | |||
449 | if (m->loop_end_cb) { | ||
450 | m->loop_end_cb(m, tmp->user_data); | ||
451 | } | ||
387 | } | 452 | } |
453 | #elif HAVE_LIBEVENT | ||
454 | static void tox_do_iterate(evutil_socket_t fd, short events, void *arg) | ||
455 | { | ||
456 | if (arg == NULL) { | ||
457 | return; | ||
458 | } | ||
388 | 459 | ||
389 | void tox_callback_loop_end(Tox *tox, tox_loop_end_cb *callback) | 460 | Event_Arg *tmp = (Event_Arg *) arg; |
461 | Messenger *m = tmp->tox; | ||
462 | struct timeval timeout; | ||
463 | |||
464 | if (m->loop_begin_cb) { | ||
465 | m->loop_begin_cb(m, tmp->user_data); | ||
466 | } | ||
467 | |||
468 | tox_iterate(tmp->tox, tmp->user_data); | ||
469 | |||
470 | timeout.tv_sec = 0; | ||
471 | |||
472 | // TODO(cleverca22): use a longer timeout. | ||
473 | timeout.tv_usec = tox_iteration_interval(tmp->tox) * 1000 * 2; | ||
474 | |||
475 | if (!m->net->sock_listener) { | ||
476 | m->net->sock_listener = event_new(m->dispatcher, m->net->sock, EV_READ | EV_PERSIST, tox_do_iterate, arg); | ||
477 | } | ||
478 | |||
479 | event_add(m->net->sock_listener, &timeout); | ||
480 | |||
481 | uint32_t len = tcp_connections_length(m->net_crypto->tcp_c); | ||
482 | |||
483 | for (uint32_t i = 0; i < len; i++) { | ||
484 | const TCP_con *conn = tcp_connections_connection_at(m->net_crypto->tcp_c, i); | ||
485 | |||
486 | if (!conn->connection->sock_listener) { | ||
487 | conn->connection->sock_listener = event_new(m->dispatcher, conn->connection->sock, EV_READ | EV_PERSIST, tox_do_iterate, | ||
488 | arg); | ||
489 | } | ||
490 | |||
491 | event_add(conn->connection->sock_listener, NULL); | ||
492 | } | ||
493 | |||
494 | if (m->loop_end_cb) { | ||
495 | m->loop_end_cb(m, tmp->user_data); | ||
496 | } | ||
497 | } | ||
498 | #else | ||
499 | /** | ||
500 | * Gathers a list of every network file descriptor, | ||
501 | * where an activity is expected on. | ||
502 | * | ||
503 | * @param sockets a pointer to an array (the pointed array can be NULL). | ||
504 | * @param sockets_num the number of current known sockets (will be updated by the funciton). | ||
505 | * | ||
506 | * @return false if errors occurred, true otherwise. | ||
507 | */ | ||
508 | static bool tox_fds(Messenger *m, Socket **sockets, uint32_t *sockets_num) | ||
390 | { | 509 | { |
391 | Messenger *m = tox; | 510 | if (m == NULL || sockets == NULL || sockets_num == NULL) { |
392 | m->loop_end_cb = callback; | 511 | return false; |
512 | } | ||
513 | |||
514 | uint32_t len = tcp_connections_length(m->net_crypto->tcp_c); | ||
515 | uint32_t fdcount = 1 + len; | ||
516 | |||
517 | if (fdcount != *sockets_num || *sockets == NULL) { | ||
518 | Socket *tmp_sockets = (Socket *) realloc(*sockets, fdcount * sizeof(Socket)); | ||
519 | |||
520 | if (tmp_sockets == NULL) { | ||
521 | return false; | ||
522 | } | ||
523 | |||
524 | *sockets = tmp_sockets; | ||
525 | *sockets_num = fdcount; | ||
526 | } | ||
527 | |||
528 | (*sockets)[0] = m->net->sock; | ||
529 | |||
530 | uint32_t i = 0; | ||
531 | |||
532 | while (i < fdcount - 1 && i < len) { | ||
533 | const TCP_con *conn = tcp_connections_connection_at(m->net_crypto->tcp_c, i); | ||
534 | i++; | ||
535 | |||
536 | if (conn != NULL) { | ||
537 | (*sockets)[i] = conn->connection->sock; | ||
538 | } else { | ||
539 | (*sockets)[i] = 0; | ||
540 | } | ||
541 | } | ||
542 | |||
543 | return true; | ||
393 | } | 544 | } |
545 | #endif | ||
394 | 546 | ||
395 | uint32_t tox_loop(Tox *tox, void *user_data) | 547 | bool tox_loop(Tox *tox, void *user_data, TOX_ERR_LOOP *error) |
396 | { | 548 | { |
397 | struct timeval timeout; | 549 | if (tox == NULL) { |
398 | int maxfd; | 550 | SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_NULL); |
399 | uint32_t i, list_size = 0; | 551 | |
400 | uint32_t *fdlist = NULL; | 552 | return false; |
553 | } | ||
554 | |||
401 | Messenger *m = tox; | 555 | Messenger *m = tox; |
402 | m->loop_run = true; | ||
403 | fd_set readable; | ||
404 | 556 | ||
557 | #ifdef HAVE_LIBEV | ||
558 | bool ret = true; | ||
559 | Event_Arg *tmp = (Event_Arg *) calloc(1, sizeof(Event_Arg)); | ||
560 | |||
561 | tmp->tox = tox; | ||
562 | tmp->user_data = user_data; | ||
563 | |||
564 | ev_async_init(&m->stop_loop, tox_stop_loop_cb); | ||
565 | m->stop_loop.data = tmp; | ||
566 | ev_async_start(m->dispatcher, &m->stop_loop); | ||
567 | |||
568 | ev_io stub_listener; | ||
569 | ev_init(&stub_listener, tox_do_iterate); | ||
570 | stub_listener.data = tmp; | ||
571 | tox_do_iterate(m->dispatcher, &stub_listener, 0); | ||
572 | |||
573 | // TODO(Ansa89): travis states that "ev_run" returns "void", | ||
574 | // but "man 3 ev" states it returns "bool" | ||
575 | #if 0 | ||
576 | ret = !ev_run(m->dispatcher, 0); | ||
577 | |||
578 | if (ret) { | ||
579 | SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_OK); | ||
580 | } else { | ||
581 | SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_BREAK); | ||
582 | } | ||
583 | |||
584 | #endif | ||
585 | |||
586 | ev_run(m->dispatcher, 0); | ||
587 | |||
588 | SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_OK); | ||
589 | |||
590 | free(tmp); | ||
591 | #elif HAVE_LIBEVENT | ||
592 | Event_Arg *tmp = (Event_Arg *) calloc(1, sizeof(Event_Arg)); | ||
593 | |||
594 | tmp->tox = tox; | ||
595 | tmp->user_data = user_data; | ||
596 | |||
597 | tox_do_iterate(0, 0, tmp); | ||
598 | bool ret = event_base_dispatch(m->dispatcher) < 0 ? false : true; | ||
599 | |||
600 | if (ret) { | ||
601 | SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_OK); | ||
602 | } else { | ||
603 | SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_BREAK); | ||
604 | } | ||
605 | |||
606 | free(tmp); | ||
607 | #else | ||
608 | bool ret = true; | ||
609 | uint32_t fdcount = 0; | ||
610 | Socket *fdlist = NULL; | ||
611 | |||
612 | m->loop_run = true; | ||
405 | 613 | ||
406 | while (m->loop_run) { | 614 | while (m->loop_run) { |
615 | Socket maxfd; | ||
616 | fd_set readable; | ||
617 | |||
407 | if (m->loop_begin_cb) { | 618 | if (m->loop_begin_cb) { |
408 | m->loop_begin_cb(tox, user_data); | 619 | m->loop_begin_cb(tox, user_data); |
409 | } | 620 | } |
@@ -413,16 +624,27 @@ uint32_t tox_loop(Tox *tox, void *user_data) | |||
413 | maxfd = 0; | 624 | maxfd = 0; |
414 | FD_ZERO(&readable); | 625 | FD_ZERO(&readable); |
415 | 626 | ||
416 | uint32_t fdcount = tox_fd_count(tox); | 627 | // TODO(cleverca22): is it a good idea to reuse previous fdlist when |
628 | // fdcount!=0 && tox_fds()==false? | ||
629 | if (fdcount == 0 && !tox_fds(m, &fdlist, &fdcount)) { | ||
630 | // We must stop because maxfd won't be set. | ||
631 | // TODO(cleverca22): should we call loop_end_cb() on error? | ||
632 | if (m->loop_end_cb) { | ||
633 | m->loop_end_cb(tox, user_data); | ||
634 | } | ||
635 | |||
636 | SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_GET_FDS); | ||
637 | |||
638 | free(fdlist); | ||
417 | 639 | ||
418 | if (fdcount > list_size) { | 640 | return false; |
419 | fdlist = realloc(fdlist, fdcount * sizeof(uint32_t)); | ||
420 | list_size = fdcount; | ||
421 | } | 641 | } |
422 | 642 | ||
423 | fdcount = tox_fds(tox, fdlist, list_size); | 643 | for (uint32_t i = 0; i < fdcount; i++) { |
644 | if (fdlist[i] == 0) { | ||
645 | continue; | ||
646 | } | ||
424 | 647 | ||
425 | for (i = 0; i < fdcount; i++) { | ||
426 | FD_SET(fdlist[i], &readable); | 648 | FD_SET(fdlist[i], &readable); |
427 | 649 | ||
428 | if (fdlist[i] > maxfd) { | 650 | if (fdlist[i] > maxfd) { |
@@ -430,27 +652,49 @@ uint32_t tox_loop(Tox *tox, void *user_data) | |||
430 | } | 652 | } |
431 | } | 653 | } |
432 | 654 | ||
655 | struct timeval timeout; | ||
656 | |||
433 | timeout.tv_sec = 0; | 657 | timeout.tv_sec = 0; |
434 | timeout.tv_usec = tox_iteration_interval(tox) * 1000 * 2; // TODO, use a longer timeout (cleverca22) | 658 | |
659 | // TODO(cleverca22): use a longer timeout. | ||
660 | timeout.tv_usec = tox_iteration_interval(tox) * 1000 * 2; | ||
435 | 661 | ||
436 | if (m->loop_end_cb) { | 662 | if (m->loop_end_cb) { |
437 | m->loop_end_cb(tox, user_data); | 663 | m->loop_end_cb(tox, user_data); |
438 | } | 664 | } |
439 | 665 | ||
440 | int ret = select(maxfd, &readable, NULL, NULL, &timeout); | 666 | if (select(maxfd, &readable, NULL, NULL, &timeout) < 0 && errno != EBADF) { |
667 | SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_SELECT); | ||
668 | |||
669 | free(fdlist); | ||
441 | 670 | ||
442 | if (ret < 0) { | 671 | return false; |
443 | return ret; | ||
444 | } | 672 | } |
445 | } | 673 | } |
446 | 674 | ||
447 | return 0; | 675 | SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_OK); |
676 | |||
677 | free(fdlist); | ||
678 | #endif | ||
679 | |||
680 | return ret; | ||
448 | } | 681 | } |
449 | 682 | ||
450 | void tox_loop_stop(Tox *tox) | 683 | void tox_loop_stop(Tox *tox) |
451 | { | 684 | { |
685 | if (tox == NULL) { | ||
686 | return; | ||
687 | } | ||
688 | |||
452 | Messenger *m = tox; | 689 | Messenger *m = tox; |
690 | |||
691 | #ifdef HAVE_LIBEV | ||
692 | ev_async_send(m->dispatcher, &m->stop_loop); | ||
693 | #elif HAVE_LIBEVENT | ||
694 | event_base_loopbreak(m->dispatcher); | ||
695 | #else | ||
453 | m->loop_run = false; | 696 | m->loop_run = false; |
697 | #endif | ||
454 | } | 698 | } |
455 | 699 | ||
456 | void tox_self_get_address(const Tox *tox, uint8_t *address) | 700 | void tox_self_get_address(const Tox *tox, uint8_t *address) |