aboutsummaryrefslogtreecommitdiff
path: root/src/arm
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-11-10 08:08:37 +0000
committerChristian Grothoff <christian@grothoff.org>2010-11-10 08:08:37 +0000
commitc096eaed42b83fcd4afc87d3d24fe31975a4b62a (patch)
tree03d6f5ebdbb97180ceba093f63a17c8b776ec527 /src/arm
parentd1d2efce4c68210f4cc6873e2c91b8ba21e876ad (diff)
downloadgnunet-c096eaed42b83fcd4afc87d3d24fe31975a4b62a.tar.gz
gnunet-c096eaed42b83fcd4afc87d3d24fe31975a4b62a.zip
sockets patch from #1616
Diffstat (limited to 'src/arm')
-rw-r--r--src/arm/gnunet-service-arm_interceptor.c287
1 files changed, 223 insertions, 64 deletions
diff --git a/src/arm/gnunet-service-arm_interceptor.c b/src/arm/gnunet-service-arm_interceptor.c
index 56268b2d0..2dd4f3703 100644
--- a/src/arm/gnunet-service-arm_interceptor.c
+++ b/src/arm/gnunet-service-arm_interceptor.c
@@ -187,9 +187,15 @@ struct ForwardedConnection
187 * Have we ever successfully written data to the service? 187 * Have we ever successfully written data to the service?
188 */ 188 */
189 int first_write_done; 189 int first_write_done;
190};
191 190
192 191
192 /**
193 * Service connection attempts
194 */
195 struct ServiceListeningInfo *service_connect_ipv4;
196 struct ServiceListeningInfo *service_connect_ipv6;
197};
198
193/** 199/**
194 * Array with the names of the services started by default. 200 * Array with the names of the services started by default.
195 */ 201 */
@@ -694,6 +700,10 @@ receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
694 &forwardToService, fc); 700 &forwardToService, fc);
695} 701}
696 702
703static void fc_acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc, int is_ipv4, int is_ipv6);
704static void fc_acceptConnection_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
705static void fc_acceptConnection_ipv6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
706static int service_try_to_connect (struct sockaddr *addr, socklen_t addrlen, struct ForwardedConnection *fc);
697 707
698/** 708/**
699 * 709 *
@@ -704,99 +714,248 @@ start_forwarding (void *cls,
704{ 714{
705 struct ForwardedConnection *fc = cls; 715 struct ForwardedConnection *fc = cls;
706 struct GNUNET_TIME_Relative rem; 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;
707 726
708 fc->start_task = GNUNET_SCHEDULER_NO_TASK; 727 fc->start_task = GNUNET_SCHEDULER_NO_TASK;
709 if ( (NULL != tc) && 728 if ( (NULL != tc) &&
710 (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) ) 729 (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) )
711 { 730 {
712 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 731 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
713 _("Unable to forward to service `%s': shutdown\n"), 732 _("Unable to forward to service `%s': shutdown\n"),
714 fc->listen_info->serviceName); 733 fc->listen_info->serviceName);
715 closeClientAndServiceSockets (fc, REASON_ERROR); 734 closeClientAndServiceSockets (fc, REASON_ERROR);
716 return; 735 return;
717 } 736 }
718 rem = GNUNET_TIME_absolute_get_remaining (fc->timeout); 737 rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
719 if (rem.rel_value == 0) 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
818static void
819fc_acceptConnection_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
820{
821 fc_acceptConnection (cls, tc, 1, 0);
822}
823
824static void
825fc_acceptConnection_ipv6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
826{
827 fc_acceptConnection (cls, tc, 0, 1);
828}
829
830static void
831fc_acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc, int is_ipv4, int is_ipv6)
832{
833 struct ForwardedConnection *fc = cls;
834 struct ServiceListeningInfo *sli;
835
836 if (is_ipv4)
837 sli = fc->service_connect_ipv4;
838 else if (is_ipv6)
839 sli = fc->service_connect_ipv6;
840 else
841 GNUNET_break (0);
842
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))
720 { 859 {
721 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 860 GNUNET_SCHEDULER_cancel (fc->service_connect_ipv6->acceptTask);
722 _("Unable to forward to service `%s': timeout before connect\n"), 861 fc->service_connect_ipv6->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv6, fc);
723 fc->listen_info->serviceName);
724 closeClientAndServiceSockets (fc, REASON_ERROR);
725 return;
726 }
727 fc->armServiceSocket =
728 GNUNET_NETWORK_socket_create (fc->listen_info->service_addr->sa_family,
729 SOCK_STREAM, 0);
730 if (NULL == fc->armServiceSocket)
731 {
732 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
733 _ ("Unable to start service `%s': %s\n"),
734 fc->listen_info->serviceName,
735 STRERROR (errno));
736 closeClientAndServiceSockets (fc, REASON_ERROR);
737 return;
738 } 862 }
739 if ( (GNUNET_SYSERR == 863 else if (is_ipv6 && fc->service_connect_ipv4 != NULL)
740 GNUNET_NETWORK_socket_connect (fc->armServiceSocket,
741 fc->listen_info->service_addr,
742 fc->listen_info->service_addr_len)) &&
743 (errno != EINPROGRESS) )
744 { 864 {
745 GNUNET_break (GNUNET_OK == 865 GNUNET_SCHEDULER_cancel (fc->service_connect_ipv4->acceptTask);
746 GNUNET_NETWORK_socket_close (fc->armServiceSocket)); 866 fc->service_connect_ipv4->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv4, fc);
747 fc->armServiceSocket = NULL;
748 fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
749 #if DEBUG_SERVICE_MANAGER
750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
751 "Failed to connected to service `%s' at `%s', will try again in %llu ms\n",
752 fc->listen_info->serviceName,
753 GNUNET_a2s (fc->listen_info->service_addr,
754 fc->listen_info->service_addr_len),
755 (unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
756 rem).rel_value);
757#endif
758 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
759 fc->start_task
760 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_min (fc->back_off,
761 rem),
762 &start_forwarding,
763 fc);
764 return;
765 } 867 }
766#if DEBUG_SERVICE_MANAGER 868 GNUNET_free (fc->listen_info->service_addr);
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 869 fc->listen_info->service_addr = sli->service_addr;
768 "Connected to service, now starting forwarding\n"); 870 fc->listen_info->service_addr_len = sli->service_addr_len;
769#endif 871 /*fc->listen_info->listeningSocket is it closed already?*/
770 if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK) 872 if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK)
771 { 873 {
772 if (fc->client_to_service_bufferDataLength == 0) 874 if (fc->client_to_service_bufferDataLength == 0)
773 fc->client_to_service_task = 875 fc->client_to_service_task =
774 GNUNET_SCHEDULER_add_read_net ( 876 GNUNET_SCHEDULER_add_read_net (
775 GNUNET_TIME_UNIT_FOREVER_REL, 877 GNUNET_TIME_UNIT_FOREVER_REL,
776 fc->armClientSocket, 878 fc->armClientSocket,
777 &receiveFromClient, fc); 879 &receiveFromClient, fc);
778 else 880 else
779 fc->client_to_service_task = 881 fc->client_to_service_task =
780 GNUNET_SCHEDULER_add_write_net ( 882 GNUNET_SCHEDULER_add_write_net (
781 GNUNET_TIME_UNIT_FOREVER_REL, 883 GNUNET_TIME_UNIT_FOREVER_REL,
782 fc->armServiceSocket, 884 fc->armServiceSocket,
783 &forwardToService, fc); 885 &forwardToService, fc);
784 } 886 }
785 if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK) 887 if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK)
786 { 888 {
787 if (fc->service_to_client_bufferDataLength == 0) 889 if (fc->service_to_client_bufferDataLength == 0)
788 fc->service_to_client_task = 890 fc->service_to_client_task =
789 GNUNET_SCHEDULER_add_read_net ( 891 GNUNET_SCHEDULER_add_read_net (
790 GNUNET_TIME_UNIT_FOREVER_REL, 892 GNUNET_TIME_UNIT_FOREVER_REL,
791 fc->armServiceSocket, 893 fc->armServiceSocket,
792 &receiveFromService, fc); 894 &receiveFromService, fc);
793 else 895 else
794 fc->service_to_client_task = 896 fc->service_to_client_task =
795 GNUNET_SCHEDULER_add_write_net ( 897 GNUNET_SCHEDULER_add_write_net (
796 GNUNET_TIME_UNIT_FOREVER_REL, 898 GNUNET_TIME_UNIT_FOREVER_REL,
797 fc->armClientSocket, 899 fc->armClientSocket,
798 &forwardToClient, fc); 900 &forwardToClient, fc);
799 } 901 }
902 }
903 else
904 {
905 GNUNET_break (0);
906 }
907 GNUNET_free (sli);
908}
909
910static int
911service_try_to_connect (struct sockaddr *addr, socklen_t addrlen, struct ForwardedConnection *fc)
912{
913 struct GNUNET_NETWORK_Handle *sock;
914 struct ServiceListeningInfo *serviceListeningInfo;
915
916 sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
917 if (sock == NULL)
918 {
919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to create a socket\n");
920 return 1;
921 }
922
923 if ( (GNUNET_SYSERR == GNUNET_NETWORK_socket_connect (sock, addr, addrlen)) &&
924 (errno != EINPROGRESS) )
925 {
926 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect\n");
927 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
928 return 1;
929 }
930
931 serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
932 serviceListeningInfo->serviceName = NULL;
933 serviceListeningInfo->service_addr = addr;
934 serviceListeningInfo->service_addr_len = addrlen;
935 serviceListeningInfo->listeningSocket = sock;
936
937 switch (addrlen)
938 {
939 case sizeof (struct sockaddr_in):
940 fc->service_connect_ipv4 = serviceListeningInfo;
941 serviceListeningInfo->acceptTask =
942 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
943 serviceListeningInfo->listeningSocket,
944 &fc_acceptConnection_ipv4, fc);
945 break;
946 case sizeof (struct sockaddr_in6):
947 fc->service_connect_ipv6 = serviceListeningInfo;
948 serviceListeningInfo->acceptTask =
949 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
950 serviceListeningInfo->listeningSocket,
951 &fc_acceptConnection_ipv6, fc);
952 break;
953 default:
954 GNUNET_break (0);
955 return 1;
956 break;
957 }
958 return 0;
800} 959}
801 960
802 961