diff options
Diffstat (limited to 'src/arm/gnunet-service-arm_interceptor.c')
-rw-r--r-- | src/arm/gnunet-service-arm_interceptor.c | 451 |
1 files changed, 237 insertions, 214 deletions
diff --git a/src/arm/gnunet-service-arm_interceptor.c b/src/arm/gnunet-service-arm_interceptor.c index 2dd4f3703..acdfe0a55 100644 --- a/src/arm/gnunet-service-arm_interceptor.c +++ b/src/arm/gnunet-service-arm_interceptor.c | |||
@@ -188,11 +188,14 @@ struct ForwardedConnection | |||
188 | */ | 188 | */ |
189 | int first_write_done; | 189 | int first_write_done; |
190 | 190 | ||
191 | |||
192 | /** | 191 | /** |
193 | * Service connection attempts | 192 | * Service connection attempts for IPv4 |
194 | */ | 193 | */ |
195 | struct ServiceListeningInfo *service_connect_ipv4; | 194 | struct ServiceListeningInfo *service_connect_ipv4; |
195 | |||
196 | /** | ||
197 | * Service connection attempts for IPv6 | ||
198 | */ | ||
196 | struct ServiceListeningInfo *service_connect_ipv6; | 199 | struct ServiceListeningInfo *service_connect_ipv6; |
197 | }; | 200 | }; |
198 | 201 | ||
@@ -348,14 +351,20 @@ closeClientAndServiceSockets (struct ForwardedConnection *fc, | |||
348 | 351 | ||
349 | 352 | ||
350 | /** | 353 | /** |
351 | * | 354 | * Read data from the client and then forward it to the service. |
355 | * | ||
356 | * @param cls callback data, struct ForwardedConnection for the communication between client and service | ||
357 | * @param tc context | ||
352 | */ | 358 | */ |
353 | static void | 359 | static void |
354 | receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | 360 | receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); |
355 | 361 | ||
356 | 362 | ||
357 | /** | 363 | /** |
358 | * | 364 | * Receive service messages sent by the service and forward it to client |
365 | * | ||
366 | * @param cls callback data, struct ForwardedConnection for the communication between client and service | ||
367 | * @param tc scheduler context | ||
359 | */ | 368 | */ |
360 | static void | 369 | static void |
361 | receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | 370 | receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); |
@@ -700,265 +709,279 @@ receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
700 | &forwardToService, fc); | 709 | &forwardToService, fc); |
701 | } | 710 | } |
702 | 711 | ||
703 | static void fc_acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc, int is_ipv4, int is_ipv6); | ||
704 | static void fc_acceptConnection_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
705 | static void fc_acceptConnection_ipv6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
706 | static int service_try_to_connect (struct sockaddr *addr, socklen_t addrlen, struct ForwardedConnection *fc); | ||
707 | 712 | ||
708 | /** | ||
709 | * | ||
710 | */ | ||
711 | static void | 713 | static void |
712 | start_forwarding (void *cls, | 714 | fc_acceptConnection_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); |
713 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
714 | { | ||
715 | struct ForwardedConnection *fc = cls; | ||
716 | struct GNUNET_TIME_Relative rem; | ||
717 | int fail = 0; | ||
718 | int failures = 0; | ||
719 | int is_zero = 0, is_ipv6 = 0, is_ipv4 = 0; | ||
720 | struct sockaddr_in *target_ipv4; | ||
721 | struct sockaddr_in6 *target_ipv6; | ||
722 | |||
723 | int free_ipv4 = 1, free_ipv6 = 1; | ||
724 | char listen_address[128]; | ||
725 | uint16_t listening_port; | ||
726 | |||
727 | fc->start_task = GNUNET_SCHEDULER_NO_TASK; | ||
728 | if ( (NULL != tc) && | ||
729 | (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) ) | ||
730 | { | ||
731 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
732 | _("Unable to forward to service `%s': shutdown\n"), | ||
733 | fc->listen_info->serviceName); | ||
734 | closeClientAndServiceSockets (fc, REASON_ERROR); | ||
735 | return; | ||
736 | } | ||
737 | rem = GNUNET_TIME_absolute_get_remaining (fc->timeout); | ||
738 | if (rem.rel_value == 0) | ||
739 | { | ||
740 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
741 | _("Unable to forward to service `%s': timeout before connect\n"), | ||
742 | fc->listen_info->serviceName); | ||
743 | closeClientAndServiceSockets (fc, REASON_ERROR); | ||
744 | return; | ||
745 | } | ||
746 | target_ipv4 = GNUNET_malloc (sizeof (struct sockaddr_in)); | ||
747 | target_ipv6 = GNUNET_malloc (sizeof (struct sockaddr_in6)); | ||
748 | |||
749 | switch (fc->listen_info->service_addr->sa_family) | ||
750 | { | ||
751 | case AF_INET: | ||
752 | inet_ntop (fc->listen_info->service_addr->sa_family, (const void *) &((struct sockaddr_in *) fc->listen_info->service_addr)->sin_addr, listen_address, INET_ADDRSTRLEN); | ||
753 | if (strncmp (listen_address, "0.0.0.0:", 8) == 0 || strncmp (listen_address, "0.0.0.0", 7) == 0) | ||
754 | is_zero = 1; | ||
755 | is_ipv4 = 1; | ||
756 | listening_port = ((struct sockaddr_in *)fc->listen_info->service_addr)->sin_port; | ||
757 | break; | ||
758 | case AF_INET6: | ||
759 | inet_ntop (fc->listen_info->service_addr->sa_family, (const void *) &((struct sockaddr_in6 *) fc->listen_info->service_addr)->sin6_addr, listen_address, INET6_ADDRSTRLEN); | ||
760 | if (strncmp (listen_address, "[::]:", 5) == 0 || strncmp (listen_address, "::", 2) == 0) | ||
761 | is_zero = 1; | ||
762 | is_ipv6 = 1; | ||
763 | listening_port = ((struct sockaddr_in6 *)fc->listen_info->service_addr)->sin6_port; | ||
764 | break; | ||
765 | default: | ||
766 | break; | ||
767 | } | ||
768 | |||
769 | fc->service_connect_ipv4 = NULL; | ||
770 | fc->service_connect_ipv6 = NULL; | ||
771 | if (is_zero) | ||
772 | { | ||
773 | /* connect to [::1] and 127.0.0.1 instead of [::] and 0.0.0.0 */ | ||
774 | inet_pton (AF_INET, "127.0.0.1", &target_ipv4->sin_addr); | ||
775 | target_ipv4->sin_family = AF_INET; | ||
776 | target_ipv4->sin_port = listening_port; | ||
777 | is_ipv4 = 1; | ||
778 | free_ipv4 = 0; | ||
779 | |||
780 | inet_pton (AF_INET6, "0:0:0:0:0:0:0:1", &target_ipv6->sin6_addr); | ||
781 | target_ipv6->sin6_family = AF_INET6; | ||
782 | target_ipv6->sin6_port = listening_port; | ||
783 | is_ipv6 = 1; | ||
784 | free_ipv6 = 0; | ||
785 | } | ||
786 | else | ||
787 | { | ||
788 | if (is_ipv4) | ||
789 | memcpy (target_ipv4, fc->listen_info->service_addr, sizeof (struct sockaddr_in)); | ||
790 | else if (is_ipv6) | ||
791 | memcpy (target_ipv6, fc->listen_info->service_addr, sizeof (struct sockaddr_in6)); | ||
792 | } | ||
793 | |||
794 | if (is_ipv4) | ||
795 | failures += free_ipv4 = service_try_to_connect ((struct sockaddr *) target_ipv4, sizeof (struct sockaddr_in), fc); | ||
796 | if (is_ipv6) | ||
797 | failures += free_ipv6 = service_try_to_connect ((struct sockaddr *) target_ipv6, sizeof (struct sockaddr_in6), fc); | ||
798 | |||
799 | if (is_ipv4 + is_ipv6 <= failures) | ||
800 | fail = 1; | ||
801 | |||
802 | if (free_ipv4) | ||
803 | GNUNET_free (target_ipv4); | ||
804 | if (free_ipv6) | ||
805 | GNUNET_free (target_ipv6); | ||
806 | |||
807 | if (fail) | ||
808 | { | ||
809 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
810 | _ ("Unable to start service `%s': %s\n"), | ||
811 | fc->listen_info->serviceName, | ||
812 | STRERROR (errno)); | ||
813 | closeClientAndServiceSockets (fc, REASON_ERROR); | ||
814 | return; | ||
815 | } | ||
816 | } | ||
817 | 715 | ||
818 | static void | 716 | static void |
819 | fc_acceptConnection_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 717 | fc_acceptConnection_ipv6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); |
820 | { | ||
821 | fc_acceptConnection (cls, tc, 1, 0); | ||
822 | } | ||
823 | 718 | ||
824 | static void | ||
825 | fc_acceptConnection_ipv6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
826 | { | ||
827 | fc_acceptConnection (cls, tc, 0, 1); | ||
828 | } | ||
829 | 719 | ||
830 | static void | 720 | static void |
831 | fc_acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc, int is_ipv4, int is_ipv6) | 721 | fc_acceptConnection (void *cls, |
722 | const struct GNUNET_SCHEDULER_TaskContext *tc, | ||
723 | int is_ipv4) | ||
832 | { | 724 | { |
833 | struct ForwardedConnection *fc = cls; | 725 | struct ForwardedConnection *fc = cls; |
834 | struct ServiceListeningInfo *sli; | 726 | struct ServiceListeningInfo *sli; |
835 | 727 | ||
836 | if (is_ipv4) | 728 | if (is_ipv4) |
837 | sli = fc->service_connect_ipv4; | 729 | sli = fc->service_connect_ipv4; |
838 | else if (is_ipv6) | 730 | else |
839 | sli = fc->service_connect_ipv6; | 731 | sli = fc->service_connect_ipv6; |
840 | else | 732 | |
841 | GNUNET_break (0); | 733 | if ( (tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | GNUNET_SCHEDULER_REASON_PREREQ_DONE)) || |
842 | 734 | ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) && fc->armServiceSocket) ) | |
843 | if ((tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | GNUNET_SCHEDULER_REASON_PREREQ_DONE)) || ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) && fc->armServiceSocket)) | ||
844 | { | ||
845 | GNUNET_NETWORK_socket_close (sli->listeningSocket); | ||
846 | if (is_ipv4) | ||
847 | fc->service_connect_ipv4 = NULL; | ||
848 | else if (is_ipv6) | ||
849 | fc->service_connect_ipv6 = NULL; | ||
850 | } | ||
851 | else if (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) | ||
852 | { | ||
853 | #if DEBUG_SERVICE_MANAGER | ||
854 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
855 | "Connected to service, now starting forwarding\n"); | ||
856 | #endif | ||
857 | fc->armServiceSocket = sli->listeningSocket; | ||
858 | if ((is_ipv4 && fc->service_connect_ipv6 != NULL)) | ||
859 | { | ||
860 | GNUNET_SCHEDULER_cancel (fc->service_connect_ipv6->acceptTask); | ||
861 | fc->service_connect_ipv6->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv6, fc); | ||
862 | } | ||
863 | else if (is_ipv6 && fc->service_connect_ipv4 != NULL) | ||
864 | { | ||
865 | GNUNET_SCHEDULER_cancel (fc->service_connect_ipv4->acceptTask); | ||
866 | fc->service_connect_ipv4->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv4, fc); | ||
867 | } | ||
868 | GNUNET_free (fc->listen_info->service_addr); | ||
869 | fc->listen_info->service_addr = sli->service_addr; | ||
870 | fc->listen_info->service_addr_len = sli->service_addr_len; | ||
871 | /*fc->listen_info->listeningSocket is it closed already?*/ | ||
872 | if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK) | ||
873 | { | 735 | { |
874 | if (fc->client_to_service_bufferDataLength == 0) | 736 | GNUNET_NETWORK_socket_close (sli->listeningSocket); |
875 | fc->client_to_service_task = | 737 | if (is_ipv4) |
876 | GNUNET_SCHEDULER_add_read_net ( | 738 | fc->service_connect_ipv4 = NULL; |
877 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
878 | fc->armClientSocket, | ||
879 | &receiveFromClient, fc); | ||
880 | else | 739 | else |
881 | fc->client_to_service_task = | 740 | fc->service_connect_ipv6 = NULL; |
882 | GNUNET_SCHEDULER_add_write_net ( | ||
883 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
884 | fc->armServiceSocket, | ||
885 | &forwardToService, fc); | ||
886 | } | 741 | } |
887 | if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK) | 742 | else if (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) |
888 | { | 743 | { |
889 | if (fc->service_to_client_bufferDataLength == 0) | 744 | #if DEBUG_SERVICE_MANAGER |
890 | fc->service_to_client_task = | 745 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
891 | GNUNET_SCHEDULER_add_read_net ( | 746 | "Connected to service, now starting forwarding\n"); |
892 | GNUNET_TIME_UNIT_FOREVER_REL, | 747 | #endif |
893 | fc->armServiceSocket, | 748 | fc->armServiceSocket = sli->listeningSocket; |
894 | &receiveFromService, fc); | 749 | if ( (GNUNET_YES == is_ipv4) && (fc->service_connect_ipv6 != NULL) ) |
895 | else | 750 | { |
896 | fc->service_to_client_task = | 751 | GNUNET_SCHEDULER_cancel (fc->service_connect_ipv6->acceptTask); |
897 | GNUNET_SCHEDULER_add_write_net ( | 752 | fc->service_connect_ipv6->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv6, fc); |
898 | GNUNET_TIME_UNIT_FOREVER_REL, | 753 | } |
899 | fc->armClientSocket, | 754 | else if ( (GNUNET_NO == is_ipv4) && (fc->service_connect_ipv4 != NULL) ) |
900 | &forwardToClient, fc); | 755 | { |
756 | GNUNET_SCHEDULER_cancel (fc->service_connect_ipv4->acceptTask); | ||
757 | fc->service_connect_ipv4->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv4, fc); | ||
758 | } | ||
759 | GNUNET_free (fc->listen_info->service_addr); | ||
760 | fc->listen_info->service_addr = sli->service_addr; | ||
761 | fc->listen_info->service_addr_len = sli->service_addr_len; | ||
762 | /* fc->listen_info->listeningSocket is it closed already ?*/ | ||
763 | if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK) | ||
764 | { | ||
765 | if (fc->client_to_service_bufferDataLength == 0) | ||
766 | fc->client_to_service_task = | ||
767 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
768 | fc->armClientSocket, | ||
769 | &receiveFromClient, fc); | ||
770 | else | ||
771 | fc->client_to_service_task = | ||
772 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
773 | fc->armServiceSocket, | ||
774 | &forwardToService, fc); | ||
775 | } | ||
776 | if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK) | ||
777 | { | ||
778 | if (fc->service_to_client_bufferDataLength == 0) | ||
779 | fc->service_to_client_task = | ||
780 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
781 | fc->armServiceSocket, | ||
782 | &receiveFromService, fc); | ||
783 | else | ||
784 | fc->service_to_client_task = | ||
785 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
786 | fc->armClientSocket, | ||
787 | &forwardToClient, fc); | ||
788 | } | ||
901 | } | 789 | } |
902 | } | ||
903 | else | 790 | else |
904 | { | 791 | { |
905 | GNUNET_break (0); | 792 | GNUNET_break (0); |
906 | } | 793 | } |
907 | GNUNET_free (sli); | 794 | GNUNET_free (sli); |
908 | } | 795 | } |
909 | 796 | ||
797 | |||
798 | static void | ||
799 | fc_acceptConnection_ipv4 (void *cls, | ||
800 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
801 | { | ||
802 | fc_acceptConnection (cls, tc, GNUNET_YES); | ||
803 | } | ||
804 | |||
805 | |||
806 | static void | ||
807 | fc_acceptConnection_ipv6 (void *cls, | ||
808 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
809 | { | ||
810 | fc_acceptConnection (cls, tc, GNUNET_NO); | ||
811 | } | ||
812 | |||
813 | |||
910 | static int | 814 | static int |
911 | service_try_to_connect (struct sockaddr *addr, socklen_t addrlen, struct ForwardedConnection *fc) | 815 | service_try_to_connect (const struct sockaddr *addr, |
816 | socklen_t addrlen, | ||
817 | struct ForwardedConnection *fc) | ||
912 | { | 818 | { |
913 | struct GNUNET_NETWORK_Handle *sock; | 819 | struct GNUNET_NETWORK_Handle *sock; |
914 | struct ServiceListeningInfo *serviceListeningInfo; | 820 | struct ServiceListeningInfo *serviceListeningInfo; |
915 | 821 | ||
916 | sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); | 822 | sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); |
917 | if (sock == NULL) | 823 | if (sock == NULL) |
918 | { | 824 | { |
919 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to create a socket\n"); | 825 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to create a socket\n"); |
920 | return 1; | 826 | return 1; |
921 | } | 827 | } |
922 | 828 | ||
923 | if ( (GNUNET_SYSERR == GNUNET_NETWORK_socket_connect (sock, addr, addrlen)) && | 829 | if ( (GNUNET_SYSERR == GNUNET_NETWORK_socket_connect (sock, addr, addrlen)) && |
924 | (errno != EINPROGRESS) ) | 830 | (errno != EINPROGRESS) ) |
925 | { | 831 | { |
926 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect\n"); | 832 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect\n"); |
927 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); | 833 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); |
928 | return 1; | 834 | return 1; |
929 | } | 835 | } |
930 | 836 | ||
931 | serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo)); | 837 | serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo)); |
932 | serviceListeningInfo->serviceName = NULL; | 838 | serviceListeningInfo->serviceName = NULL; |
933 | serviceListeningInfo->service_addr = addr; | 839 | serviceListeningInfo->service_addr = GNUNET_malloc (addrlen); |
840 | memcpy (serviceListeningInfo->service_addr, | ||
841 | addr, | ||
842 | addrlen); | ||
934 | serviceListeningInfo->service_addr_len = addrlen; | 843 | serviceListeningInfo->service_addr_len = addrlen; |
935 | serviceListeningInfo->listeningSocket = sock; | 844 | serviceListeningInfo->listeningSocket = sock; |
936 | 845 | ||
937 | switch (addrlen) | 846 | switch (addrlen) |
938 | { | 847 | { |
939 | case sizeof (struct sockaddr_in): | 848 | case sizeof (struct sockaddr_in): |
940 | fc->service_connect_ipv4 = serviceListeningInfo; | 849 | fc->service_connect_ipv4 = serviceListeningInfo; |
941 | serviceListeningInfo->acceptTask = | 850 | serviceListeningInfo->acceptTask = |
942 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | 851 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, |
943 | serviceListeningInfo->listeningSocket, | 852 | serviceListeningInfo->listeningSocket, |
944 | &fc_acceptConnection_ipv4, fc); | 853 | &fc_acceptConnection_ipv4, fc); |
945 | break; | 854 | break; |
946 | case sizeof (struct sockaddr_in6): | 855 | case sizeof (struct sockaddr_in6): |
947 | fc->service_connect_ipv6 = serviceListeningInfo; | 856 | fc->service_connect_ipv6 = serviceListeningInfo; |
948 | serviceListeningInfo->acceptTask = | 857 | serviceListeningInfo->acceptTask = |
949 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | 858 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, |
950 | serviceListeningInfo->listeningSocket, | 859 | serviceListeningInfo->listeningSocket, |
951 | &fc_acceptConnection_ipv6, fc); | 860 | &fc_acceptConnection_ipv6, fc); |
952 | break; | 861 | break; |
953 | default: | 862 | default: |
954 | GNUNET_break (0); | 863 | GNUNET_break (0); |
955 | return 1; | 864 | return 1; |
956 | break; | 865 | } |
957 | } | ||
958 | return 0; | 866 | return 0; |
959 | } | 867 | } |
960 | 868 | ||
961 | 869 | ||
870 | /** | ||
871 | * | ||
872 | */ | ||
873 | static void | ||
874 | start_forwarding (void *cls, | ||
875 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
876 | { | ||
877 | struct ForwardedConnection *fc = cls; | ||
878 | struct GNUNET_TIME_Relative rem; | ||
879 | int failures; | ||
880 | int is_zero; | ||
881 | int is_ipv4; | ||
882 | int is_ipv6; | ||
883 | struct sockaddr_in target_ipv4; | ||
884 | struct sockaddr_in6 target_ipv6; | ||
885 | const struct sockaddr *v4; | ||
886 | const struct sockaddr *v6; | ||
887 | char listen_address[INET_ADDRSTRLEN]; | ||
888 | uint16_t listening_port; /* in big endian */ | ||
889 | |||
890 | fc->start_task = GNUNET_SCHEDULER_NO_TASK; | ||
891 | if ( (NULL != tc) && | ||
892 | (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) ) | ||
893 | { | ||
894 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
895 | _("Unable to forward to service `%s': shutdown\n"), | ||
896 | fc->listen_info->serviceName); | ||
897 | closeClientAndServiceSockets (fc, REASON_ERROR); | ||
898 | return; | ||
899 | } | ||
900 | rem = GNUNET_TIME_absolute_get_remaining (fc->timeout); | ||
901 | if (rem.rel_value == 0) | ||
902 | { | ||
903 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
904 | _("Unable to forward to service `%s': timeout before connect\n"), | ||
905 | fc->listen_info->serviceName); | ||
906 | closeClientAndServiceSockets (fc, REASON_ERROR); | ||
907 | return; | ||
908 | } | ||
909 | switch (fc->listen_info->service_addr->sa_family) | ||
910 | { | ||
911 | case AF_INET: | ||
912 | inet_ntop (fc->listen_info->service_addr->sa_family, | ||
913 | (const void *) &((struct sockaddr_in *) fc->listen_info->service_addr)->sin_addr, | ||
914 | listen_address, | ||
915 | INET_ADDRSTRLEN); | ||
916 | is_zero = (strncmp (listen_address, "0.0.0.0:", 8) == 0) || (strncmp (listen_address, "0.0.0.0", 7) == 0); | ||
917 | is_ipv4 = GNUNET_YES; | ||
918 | is_ipv6 = GNUNET_NO; | ||
919 | listening_port = ((struct sockaddr_in *)fc->listen_info->service_addr)->sin_port; | ||
920 | break; | ||
921 | case AF_INET6: | ||
922 | inet_ntop (fc->listen_info->service_addr->sa_family, | ||
923 | (const void *) &((struct sockaddr_in6 *) fc->listen_info->service_addr)->sin6_addr, | ||
924 | listen_address, | ||
925 | INET6_ADDRSTRLEN); | ||
926 | is_zero = (strncmp (listen_address, "[::]:", 5) == 0) || (strncmp (listen_address, "::", 2) == 0); | ||
927 | is_ipv4 = GNUNET_NO; | ||
928 | is_ipv6 = GNUNET_YES; | ||
929 | listening_port = ((struct sockaddr_in6 *)fc->listen_info->service_addr)->sin6_port; | ||
930 | break; | ||
931 | default: | ||
932 | GNUNET_break (0); | ||
933 | closeClientAndServiceSockets (fc, REASON_ERROR); | ||
934 | return; | ||
935 | } | ||
936 | |||
937 | fc->service_connect_ipv4 = NULL; | ||
938 | fc->service_connect_ipv6 = NULL; | ||
939 | v4 = NULL; | ||
940 | v6 = NULL; | ||
941 | if (is_zero) | ||
942 | { | ||
943 | /* connect to [::1] and 127.0.0.1 instead of [::] and 0.0.0.0 */ | ||
944 | memset (&target_ipv4, 0, sizeof (target_ipv4)); | ||
945 | inet_pton (AF_INET, "127.0.0.1", &target_ipv4.sin_addr); | ||
946 | target_ipv4.sin_family = AF_INET; | ||
947 | target_ipv4.sin_port = listening_port; | ||
948 | v4 = (const struct sockaddr *) &target_ipv4; | ||
949 | is_ipv4 = GNUNET_YES; | ||
950 | |||
951 | memset (&target_ipv6, 0, sizeof (target_ipv6)); | ||
952 | inet_pton (AF_INET6, "::1", &target_ipv6.sin6_addr); | ||
953 | target_ipv6.sin6_family = AF_INET6; | ||
954 | target_ipv6.sin6_port = listening_port; | ||
955 | is_ipv6 = GNUNET_YES; | ||
956 | v6 = (const struct sockaddr *) &target_ipv6; | ||
957 | } | ||
958 | else | ||
959 | { | ||
960 | if (is_ipv4) | ||
961 | v4 = (const struct sockaddr*) fc->listen_info->service_addr; | ||
962 | if (is_ipv6) | ||
963 | v6 = (const struct sockaddr*) fc->listen_info->service_addr; | ||
964 | } | ||
965 | failures = 0; | ||
966 | if (is_ipv4) | ||
967 | failures += service_try_to_connect (v4, | ||
968 | sizeof (struct sockaddr_in), | ||
969 | fc); | ||
970 | if (is_ipv6) | ||
971 | failures += service_try_to_connect (v6, | ||
972 | sizeof (struct sockaddr_in6), | ||
973 | fc); | ||
974 | if (is_ipv4 + is_ipv6 == failures) | ||
975 | { | ||
976 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
977 | _ ("Unable to start service `%s': %s\n"), | ||
978 | fc->listen_info->serviceName, | ||
979 | STRERROR (errno)); | ||
980 | closeClientAndServiceSockets (fc, REASON_ERROR); | ||
981 | return; | ||
982 | } | ||
983 | } | ||
984 | |||
962 | 985 | ||
963 | /** | 986 | /** |
964 | * | 987 | * |