diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-02-09 23:29:47 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-02-09 23:30:00 +0100 |
commit | d974bae720beaea9223a8729f4e6c88c326c522b (patch) | |
tree | d8f9a5dedb46fcd6be7731914d86159fb564c2f8 /src/util | |
parent | 4f9169370608dd9c0c125455b651082f5acc7ea6 (diff) | |
download | gnunet-d974bae720beaea9223a8729f4e6c88c326c522b.tar.gz gnunet-d974bae720beaea9223a8729f4e6c88c326c522b.zip |
untested fix for #5511
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/network.c | 3 | ||||
-rw-r--r-- | src/util/service.c | 1078 |
2 files changed, 585 insertions, 496 deletions
diff --git a/src/util/network.c b/src/util/network.c index 3e39374e8..a100be375 100644 --- a/src/util/network.c +++ b/src/util/network.c | |||
@@ -11,7 +11,7 @@ | |||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Affero General Public License for more details. | 13 | Affero General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU Affero General Public License | 15 | You should have received a copy of the GNU Affero General Public License |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 17 | ||
@@ -463,7 +463,6 @@ GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc, | |||
463 | (NULL != address) ? address->sa_family : desc->af, | 463 | (NULL != address) ? address->sa_family : desc->af, |
464 | SOCK_STREAM)) | 464 | SOCK_STREAM)) |
465 | { | 465 | { |
466 | |||
467 | return NULL; | 466 | return NULL; |
468 | } | 467 | } |
469 | return ret; | 468 | return ret; |
diff --git a/src/util/service.c b/src/util/service.c index b481a4786..ee140f88e 100644 --- a/src/util/service.c +++ b/src/util/service.c | |||
@@ -79,6 +79,38 @@ struct ServiceListenContext | |||
79 | 79 | ||
80 | 80 | ||
81 | /** | 81 | /** |
82 | * Reasons why we might be suspended. | ||
83 | */ | ||
84 | enum SuspendReason | ||
85 | { | ||
86 | /** | ||
87 | * We are running normally. | ||
88 | */ | ||
89 | SUSPEND_STATE_NONE = 0, | ||
90 | |||
91 | /** | ||
92 | * Application requested it. | ||
93 | */ | ||
94 | SUSPEND_STATE_APP = 1, | ||
95 | |||
96 | /** | ||
97 | * OS ran out of file descriptors. | ||
98 | */ | ||
99 | SUSPEND_STATE_EMFILE = 2, | ||
100 | |||
101 | /** | ||
102 | * Both reasons, APP and EMFILE apply. | ||
103 | */ | ||
104 | SUSPEND_STATE_APP_AND_EMFILE = 3, | ||
105 | |||
106 | /** | ||
107 | * Suspension because service was permanently shutdown. | ||
108 | */ | ||
109 | SUSPEND_STATE_SHUTDOWN = 4 | ||
110 | }; | ||
111 | |||
112 | |||
113 | /** | ||
82 | * Handle to a service. | 114 | * Handle to a service. |
83 | */ | 115 | */ |
84 | struct GNUNET_SERVICE_Handle | 116 | struct GNUNET_SERVICE_Handle |
@@ -188,6 +220,11 @@ struct GNUNET_SERVICE_Handle | |||
188 | int got_shutdown; | 220 | int got_shutdown; |
189 | 221 | ||
190 | /** | 222 | /** |
223 | * Are we suspended, and if so, why? | ||
224 | */ | ||
225 | enum SuspendReason suspend_state; | ||
226 | |||
227 | /** | ||
191 | * Our options. | 228 | * Our options. |
192 | */ | 229 | */ |
193 | enum GNUNET_SERVICE_Options options; | 230 | enum GNUNET_SERVICE_Options options; |
@@ -329,9 +366,9 @@ struct GNUNET_SERVICE_Client | |||
329 | static int | 366 | static int |
330 | have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh) | 367 | have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh) |
331 | { | 368 | { |
332 | struct GNUNET_SERVICE_Client *client; | 369 | for (struct GNUNET_SERVICE_Client *client = sh->clients_head; |
333 | 370 | NULL != client; | |
334 | for (client = sh->clients_head;NULL != client; client = client->next) | 371 | client = client->next) |
335 | { | 372 | { |
336 | if (client->is_monitor) | 373 | if (client->is_monitor) |
337 | continue; | 374 | continue; |
@@ -375,6 +412,526 @@ service_shutdown (void *cls) | |||
375 | 412 | ||
376 | 413 | ||
377 | /** | 414 | /** |
415 | * Check if the given IP address is in the list of IP addresses. | ||
416 | * | ||
417 | * @param list a list of networks | ||
418 | * @param add the IP to check (in network byte order) | ||
419 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
420 | */ | ||
421 | static int | ||
422 | check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list, | ||
423 | const struct in_addr *add) | ||
424 | { | ||
425 | unsigned int i; | ||
426 | |||
427 | if (NULL == list) | ||
428 | return GNUNET_NO; | ||
429 | i = 0; | ||
430 | while ( (0 != list[i].network.s_addr) || | ||
431 | (0 != list[i].netmask.s_addr) ) | ||
432 | { | ||
433 | if ((add->s_addr & list[i].netmask.s_addr) == | ||
434 | (list[i].network.s_addr & list[i].netmask.s_addr)) | ||
435 | return GNUNET_YES; | ||
436 | i++; | ||
437 | } | ||
438 | return GNUNET_NO; | ||
439 | } | ||
440 | |||
441 | |||
442 | /** | ||
443 | * Check if the given IP address is in the list of IP addresses. | ||
444 | * | ||
445 | * @param list a list of networks | ||
446 | * @param ip the IP to check (in network byte order) | ||
447 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
448 | */ | ||
449 | static int | ||
450 | check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list, | ||
451 | const struct in6_addr *ip) | ||
452 | { | ||
453 | unsigned int i; | ||
454 | unsigned int j; | ||
455 | struct in6_addr zero; | ||
456 | |||
457 | if (NULL == list) | ||
458 | return GNUNET_NO; | ||
459 | memset (&zero, | ||
460 | 0, | ||
461 | sizeof (struct in6_addr)); | ||
462 | i = 0; | ||
463 | NEXT: | ||
464 | while (0 != memcmp (&zero, | ||
465 | &list[i].network, | ||
466 | sizeof (struct in6_addr))) | ||
467 | { | ||
468 | for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++) | ||
469 | if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) != | ||
470 | (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j])) | ||
471 | { | ||
472 | i++; | ||
473 | goto NEXT; | ||
474 | } | ||
475 | return GNUNET_YES; | ||
476 | } | ||
477 | return GNUNET_NO; | ||
478 | } | ||
479 | |||
480 | |||
481 | /** | ||
482 | * Suspend accepting connections from the listen socket temporarily. | ||
483 | * Resume activity using #do_resume. | ||
484 | * | ||
485 | * @param sh service to stop accepting connections. | ||
486 | * @param sr reason for suspending accepting connections | ||
487 | */ | ||
488 | static void | ||
489 | do_suspend (struct GNUNET_SERVICE_Handle *sh, | ||
490 | enum SuspendReason sr) | ||
491 | { | ||
492 | struct ServiceListenContext *slc; | ||
493 | |||
494 | GNUNET_assert (0 == (sh->suspend_state & sr)); | ||
495 | sh->suspend_state |= sr; | ||
496 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) | ||
497 | { | ||
498 | if (NULL != slc->listen_task) | ||
499 | { | ||
500 | GNUNET_SCHEDULER_cancel (slc->listen_task); | ||
501 | slc->listen_task = NULL; | ||
502 | } | ||
503 | } | ||
504 | } | ||
505 | |||
506 | |||
507 | /** | ||
508 | * Task run when we are ready to transmit data to the | ||
509 | * client. | ||
510 | * | ||
511 | * @param cls the `struct GNUNET_SERVICE_Client *` to send to | ||
512 | */ | ||
513 | static void | ||
514 | do_send (void *cls) | ||
515 | { | ||
516 | struct GNUNET_SERVICE_Client *client = cls; | ||
517 | ssize_t ret; | ||
518 | size_t left; | ||
519 | const char *buf; | ||
520 | |||
521 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
522 | "service: sending message with type %u", | ||
523 | ntohs(client->msg->type)); | ||
524 | |||
525 | |||
526 | client->send_task = NULL; | ||
527 | buf = (const char *) client->msg; | ||
528 | left = ntohs (client->msg->size) - client->msg_pos; | ||
529 | ret = GNUNET_NETWORK_socket_send (client->sock, | ||
530 | &buf[client->msg_pos], | ||
531 | left); | ||
532 | GNUNET_assert (ret <= (ssize_t) left); | ||
533 | if (0 == ret) | ||
534 | { | ||
535 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
536 | "no data send"); | ||
537 | GNUNET_MQ_inject_error (client->mq, | ||
538 | GNUNET_MQ_ERROR_WRITE); | ||
539 | return; | ||
540 | } | ||
541 | if (-1 == ret) | ||
542 | { | ||
543 | if ( (EAGAIN == errno) || | ||
544 | (EINTR == errno) ) | ||
545 | { | ||
546 | /* ignore */ | ||
547 | ret = 0; | ||
548 | } | ||
549 | else | ||
550 | { | ||
551 | if (EPIPE != errno) | ||
552 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
553 | "send"); | ||
554 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
555 | "socket send returned with error code %i", | ||
556 | errno); | ||
557 | GNUNET_MQ_inject_error (client->mq, | ||
558 | GNUNET_MQ_ERROR_WRITE); | ||
559 | return; | ||
560 | } | ||
561 | } | ||
562 | if (0 == client->msg_pos) | ||
563 | { | ||
564 | GNUNET_MQ_impl_send_in_flight (client->mq); | ||
565 | } | ||
566 | client->msg_pos += ret; | ||
567 | if (left > (size_t) ret) | ||
568 | { | ||
569 | GNUNET_assert (NULL == client->drop_task); | ||
570 | client->send_task | ||
571 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
572 | client->sock, | ||
573 | &do_send, | ||
574 | client); | ||
575 | return; | ||
576 | } | ||
577 | GNUNET_MQ_impl_send_continue (client->mq); | ||
578 | } | ||
579 | |||
580 | |||
581 | /** | ||
582 | * Signature of functions implementing the sending functionality of a | ||
583 | * message queue. | ||
584 | * | ||
585 | * @param mq the message queue | ||
586 | * @param msg the message to send | ||
587 | * @param impl_state our `struct GNUNET_SERVICE_Client *` | ||
588 | */ | ||
589 | static void | ||
590 | service_mq_send (struct GNUNET_MQ_Handle *mq, | ||
591 | const struct GNUNET_MessageHeader *msg, | ||
592 | void *impl_state) | ||
593 | { | ||
594 | struct GNUNET_SERVICE_Client *client = impl_state; | ||
595 | |||
596 | (void) mq; | ||
597 | if (NULL != client->drop_task) | ||
598 | return; /* we're going down right now, do not try to send */ | ||
599 | GNUNET_assert (NULL == client->send_task); | ||
600 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
601 | "Sending message of type %u and size %u to client\n", | ||
602 | ntohs (msg->type), | ||
603 | ntohs (msg->size)); | ||
604 | client->msg = msg; | ||
605 | client->msg_pos = 0; | ||
606 | client->send_task | ||
607 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
608 | client->sock, | ||
609 | &do_send, | ||
610 | client); | ||
611 | } | ||
612 | |||
613 | |||
614 | /** | ||
615 | * Implementation function that cancels the currently sent message. | ||
616 | * | ||
617 | * @param mq message queue | ||
618 | * @param impl_state state specific to the implementation | ||
619 | */ | ||
620 | static void | ||
621 | service_mq_cancel (struct GNUNET_MQ_Handle *mq, | ||
622 | void *impl_state) | ||
623 | { | ||
624 | struct GNUNET_SERVICE_Client *client = impl_state; | ||
625 | |||
626 | (void) mq; | ||
627 | GNUNET_assert (0 == client->msg_pos); | ||
628 | client->msg = NULL; | ||
629 | GNUNET_SCHEDULER_cancel (client->send_task); | ||
630 | client->send_task = NULL; | ||
631 | } | ||
632 | |||
633 | |||
634 | /** | ||
635 | * Generic error handler, called with the appropriate | ||
636 | * error code and the same closure specified at the creation of | ||
637 | * the message queue. | ||
638 | * Not every message queue implementation supports an error handler. | ||
639 | * | ||
640 | * @param cls closure with our `struct GNUNET_SERVICE_Client` | ||
641 | * @param error error code | ||
642 | */ | ||
643 | static void | ||
644 | service_mq_error_handler (void *cls, | ||
645 | enum GNUNET_MQ_Error error) | ||
646 | { | ||
647 | struct GNUNET_SERVICE_Client *client = cls; | ||
648 | struct GNUNET_SERVICE_Handle *sh = client->sh; | ||
649 | |||
650 | if ( (GNUNET_MQ_ERROR_NO_MATCH == error) && | ||
651 | (GNUNET_NO == sh->require_found) ) | ||
652 | { | ||
653 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
654 | "No handler for message of type %u found\n", | ||
655 | (unsigned int) client->warn_type); | ||
656 | GNUNET_SERVICE_client_continue (client); | ||
657 | return; /* ignore error */ | ||
658 | } | ||
659 | GNUNET_SERVICE_client_drop (client); | ||
660 | } | ||
661 | |||
662 | |||
663 | /** | ||
664 | * Task run to warn about missing calls to #GNUNET_SERVICE_client_continue(). | ||
665 | * | ||
666 | * @param cls our `struct GNUNET_SERVICE_Client *` to process more requests from | ||
667 | */ | ||
668 | static void | ||
669 | warn_no_client_continue (void *cls) | ||
670 | { | ||
671 | struct GNUNET_SERVICE_Client *client = cls; | ||
672 | |||
673 | GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */ | ||
674 | client->warn_task | ||
675 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
676 | &warn_no_client_continue, | ||
677 | client); | ||
678 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
679 | _("Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"), | ||
680 | (unsigned int) client->warn_type, | ||
681 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start), | ||
682 | GNUNET_YES)); | ||
683 | } | ||
684 | |||
685 | |||
686 | /** | ||
687 | * Functions with this signature are called whenever a | ||
688 | * complete message is received by the tokenizer for a client. | ||
689 | * | ||
690 | * Do not call #GNUNET_MST_destroy() from within | ||
691 | * the scope of this callback. | ||
692 | * | ||
693 | * @param cls closure with the `struct GNUNET_SERVICE_Client *` | ||
694 | * @param message the actual message | ||
695 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if the client was dropped | ||
696 | */ | ||
697 | static int | ||
698 | service_client_mst_cb (void *cls, | ||
699 | const struct GNUNET_MessageHeader *message) | ||
700 | { | ||
701 | struct GNUNET_SERVICE_Client *client = cls; | ||
702 | |||
703 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
704 | "Received message of type %u and size %u from client\n", | ||
705 | ntohs (message->type), | ||
706 | ntohs (message->size)); | ||
707 | GNUNET_assert (GNUNET_NO == client->needs_continue); | ||
708 | client->needs_continue = GNUNET_YES; | ||
709 | client->warn_type = ntohs (message->type); | ||
710 | client->warn_start = GNUNET_TIME_absolute_get (); | ||
711 | GNUNET_assert (NULL == client->warn_task); | ||
712 | client->warn_task | ||
713 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
714 | &warn_no_client_continue, | ||
715 | client); | ||
716 | GNUNET_MQ_inject_message (client->mq, | ||
717 | message); | ||
718 | if (NULL != client->drop_task) | ||
719 | return GNUNET_SYSERR; | ||
720 | return GNUNET_OK; | ||
721 | } | ||
722 | |||
723 | |||
724 | /** | ||
725 | * A client sent us data. Receive and process it. If we are done, | ||
726 | * reschedule this task. | ||
727 | * | ||
728 | * @param cls the `struct GNUNET_SERVICE_Client` that sent us data. | ||
729 | */ | ||
730 | static void | ||
731 | service_client_recv (void *cls) | ||
732 | { | ||
733 | struct GNUNET_SERVICE_Client *client = cls; | ||
734 | int ret; | ||
735 | |||
736 | client->recv_task = NULL; | ||
737 | ret = GNUNET_MST_read (client->mst, | ||
738 | client->sock, | ||
739 | GNUNET_NO, | ||
740 | GNUNET_YES); | ||
741 | if (GNUNET_SYSERR == ret) | ||
742 | { | ||
743 | /* client closed connection (or IO error) */ | ||
744 | if (NULL == client->drop_task) | ||
745 | { | ||
746 | GNUNET_assert (GNUNET_NO == client->needs_continue); | ||
747 | GNUNET_SERVICE_client_drop (client); | ||
748 | } | ||
749 | return; | ||
750 | } | ||
751 | if (GNUNET_NO == ret) | ||
752 | return; /* more messages in buffer, wait for application | ||
753 | to be done processing */ | ||
754 | GNUNET_assert (GNUNET_OK == ret); | ||
755 | if (GNUNET_YES == client->needs_continue) | ||
756 | return; | ||
757 | if (NULL != client->recv_task) | ||
758 | return; | ||
759 | /* MST needs more data, re-schedule read job */ | ||
760 | client->recv_task | ||
761 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
762 | client->sock, | ||
763 | &service_client_recv, | ||
764 | client); | ||
765 | } | ||
766 | |||
767 | |||
768 | /** | ||
769 | * We have successfully accepted a connection from a client. Now | ||
770 | * setup the client (with the scheduler) and tell the application. | ||
771 | * | ||
772 | * @param sh service that accepted the client | ||
773 | * @param sock socket associated with the client | ||
774 | */ | ||
775 | static void | ||
776 | start_client (struct GNUNET_SERVICE_Handle *sh, | ||
777 | struct GNUNET_NETWORK_Handle *csock) | ||
778 | { | ||
779 | struct GNUNET_SERVICE_Client *client; | ||
780 | |||
781 | client = GNUNET_new (struct GNUNET_SERVICE_Client); | ||
782 | GNUNET_CONTAINER_DLL_insert (sh->clients_head, | ||
783 | sh->clients_tail, | ||
784 | client); | ||
785 | client->sh = sh; | ||
786 | client->sock = csock; | ||
787 | client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send, | ||
788 | NULL, | ||
789 | &service_mq_cancel, | ||
790 | client, | ||
791 | sh->handlers, | ||
792 | &service_mq_error_handler, | ||
793 | client); | ||
794 | client->mst = GNUNET_MST_create (&service_client_mst_cb, | ||
795 | client); | ||
796 | if (NULL != sh->connect_cb) | ||
797 | client->user_context = sh->connect_cb (sh->cb_cls, | ||
798 | client, | ||
799 | client->mq); | ||
800 | GNUNET_MQ_set_handlers_closure (client->mq, | ||
801 | client->user_context); | ||
802 | client->recv_task | ||
803 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
804 | client->sock, | ||
805 | &service_client_recv, | ||
806 | client); | ||
807 | } | ||
808 | |||
809 | |||
810 | /** | ||
811 | * We have a client. Accept the incoming socket(s) (and reschedule | ||
812 | * the listen task). | ||
813 | * | ||
814 | * @param cls the `struct ServiceListenContext` of the ready listen socket | ||
815 | */ | ||
816 | static void | ||
817 | accept_client (void *cls) | ||
818 | { | ||
819 | struct ServiceListenContext *slc = cls; | ||
820 | struct GNUNET_SERVICE_Handle *sh = slc->sh; | ||
821 | |||
822 | slc->listen_task = NULL; | ||
823 | while (1) | ||
824 | { | ||
825 | struct GNUNET_NETWORK_Handle *sock; | ||
826 | const struct sockaddr_in *v4; | ||
827 | const struct sockaddr_in6 *v6; | ||
828 | struct sockaddr_storage sa; | ||
829 | socklen_t addrlen; | ||
830 | int ok; | ||
831 | |||
832 | addrlen = sizeof (sa); | ||
833 | sock = GNUNET_NETWORK_socket_accept (slc->listen_socket, | ||
834 | (struct sockaddr *) &sa, | ||
835 | &addrlen); | ||
836 | if (NULL == sock) | ||
837 | { | ||
838 | if (EMFILE == errno) | ||
839 | do_suspend (sh, | ||
840 | SUSPEND_STATE_EMFILE); | ||
841 | else | ||
842 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
843 | "accept"); | ||
844 | break; | ||
845 | } | ||
846 | switch (sa.ss_family) | ||
847 | { | ||
848 | case AF_INET: | ||
849 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); | ||
850 | v4 = (const struct sockaddr_in *) &sa; | ||
851 | ok = ( ( (NULL == sh->v4_allowed) || | ||
852 | (check_ipv4_listed (sh->v4_allowed, | ||
853 | &v4->sin_addr))) && | ||
854 | ( (NULL == sh->v4_denied) || | ||
855 | (! check_ipv4_listed (sh->v4_denied, | ||
856 | &v4->sin_addr)) ) ); | ||
857 | break; | ||
858 | case AF_INET6: | ||
859 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); | ||
860 | v6 = (const struct sockaddr_in6 *) &sa; | ||
861 | ok = ( ( (NULL == sh->v6_allowed) || | ||
862 | (check_ipv6_listed (sh->v6_allowed, | ||
863 | &v6->sin6_addr))) && | ||
864 | ( (NULL == sh->v6_denied) || | ||
865 | (! check_ipv6_listed (sh->v6_denied, | ||
866 | &v6->sin6_addr)) ) ); | ||
867 | break; | ||
868 | #ifndef WINDOWS | ||
869 | case AF_UNIX: | ||
870 | ok = GNUNET_OK; /* controlled using file-system ACL now */ | ||
871 | break; | ||
872 | #endif | ||
873 | default: | ||
874 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
875 | _("Unknown address family %d\n"), | ||
876 | sa.ss_family); | ||
877 | return; | ||
878 | } | ||
879 | if (! ok) | ||
880 | { | ||
881 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
882 | "Service rejected incoming connection from %s due to policy.\n", | ||
883 | GNUNET_a2s ((const struct sockaddr *) &sa, | ||
884 | addrlen)); | ||
885 | GNUNET_break (GNUNET_OK == | ||
886 | GNUNET_NETWORK_socket_close (sock)); | ||
887 | continue; | ||
888 | } | ||
889 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
890 | "Service accepted incoming connection from %s.\n", | ||
891 | GNUNET_a2s ((const struct sockaddr *) &sa, | ||
892 | addrlen)); | ||
893 | start_client (slc->sh, | ||
894 | sock); | ||
895 | } | ||
896 | slc->listen_task | ||
897 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
898 | slc->listen_socket, | ||
899 | &accept_client, | ||
900 | slc); | ||
901 | } | ||
902 | |||
903 | |||
904 | /** | ||
905 | * Resume accepting connections from the listen socket. | ||
906 | * | ||
907 | * @param sh service to resume accepting connections. | ||
908 | * @param sr reason that is no longer causing the suspension, | ||
909 | * or #SUSPEND_STATE_NONE on first startup | ||
910 | */ | ||
911 | static void | ||
912 | do_resume (struct GNUNET_SERVICE_Handle *sh, | ||
913 | enum SuspendReason sr) | ||
914 | { | ||
915 | struct ServiceListenContext *slc; | ||
916 | |||
917 | GNUNET_assert ( (SUSPEND_STATE_NONE == sr) || | ||
918 | (0 != (sh->suspend_state & sr)) ); | ||
919 | sh->suspend_state -= sr; | ||
920 | if (SUSPEND_STATE_NONE != sh->suspend_state) | ||
921 | return; | ||
922 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) | ||
923 | { | ||
924 | GNUNET_assert (NULL == slc->listen_task); | ||
925 | slc->listen_task | ||
926 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
927 | slc->listen_socket, | ||
928 | &accept_client, | ||
929 | slc); | ||
930 | } | ||
931 | } | ||
932 | |||
933 | |||
934 | /** | ||
378 | * First task run by any service. Initializes our shutdown task, | 935 | * First task run by any service. Initializes our shutdown task, |
379 | * starts the listening operation on our listen sockets and launches | 936 | * starts the listening operation on our listen sockets and launches |
380 | * the custom logic of the application service. | 937 | * the custom logic of the application service. |
@@ -389,7 +946,8 @@ service_main (void *cls) | |||
389 | if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN != sh->options) | 946 | if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN != sh->options) |
390 | GNUNET_SCHEDULER_add_shutdown (&service_shutdown, | 947 | GNUNET_SCHEDULER_add_shutdown (&service_shutdown, |
391 | sh); | 948 | sh); |
392 | GNUNET_SERVICE_resume (sh); | 949 | do_resume (sh, |
950 | SUSPEND_STATE_NONE); | ||
393 | 951 | ||
394 | if (-1 != sh->ready_confirm_fd) | 952 | if (-1 != sh->ready_confirm_fd) |
395 | { | 953 | { |
@@ -1665,7 +2223,8 @@ GNUNET_SERVICE_start (const char *service_name, | |||
1665 | GNUNET_free (sh); | 2223 | GNUNET_free (sh); |
1666 | return NULL; | 2224 | return NULL; |
1667 | } | 2225 | } |
1668 | GNUNET_SERVICE_resume (sh); | 2226 | do_resume (sh, |
2227 | SUSPEND_STATE_NONE); | ||
1669 | return sh; | 2228 | return sh; |
1670 | } | 2229 | } |
1671 | 2230 | ||
@@ -1820,7 +2379,7 @@ GNUNET_SERVICE_run_ (int argc, | |||
1820 | GNUNET_DISK_file_test (opt_cfg_filename)) || | 2379 | GNUNET_DISK_file_test (opt_cfg_filename)) || |
1821 | (GNUNET_SYSERR == | 2380 | (GNUNET_SYSERR == |
1822 | GNUNET_CONFIGURATION_load (cfg, | 2381 | GNUNET_CONFIGURATION_load (cfg, |
1823 | opt_cfg_filename)) ) | 2382 | opt_cfg_filename)) ) |
1824 | { | 2383 | { |
1825 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 2384 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1826 | _("Malformed configuration file `%s', exit ...\n"), | 2385 | _("Malformed configuration file `%s', exit ...\n"), |
@@ -1836,7 +2395,7 @@ GNUNET_SERVICE_run_ (int argc, | |||
1836 | if (GNUNET_SYSERR == | 2395 | if (GNUNET_SYSERR == |
1837 | GNUNET_CONFIGURATION_load (cfg, | 2396 | GNUNET_CONFIGURATION_load (cfg, |
1838 | cfg_filename)) | 2397 | cfg_filename)) |
1839 | { | 2398 | { |
1840 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 2399 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1841 | _("Malformed configuration file `%s', exit ...\n"), | 2400 | _("Malformed configuration file `%s', exit ...\n"), |
1842 | cfg_filename); | 2401 | cfg_filename); |
@@ -1953,472 +2512,8 @@ shutdown: | |||
1953 | void | 2512 | void |
1954 | GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh) | 2513 | GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh) |
1955 | { | 2514 | { |
1956 | struct ServiceListenContext *slc; | 2515 | do_suspend (sh, |
1957 | 2516 | SUSPEND_STATE_APP); | |
1958 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) | ||
1959 | { | ||
1960 | if (NULL != slc->listen_task) | ||
1961 | { | ||
1962 | GNUNET_SCHEDULER_cancel (slc->listen_task); | ||
1963 | slc->listen_task = NULL; | ||
1964 | } | ||
1965 | } | ||
1966 | } | ||
1967 | |||
1968 | |||
1969 | /** | ||
1970 | * Task run when we are ready to transmit data to the | ||
1971 | * client. | ||
1972 | * | ||
1973 | * @param cls the `struct GNUNET_SERVICE_Client *` to send to | ||
1974 | */ | ||
1975 | static void | ||
1976 | do_send (void *cls) | ||
1977 | { | ||
1978 | struct GNUNET_SERVICE_Client *client = cls; | ||
1979 | ssize_t ret; | ||
1980 | size_t left; | ||
1981 | const char *buf; | ||
1982 | |||
1983 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1984 | "service: sending message with type %u", | ||
1985 | ntohs(client->msg->type)); | ||
1986 | |||
1987 | |||
1988 | client->send_task = NULL; | ||
1989 | buf = (const char *) client->msg; | ||
1990 | left = ntohs (client->msg->size) - client->msg_pos; | ||
1991 | ret = GNUNET_NETWORK_socket_send (client->sock, | ||
1992 | &buf[client->msg_pos], | ||
1993 | left); | ||
1994 | GNUNET_assert (ret <= (ssize_t) left); | ||
1995 | if (0 == ret) | ||
1996 | { | ||
1997 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1998 | "no data send"); | ||
1999 | GNUNET_MQ_inject_error (client->mq, | ||
2000 | GNUNET_MQ_ERROR_WRITE); | ||
2001 | return; | ||
2002 | } | ||
2003 | if (-1 == ret) | ||
2004 | { | ||
2005 | if ( (EAGAIN == errno) || | ||
2006 | (EINTR == errno) ) | ||
2007 | { | ||
2008 | /* ignore */ | ||
2009 | ret = 0; | ||
2010 | } | ||
2011 | else | ||
2012 | { | ||
2013 | if (EPIPE != errno) | ||
2014 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
2015 | "send"); | ||
2016 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2017 | "socket send returned with error code %i", | ||
2018 | errno); | ||
2019 | GNUNET_MQ_inject_error (client->mq, | ||
2020 | GNUNET_MQ_ERROR_WRITE); | ||
2021 | return; | ||
2022 | } | ||
2023 | } | ||
2024 | if (0 == client->msg_pos) | ||
2025 | { | ||
2026 | GNUNET_MQ_impl_send_in_flight (client->mq); | ||
2027 | } | ||
2028 | client->msg_pos += ret; | ||
2029 | if (left > (size_t) ret) | ||
2030 | { | ||
2031 | GNUNET_assert (NULL == client->drop_task); | ||
2032 | client->send_task | ||
2033 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2034 | client->sock, | ||
2035 | &do_send, | ||
2036 | client); | ||
2037 | return; | ||
2038 | } | ||
2039 | GNUNET_MQ_impl_send_continue (client->mq); | ||
2040 | } | ||
2041 | |||
2042 | |||
2043 | /** | ||
2044 | * Signature of functions implementing the sending functionality of a | ||
2045 | * message queue. | ||
2046 | * | ||
2047 | * @param mq the message queue | ||
2048 | * @param msg the message to send | ||
2049 | * @param impl_state our `struct GNUNET_SERVICE_Client *` | ||
2050 | */ | ||
2051 | static void | ||
2052 | service_mq_send (struct GNUNET_MQ_Handle *mq, | ||
2053 | const struct GNUNET_MessageHeader *msg, | ||
2054 | void *impl_state) | ||
2055 | { | ||
2056 | struct GNUNET_SERVICE_Client *client = impl_state; | ||
2057 | |||
2058 | (void) mq; | ||
2059 | if (NULL != client->drop_task) | ||
2060 | return; /* we're going down right now, do not try to send */ | ||
2061 | GNUNET_assert (NULL == client->send_task); | ||
2062 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2063 | "Sending message of type %u and size %u to client\n", | ||
2064 | ntohs (msg->type), | ||
2065 | ntohs (msg->size)); | ||
2066 | client->msg = msg; | ||
2067 | client->msg_pos = 0; | ||
2068 | client->send_task | ||
2069 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2070 | client->sock, | ||
2071 | &do_send, | ||
2072 | client); | ||
2073 | } | ||
2074 | |||
2075 | |||
2076 | /** | ||
2077 | * Implementation function that cancels the currently sent message. | ||
2078 | * | ||
2079 | * @param mq message queue | ||
2080 | * @param impl_state state specific to the implementation | ||
2081 | */ | ||
2082 | static void | ||
2083 | service_mq_cancel (struct GNUNET_MQ_Handle *mq, | ||
2084 | void *impl_state) | ||
2085 | { | ||
2086 | struct GNUNET_SERVICE_Client *client = impl_state; | ||
2087 | |||
2088 | (void) mq; | ||
2089 | GNUNET_assert (0 == client->msg_pos); | ||
2090 | client->msg = NULL; | ||
2091 | GNUNET_SCHEDULER_cancel (client->send_task); | ||
2092 | client->send_task = NULL; | ||
2093 | } | ||
2094 | |||
2095 | |||
2096 | /** | ||
2097 | * Generic error handler, called with the appropriate | ||
2098 | * error code and the same closure specified at the creation of | ||
2099 | * the message queue. | ||
2100 | * Not every message queue implementation supports an error handler. | ||
2101 | * | ||
2102 | * @param cls closure with our `struct GNUNET_SERVICE_Client` | ||
2103 | * @param error error code | ||
2104 | */ | ||
2105 | static void | ||
2106 | service_mq_error_handler (void *cls, | ||
2107 | enum GNUNET_MQ_Error error) | ||
2108 | { | ||
2109 | struct GNUNET_SERVICE_Client *client = cls; | ||
2110 | struct GNUNET_SERVICE_Handle *sh = client->sh; | ||
2111 | |||
2112 | if ( (GNUNET_MQ_ERROR_NO_MATCH == error) && | ||
2113 | (GNUNET_NO == sh->require_found) ) | ||
2114 | { | ||
2115 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2116 | "No handler for message of type %u found\n", | ||
2117 | (unsigned int) client->warn_type); | ||
2118 | GNUNET_SERVICE_client_continue (client); | ||
2119 | return; /* ignore error */ | ||
2120 | } | ||
2121 | GNUNET_SERVICE_client_drop (client); | ||
2122 | } | ||
2123 | |||
2124 | |||
2125 | /** | ||
2126 | * Task run to warn about missing calls to #GNUNET_SERVICE_client_continue(). | ||
2127 | * | ||
2128 | * @param cls our `struct GNUNET_SERVICE_Client *` to process more requests from | ||
2129 | */ | ||
2130 | static void | ||
2131 | warn_no_client_continue (void *cls) | ||
2132 | { | ||
2133 | struct GNUNET_SERVICE_Client *client = cls; | ||
2134 | |||
2135 | GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */ | ||
2136 | client->warn_task | ||
2137 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
2138 | &warn_no_client_continue, | ||
2139 | client); | ||
2140 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2141 | _("Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"), | ||
2142 | (unsigned int) client->warn_type, | ||
2143 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start), | ||
2144 | GNUNET_YES)); | ||
2145 | } | ||
2146 | |||
2147 | |||
2148 | /** | ||
2149 | * Functions with this signature are called whenever a | ||
2150 | * complete message is received by the tokenizer for a client. | ||
2151 | * | ||
2152 | * Do not call #GNUNET_MST_destroy() from within | ||
2153 | * the scope of this callback. | ||
2154 | * | ||
2155 | * @param cls closure with the `struct GNUNET_SERVICE_Client *` | ||
2156 | * @param message the actual message | ||
2157 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if the client was dropped | ||
2158 | */ | ||
2159 | static int | ||
2160 | service_client_mst_cb (void *cls, | ||
2161 | const struct GNUNET_MessageHeader *message) | ||
2162 | { | ||
2163 | struct GNUNET_SERVICE_Client *client = cls; | ||
2164 | |||
2165 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2166 | "Received message of type %u and size %u from client\n", | ||
2167 | ntohs (message->type), | ||
2168 | ntohs (message->size)); | ||
2169 | GNUNET_assert (GNUNET_NO == client->needs_continue); | ||
2170 | client->needs_continue = GNUNET_YES; | ||
2171 | client->warn_type = ntohs (message->type); | ||
2172 | client->warn_start = GNUNET_TIME_absolute_get (); | ||
2173 | GNUNET_assert (NULL == client->warn_task); | ||
2174 | client->warn_task | ||
2175 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
2176 | &warn_no_client_continue, | ||
2177 | client); | ||
2178 | GNUNET_MQ_inject_message (client->mq, | ||
2179 | message); | ||
2180 | if (NULL != client->drop_task) | ||
2181 | return GNUNET_SYSERR; | ||
2182 | return GNUNET_OK; | ||
2183 | } | ||
2184 | |||
2185 | |||
2186 | /** | ||
2187 | * A client sent us data. Receive and process it. If we are done, | ||
2188 | * reschedule this task. | ||
2189 | * | ||
2190 | * @param cls the `struct GNUNET_SERVICE_Client` that sent us data. | ||
2191 | */ | ||
2192 | static void | ||
2193 | service_client_recv (void *cls) | ||
2194 | { | ||
2195 | struct GNUNET_SERVICE_Client *client = cls; | ||
2196 | int ret; | ||
2197 | |||
2198 | client->recv_task = NULL; | ||
2199 | ret = GNUNET_MST_read (client->mst, | ||
2200 | client->sock, | ||
2201 | GNUNET_NO, | ||
2202 | GNUNET_YES); | ||
2203 | if (GNUNET_SYSERR == ret) | ||
2204 | { | ||
2205 | /* client closed connection (or IO error) */ | ||
2206 | if (NULL == client->drop_task) | ||
2207 | { | ||
2208 | GNUNET_assert (GNUNET_NO == client->needs_continue); | ||
2209 | GNUNET_SERVICE_client_drop (client); | ||
2210 | } | ||
2211 | return; | ||
2212 | } | ||
2213 | if (GNUNET_NO == ret) | ||
2214 | return; /* more messages in buffer, wait for application | ||
2215 | to be done processing */ | ||
2216 | GNUNET_assert (GNUNET_OK == ret); | ||
2217 | if (GNUNET_YES == client->needs_continue) | ||
2218 | return; | ||
2219 | if (NULL != client->recv_task) | ||
2220 | return; | ||
2221 | /* MST needs more data, re-schedule read job */ | ||
2222 | client->recv_task | ||
2223 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2224 | client->sock, | ||
2225 | &service_client_recv, | ||
2226 | client); | ||
2227 | } | ||
2228 | |||
2229 | |||
2230 | /** | ||
2231 | * We have successfully accepted a connection from a client. Now | ||
2232 | * setup the client (with the scheduler) and tell the application. | ||
2233 | * | ||
2234 | * @param sh service that accepted the client | ||
2235 | * @param sock socket associated with the client | ||
2236 | */ | ||
2237 | static void | ||
2238 | start_client (struct GNUNET_SERVICE_Handle *sh, | ||
2239 | struct GNUNET_NETWORK_Handle *csock) | ||
2240 | { | ||
2241 | struct GNUNET_SERVICE_Client *client; | ||
2242 | |||
2243 | client = GNUNET_new (struct GNUNET_SERVICE_Client); | ||
2244 | GNUNET_CONTAINER_DLL_insert (sh->clients_head, | ||
2245 | sh->clients_tail, | ||
2246 | client); | ||
2247 | client->sh = sh; | ||
2248 | client->sock = csock; | ||
2249 | client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send, | ||
2250 | NULL, | ||
2251 | &service_mq_cancel, | ||
2252 | client, | ||
2253 | sh->handlers, | ||
2254 | &service_mq_error_handler, | ||
2255 | client); | ||
2256 | client->mst = GNUNET_MST_create (&service_client_mst_cb, | ||
2257 | client); | ||
2258 | if (NULL != sh->connect_cb) | ||
2259 | client->user_context = sh->connect_cb (sh->cb_cls, | ||
2260 | client, | ||
2261 | client->mq); | ||
2262 | GNUNET_MQ_set_handlers_closure (client->mq, | ||
2263 | client->user_context); | ||
2264 | client->recv_task | ||
2265 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2266 | client->sock, | ||
2267 | &service_client_recv, | ||
2268 | client); | ||
2269 | } | ||
2270 | |||
2271 | |||
2272 | /** | ||
2273 | * Check if the given IP address is in the list of IP addresses. | ||
2274 | * | ||
2275 | * @param list a list of networks | ||
2276 | * @param add the IP to check (in network byte order) | ||
2277 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
2278 | */ | ||
2279 | static int | ||
2280 | check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list, | ||
2281 | const struct in_addr *add) | ||
2282 | { | ||
2283 | unsigned int i; | ||
2284 | |||
2285 | if (NULL == list) | ||
2286 | return GNUNET_NO; | ||
2287 | i = 0; | ||
2288 | while ( (0 != list[i].network.s_addr) || | ||
2289 | (0 != list[i].netmask.s_addr) ) | ||
2290 | { | ||
2291 | if ((add->s_addr & list[i].netmask.s_addr) == | ||
2292 | (list[i].network.s_addr & list[i].netmask.s_addr)) | ||
2293 | return GNUNET_YES; | ||
2294 | i++; | ||
2295 | } | ||
2296 | return GNUNET_NO; | ||
2297 | } | ||
2298 | |||
2299 | |||
2300 | /** | ||
2301 | * Check if the given IP address is in the list of IP addresses. | ||
2302 | * | ||
2303 | * @param list a list of networks | ||
2304 | * @param ip the IP to check (in network byte order) | ||
2305 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
2306 | */ | ||
2307 | static int | ||
2308 | check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list, | ||
2309 | const struct in6_addr *ip) | ||
2310 | { | ||
2311 | unsigned int i; | ||
2312 | unsigned int j; | ||
2313 | struct in6_addr zero; | ||
2314 | |||
2315 | if (NULL == list) | ||
2316 | return GNUNET_NO; | ||
2317 | memset (&zero, | ||
2318 | 0, | ||
2319 | sizeof (struct in6_addr)); | ||
2320 | i = 0; | ||
2321 | NEXT: | ||
2322 | while (0 != memcmp (&zero, | ||
2323 | &list[i].network, | ||
2324 | sizeof (struct in6_addr))) | ||
2325 | { | ||
2326 | for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++) | ||
2327 | if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) != | ||
2328 | (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j])) | ||
2329 | { | ||
2330 | i++; | ||
2331 | goto NEXT; | ||
2332 | } | ||
2333 | return GNUNET_YES; | ||
2334 | } | ||
2335 | return GNUNET_NO; | ||
2336 | } | ||
2337 | |||
2338 | |||
2339 | /** | ||
2340 | * We have a client. Accept the incoming socket(s) (and reschedule | ||
2341 | * the listen task). | ||
2342 | * | ||
2343 | * @param cls the `struct ServiceListenContext` of the ready listen socket | ||
2344 | */ | ||
2345 | static void | ||
2346 | accept_client (void *cls) | ||
2347 | { | ||
2348 | struct ServiceListenContext *slc = cls; | ||
2349 | struct GNUNET_SERVICE_Handle *sh = slc->sh; | ||
2350 | |||
2351 | slc->listen_task = NULL; | ||
2352 | while (1) | ||
2353 | { | ||
2354 | struct GNUNET_NETWORK_Handle *sock; | ||
2355 | const struct sockaddr_in *v4; | ||
2356 | const struct sockaddr_in6 *v6; | ||
2357 | struct sockaddr_storage sa; | ||
2358 | socklen_t addrlen; | ||
2359 | int ok; | ||
2360 | |||
2361 | addrlen = sizeof (sa); | ||
2362 | sock = GNUNET_NETWORK_socket_accept (slc->listen_socket, | ||
2363 | (struct sockaddr *) &sa, | ||
2364 | &addrlen); | ||
2365 | if (NULL == sock) | ||
2366 | break; | ||
2367 | switch (sa.ss_family) | ||
2368 | { | ||
2369 | case AF_INET: | ||
2370 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); | ||
2371 | v4 = (const struct sockaddr_in *) &sa; | ||
2372 | ok = ( ( (NULL == sh->v4_allowed) || | ||
2373 | (check_ipv4_listed (sh->v4_allowed, | ||
2374 | &v4->sin_addr))) && | ||
2375 | ( (NULL == sh->v4_denied) || | ||
2376 | (! check_ipv4_listed (sh->v4_denied, | ||
2377 | &v4->sin_addr)) ) ); | ||
2378 | break; | ||
2379 | case AF_INET6: | ||
2380 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); | ||
2381 | v6 = (const struct sockaddr_in6 *) &sa; | ||
2382 | ok = ( ( (NULL == sh->v6_allowed) || | ||
2383 | (check_ipv6_listed (sh->v6_allowed, | ||
2384 | &v6->sin6_addr))) && | ||
2385 | ( (NULL == sh->v6_denied) || | ||
2386 | (! check_ipv6_listed (sh->v6_denied, | ||
2387 | &v6->sin6_addr)) ) ); | ||
2388 | break; | ||
2389 | #ifndef WINDOWS | ||
2390 | case AF_UNIX: | ||
2391 | ok = GNUNET_OK; /* controlled using file-system ACL now */ | ||
2392 | break; | ||
2393 | #endif | ||
2394 | default: | ||
2395 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2396 | _("Unknown address family %d\n"), | ||
2397 | sa.ss_family); | ||
2398 | return; | ||
2399 | } | ||
2400 | if (! ok) | ||
2401 | { | ||
2402 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2403 | "Service rejected incoming connection from %s due to policy.\n", | ||
2404 | GNUNET_a2s ((const struct sockaddr *) &sa, | ||
2405 | addrlen)); | ||
2406 | GNUNET_break (GNUNET_OK == | ||
2407 | GNUNET_NETWORK_socket_close (sock)); | ||
2408 | continue; | ||
2409 | } | ||
2410 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2411 | "Service accepted incoming connection from %s.\n", | ||
2412 | GNUNET_a2s ((const struct sockaddr *) &sa, | ||
2413 | addrlen)); | ||
2414 | start_client (slc->sh, | ||
2415 | sock); | ||
2416 | } | ||
2417 | slc->listen_task | ||
2418 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2419 | slc->listen_socket, | ||
2420 | &accept_client, | ||
2421 | slc); | ||
2422 | } | 2517 | } |
2423 | 2518 | ||
2424 | 2519 | ||
@@ -2430,17 +2525,8 @@ accept_client (void *cls) | |||
2430 | void | 2525 | void |
2431 | GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh) | 2526 | GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh) |
2432 | { | 2527 | { |
2433 | struct ServiceListenContext *slc; | 2528 | do_resume (sh, |
2434 | 2529 | SUSPEND_STATE_APP); | |
2435 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) | ||
2436 | { | ||
2437 | GNUNET_assert (NULL == slc->listen_task); | ||
2438 | slc->listen_task | ||
2439 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2440 | slc->listen_socket, | ||
2441 | &accept_client, | ||
2442 | slc); | ||
2443 | } | ||
2444 | } | 2530 | } |
2445 | 2531 | ||
2446 | 2532 | ||
@@ -2547,6 +2633,9 @@ finish_client_drop (void *cls) | |||
2547 | { | 2633 | { |
2548 | GNUNET_break (GNUNET_OK == | 2634 | GNUNET_break (GNUNET_OK == |
2549 | GNUNET_NETWORK_socket_close (c->sock)); | 2635 | GNUNET_NETWORK_socket_close (c->sock)); |
2636 | if (0 != (SUSPEND_STATE_EMFILE & sh->suspend_state)) | ||
2637 | do_resume (sh, | ||
2638 | SUSPEND_STATE_EMFILE); | ||
2550 | } | 2639 | } |
2551 | else | 2640 | else |
2552 | { | 2641 | { |
@@ -2578,20 +2667,20 @@ GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c) | |||
2578 | "Client dropped: %p (MQ: %p)\n", | 2667 | "Client dropped: %p (MQ: %p)\n", |
2579 | c, | 2668 | c, |
2580 | c->mq); | 2669 | c->mq); |
2581 | |||
2582 | #if EXECINFO | 2670 | #if EXECINFO |
2583 | void *backtrace_array[MAX_TRACE_DEPTH]; | 2671 | { |
2584 | int num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH); | 2672 | void *backtrace_array[MAX_TRACE_DEPTH]; |
2673 | int num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH); | ||
2585 | char **backtrace_strings = | 2674 | char **backtrace_strings = |
2586 | backtrace_symbols (backtrace_array, | 2675 | backtrace_symbols (backtrace_array, |
2587 | t->num_backtrace_strings); | 2676 | t->num_backtrace_strings); |
2588 | for (unsigned int i = 0; i < num_backtrace_strings; i++) | 2677 | for (unsigned int i = 0; i < num_backtrace_strings; i++) |
2589 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 2678 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2590 | "client drop trace %u: %s\n", | 2679 | "client drop trace %u: %s\n", |
2591 | i, | 2680 | i, |
2592 | backtrace_strings[i]); | 2681 | backtrace_strings[i]); |
2682 | } | ||
2593 | #endif | 2683 | #endif |
2594 | |||
2595 | if (NULL != c->drop_task) | 2684 | if (NULL != c->drop_task) |
2596 | { | 2685 | { |
2597 | /* asked to drop twice! */ | 2686 | /* asked to drop twice! */ |
@@ -2635,7 +2724,8 @@ GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh) | |||
2635 | { | 2724 | { |
2636 | struct GNUNET_SERVICE_Client *client; | 2725 | struct GNUNET_SERVICE_Client *client; |
2637 | 2726 | ||
2638 | GNUNET_SERVICE_suspend (sh); | 2727 | do_suspend (sh, |
2728 | SUSPEND_STATE_SHUTDOWN); | ||
2639 | sh->got_shutdown = GNUNET_NO; | 2729 | sh->got_shutdown = GNUNET_NO; |
2640 | while (NULL != (client = sh->clients_head)) | 2730 | while (NULL != (client = sh->clients_head)) |
2641 | GNUNET_SERVICE_client_drop (client); | 2731 | GNUNET_SERVICE_client_drop (client); |