diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-08-11 11:05:35 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-08-11 11:05:35 +0000 |
commit | 6202dff2295abe7813a12bb53b90916bf26bb132 (patch) | |
tree | b85554987672862cdff97a597f8311df8ce55b28 /src/util | |
parent | ac8f7679c65c1bea265f2a1501a5f6901a1227e9 (diff) | |
download | gnunet-6202dff2295abe7813a12bb53b90916bf26bb132.tar.gz gnunet-6202dff2295abe7813a12bb53b90916bf26bb132.zip |
use bind instead of connect to test if service is running to avoid long timeouts during startup
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/client.c | 174 | ||||
-rw-r--r-- | src/util/network.c | 2 |
2 files changed, 173 insertions, 3 deletions
diff --git a/src/util/client.c b/src/util/client.c index 490d1f3da..a05c5bf75 100644 --- a/src/util/client.c +++ b/src/util/client.c | |||
@@ -666,6 +666,15 @@ confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg) | |||
666 | } | 666 | } |
667 | 667 | ||
668 | 668 | ||
669 | /** | ||
670 | * Send the 'TEST' message to the service. If successful, prepare to | ||
671 | * receive the reply. | ||
672 | * | ||
673 | * @param cls the 'struct GNUNET_CLIENT_Connection' of the connection to test | ||
674 | * @param size number of bytes available in buf | ||
675 | * @param buf where to write the message | ||
676 | * @return number of bytes written to buf | ||
677 | */ | ||
669 | static size_t | 678 | static size_t |
670 | write_test (void *cls, size_t size, void *buf) | 679 | write_test (void *cls, size_t size, void *buf) |
671 | { | 680 | { |
@@ -698,11 +707,13 @@ write_test (void *cls, size_t size, void *buf) | |||
698 | 707 | ||
699 | 708 | ||
700 | /** | 709 | /** |
701 | * Wait until the service is running. | 710 | * Test if the service is running. If we are given a UNIXPATH or a local address, |
711 | * we do this NOT by trying to connect to the service, but by trying to BIND to | ||
712 | * the same port. If the BIND fails, we know the service is running. | ||
702 | * | 713 | * |
703 | * @param service name of the service to wait for | 714 | * @param service name of the service to wait for |
704 | * @param cfg configuration to use | 715 | * @param cfg configuration to use |
705 | * @param timeout how long to wait at most in ms | 716 | * @param timeout how long to wait at most |
706 | * @param task task to run if service is running | 717 | * @param task task to run if service is running |
707 | * (reason will be "PREREQ_DONE" (service running) | 718 | * (reason will be "PREREQ_DONE" (service running) |
708 | * or "TIMEOUT" (service not known to be running)) | 719 | * or "TIMEOUT" (service not known to be running)) |
@@ -714,12 +725,171 @@ GNUNET_CLIENT_service_test (const char *service, | |||
714 | struct GNUNET_TIME_Relative timeout, | 725 | struct GNUNET_TIME_Relative timeout, |
715 | GNUNET_SCHEDULER_Task task, void *task_cls) | 726 | GNUNET_SCHEDULER_Task task, void *task_cls) |
716 | { | 727 | { |
728 | char *hostname; | ||
729 | unsigned long long port; | ||
730 | struct GNUNET_NETWORK_Handle *sock; | ||
717 | struct GNUNET_CLIENT_Connection *conn; | 731 | struct GNUNET_CLIENT_Connection *conn; |
718 | 732 | ||
719 | #if DEBUG_CLIENT | 733 | #if DEBUG_CLIENT |
720 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 734 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
721 | "Testing if service `%s' is running.\n", service); | 735 | "Testing if service `%s' is running.\n", service); |
722 | #endif | 736 | #endif |
737 | #ifdef AF_UNIX | ||
738 | { | ||
739 | /* probe UNIX support */ | ||
740 | struct sockaddr_un s_un; | ||
741 | size_t slen; | ||
742 | char *unixpath; | ||
743 | |||
744 | unixpath = NULL; | ||
745 | if ( (GNUNET_OK == | ||
746 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
747 | service, | ||
748 | "UNIXPATH", &unixpath)) && | ||
749 | (0 < strlen (unixpath)) ) /* We have a non-NULL unixpath, does that mean it's valid? */ | ||
750 | { | ||
751 | if (strlen(unixpath) >= sizeof(s_un.sun_path)) | ||
752 | { | ||
753 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
754 | _("UNIXPATH `%s' too long, maximum length is %llu\n"), | ||
755 | unixpath, | ||
756 | sizeof(s_un.sun_path)); | ||
757 | } | ||
758 | else | ||
759 | { | ||
760 | sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); | ||
761 | if (sock != NULL) | ||
762 | { | ||
763 | memset (&s_un, 0, sizeof (s_un)); | ||
764 | s_un.sun_family = AF_UNIX; | ||
765 | slen = strlen (unixpath) + 1; | ||
766 | if (slen >= sizeof (s_un.sun_path)) | ||
767 | slen = sizeof (s_un.sun_path) - 1; | ||
768 | memcpy (s_un.sun_path, | ||
769 | unixpath, | ||
770 | slen); | ||
771 | s_un.sun_path[slen] = '\0'; | ||
772 | slen = sizeof (struct sockaddr_un); | ||
773 | #if LINUX | ||
774 | s_un.sun_path[0] = '\0'; | ||
775 | #endif | ||
776 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
777 | s_un.sun_len = (u_char) slen; | ||
778 | #endif | ||
779 | if (GNUNET_OK != | ||
780 | GNUNET_NETWORK_socket_bind (sock, | ||
781 | (const struct sockaddr*) &s_un, | ||
782 | slen)) | ||
783 | { | ||
784 | /* failed to bind => service must be running */ | ||
785 | GNUNET_free (unixpath); | ||
786 | (void) GNUNET_NETWORK_socket_close (sock); | ||
787 | GNUNET_SCHEDULER_add_continuation (task, | ||
788 | task_cls, | ||
789 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
790 | return; | ||
791 | } | ||
792 | (void) GNUNET_NETWORK_socket_close (sock); | ||
793 | } | ||
794 | /* let's try IP */ | ||
795 | } | ||
796 | } | ||
797 | GNUNET_free_non_null (unixpath); | ||
798 | } | ||
799 | #endif | ||
800 | |||
801 | hostname = NULL; | ||
802 | if ((GNUNET_OK != | ||
803 | GNUNET_CONFIGURATION_get_value_number (cfg, | ||
804 | service, | ||
805 | "PORT", | ||
806 | &port)) || | ||
807 | (port > 65535) || | ||
808 | (GNUNET_OK != | ||
809 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
810 | service, | ||
811 | "HOSTNAME", &hostname))) | ||
812 | { | ||
813 | /* UNIXPATH failed (if possible) AND IP failed => error */ | ||
814 | service_test_error (task, task_cls); | ||
815 | return; | ||
816 | } | ||
817 | |||
818 | if (0 == strcmp ("localhost", hostname)) | ||
819 | { | ||
820 | /* can test using 'bind' */ | ||
821 | struct sockaddr_in s_in; | ||
822 | |||
823 | memset (&s_in, 0, sizeof (s_in)); | ||
824 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
825 | s_in.sin_len = saddrlens[1]; | ||
826 | #endif | ||
827 | s_in.sin_family = AF_INET; | ||
828 | s_in.sin_port = htons (port); | ||
829 | |||
830 | sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); | ||
831 | if (sock != NULL) | ||
832 | { | ||
833 | if (GNUNET_OK != | ||
834 | GNUNET_NETWORK_socket_bind (sock, | ||
835 | (const struct sockaddr*) &s_in, | ||
836 | sizeof (s_in))) | ||
837 | { | ||
838 | /* failed to bind => service must be running */ | ||
839 | GNUNET_free (hostname); | ||
840 | (void) GNUNET_NETWORK_socket_close (sock); | ||
841 | GNUNET_SCHEDULER_add_continuation (task, | ||
842 | task_cls, | ||
843 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
844 | return; | ||
845 | } | ||
846 | (void) GNUNET_NETWORK_socket_close (sock); | ||
847 | } | ||
848 | } | ||
849 | |||
850 | if (0 == strcmp ("ip6-localhost", hostname)) | ||
851 | { | ||
852 | /* can test using 'bind' */ | ||
853 | struct sockaddr_in6 s_in6; | ||
854 | |||
855 | memset (&s_in6, 0, sizeof (s_in6)); | ||
856 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
857 | s_in6.sin6_len = saddrlens[1]; | ||
858 | #endif | ||
859 | s_in6.sin6_family = AF_INET6; | ||
860 | s_in6.sin6_port = htons (port); | ||
861 | |||
862 | sock = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0); | ||
863 | if (sock != NULL) | ||
864 | { | ||
865 | if (GNUNET_OK != | ||
866 | GNUNET_NETWORK_socket_bind (sock, | ||
867 | (const struct sockaddr*) &s_in6, | ||
868 | sizeof (s_in6))) | ||
869 | { | ||
870 | /* failed to bind => service must be running */ | ||
871 | GNUNET_free (hostname); | ||
872 | (void) GNUNET_NETWORK_socket_close (sock); | ||
873 | GNUNET_SCHEDULER_add_continuation (task, | ||
874 | task_cls, | ||
875 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
876 | return; | ||
877 | } | ||
878 | (void) GNUNET_NETWORK_socket_close (sock); | ||
879 | } | ||
880 | } | ||
881 | |||
882 | if ( (0 == strcmp ("localhost", hostname)) || | ||
883 | (0 == strcmp ("ip6-localhost", hostname)) ) | ||
884 | { | ||
885 | /* all binds succeeded => claim service not running right now */ | ||
886 | GNUNET_free_non_null (hostname); | ||
887 | service_test_error (task, task_cls); | ||
888 | return; | ||
889 | } | ||
890 | GNUNET_free_non_null (hostname); | ||
891 | |||
892 | /* non-localhost, try 'connect' method */ | ||
723 | conn = GNUNET_CLIENT_connect (service, cfg); | 893 | conn = GNUNET_CLIENT_connect (service, cfg); |
724 | if (conn == NULL) | 894 | if (conn == NULL) |
725 | { | 895 | { |
diff --git a/src/util/network.c b/src/util/network.c index 9c6d0c90b..98eeb7b0c 100644 --- a/src/util/network.c +++ b/src/util/network.c | |||
@@ -321,7 +321,7 @@ GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc, | |||
321 | SetErrnoFromWinsockError (WSAGetLastError ()); | 321 | SetErrnoFromWinsockError (WSAGetLastError ()); |
322 | #endif | 322 | #endif |
323 | if (ret != 0) | 323 | if (ret != 0) |
324 | return GNUNET_SYSERR; | 324 | return GNUNET_SYSERR; |
325 | #ifndef MINGW | 325 | #ifndef MINGW |
326 | #ifndef LINUX | 326 | #ifndef LINUX |
327 | desc->addr = GNUNET_malloc (address_len); | 327 | desc->addr = GNUNET_malloc (address_len); |