summaryrefslogtreecommitdiff
path: root/toxcore/tox.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore/tox.c')
-rw-r--r--toxcore/tox.c338
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)
85typedef struct {
86 Tox *tox;
87 void *user_data;
88} Event_Arg;
89#endif
74 90
75bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch) 91bool 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
345uint32_t tox_fd_count(Tox *tox) 363void 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/** 373void 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 */
355uint32_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; 384static 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
383void tox_callback_loop_begin(Tox *tox, tox_loop_begin_cb *callback) 413static 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
454static void tox_do_iterate(evutil_socket_t fd, short events, void *arg)
455{
456 if (arg == NULL) {
457 return;
458 }
388 459
389void 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 */
508static 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
395uint32_t tox_loop(Tox *tox, void *user_data) 547bool 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
450void tox_loop_stop(Tox *tox) 683void 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
456void tox_self_get_address(const Tox *tox, uint8_t *address) 700void tox_self_get_address(const Tox *tox, uint8_t *address)