aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-08-11 11:05:35 +0000
committerChristian Grothoff <christian@grothoff.org>2011-08-11 11:05:35 +0000
commit6202dff2295abe7813a12bb53b90916bf26bb132 (patch)
treeb85554987672862cdff97a597f8311df8ce55b28 /src/util
parentac8f7679c65c1bea265f2a1501a5f6901a1227e9 (diff)
downloadgnunet-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.c174
-rw-r--r--src/util/network.c2
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 */
669static size_t 678static size_t
670write_test (void *cls, size_t size, void *buf) 679write_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);