aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-06-05 21:33:58 +0000
committerChristian Grothoff <christian@grothoff.org>2013-06-05 21:33:58 +0000
commita998e0abbd220035bdb333388da229852980e2cc (patch)
treeaddf062abb3cc68ab1103a415fbdec315dd54a63 /src/util
parent4ce2d673d41ad8a8b9e5389b5b97ecb5e77f190d (diff)
downloadgnunet-a998e0abbd220035bdb333388da229852980e2cc.tar.gz
gnunet-a998e0abbd220035bdb333388da229852980e2cc.zip
-cleaning up client api to test for service availability
Diffstat (limited to 'src/util')
-rw-r--r--src/util/client.c225
-rw-r--r--src/util/test_service.c25
2 files changed, 167 insertions, 83 deletions
diff --git a/src/util/client.c b/src/util/client.c
index 8b4776201..73b912cc6 100644
--- a/src/util/client.c
+++ b/src/util/client.c
@@ -179,27 +179,12 @@ struct GNUNET_CLIENT_Connection
179 struct GNUNET_CLIENT_TransmitHandle *th; 179 struct GNUNET_CLIENT_TransmitHandle *th;
180 180
181 /** 181 /**
182 * Handler for service test completion (NULL unless in service_test)
183 */
184 GNUNET_SCHEDULER_Task test_cb;
185
186 /**
187 * Deadline for calling 'test_cb'.
188 */
189 struct GNUNET_TIME_Absolute test_deadline;
190
191 /**
192 * If we are re-trying and are delaying to do so, 182 * If we are re-trying and are delaying to do so,
193 * handle to the scheduled task managing the delay. 183 * handle to the scheduled task managing the delay.
194 */ 184 */
195 GNUNET_SCHEDULER_TaskIdentifier receive_task; 185 GNUNET_SCHEDULER_TaskIdentifier receive_task;
196 186
197 /** 187 /**
198 * Closure for test_cb (NULL unless in service_test)
199 */
200 void *test_cb_cls;
201
202 /**
203 * Buffer for received message. 188 * Buffer for received message.
204 */ 189 */
205 char *received_buf; 190 char *received_buf;
@@ -639,26 +624,119 @@ GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *client,
639 624
640 625
641/** 626/**
642 * Report service unavailable. 627 * Handle for a test to check if a service is running.
628 */
629struct GNUNET_CLIENT_TestHandle
630{
631 /**
632 * Function to call with the result of the test.
633 */
634 GNUNET_CLIENT_TestResultCallback cb;
635
636 /**
637 * Closure for 'cb'.
638 */
639 void *cb_cls;
640
641 /**
642 * Client connection we are using for the test, if any.
643 */
644 struct GNUNET_CLIENT_Connection *client;
645
646 /**
647 * Handle for the transmission request, if any.
648 */
649 struct GNUNET_CLIENT_TransmitHandle *th;
650
651 /**
652 * Deadline for calling 'cb'.
653 */
654 struct GNUNET_TIME_Absolute test_deadline;
655
656 /**
657 * ID of task used for asynchronous operations.
658 */
659 GNUNET_SCHEDULER_TaskIdentifier task;
660
661 /**
662 * Final result to report back (once known).
663 */
664 int result;
665};
666
667
668/**
669 * Abort testing for service.
670 *
671 * @param th test handle
672 */
673void
674GNUNET_CLIENT_service_test_cancel (struct GNUNET_CLIENT_TestHandle *th)
675{
676 if (NULL != th->th)
677 {
678 GNUNET_CLIENT_notify_transmit_ready_cancel (th->th);
679 th->th = NULL;
680 }
681 if (NULL != th->client)
682 {
683 GNUNET_CLIENT_disconnect (th->client);
684 th->client = NULL;
685 }
686 if (GNUNET_SCHEDULER_NO_TASK != th->task)
687 {
688 GNUNET_SCHEDULER_cancel (th->task);
689 th->task = GNUNET_SCHEDULER_NO_TASK;
690 }
691 GNUNET_free (th);
692}
693
694
695/**
696 * Task that reports back the result by calling the callback
697 * and then cleans up.
698 *
699 * @param cls the 'struct GNUNET_CLIENT_TestHandle'
700 * @param tc scheduler context
701 */
702static void
703report_result (void *cls,
704 const struct GNUNET_SCHEDULER_TaskContext *tc)
705{
706 struct GNUNET_CLIENT_TestHandle *th = cls;
707
708 th->task = GNUNET_SCHEDULER_NO_TASK;
709 th->cb (th->cb_cls, th->result);
710 GNUNET_CLIENT_service_test_cancel (th);
711}
712
713
714/**
715 * Report service test result asynchronously back to callback.
716 *
717 * @param th test handle with the result and the callback
718 * @param result result to report
643 */ 719 */
644static void 720static void
645service_test_error (GNUNET_SCHEDULER_Task task, void *task_cls) 721service_test_report (struct GNUNET_CLIENT_TestHandle *th,
722 int result)
646{ 723{
647 GNUNET_SCHEDULER_add_continuation (task, task_cls, 724 th->result = result;
648 GNUNET_SCHEDULER_REASON_TIMEOUT); 725 th->task = GNUNET_SCHEDULER_add_now (&report_result,
726 th);
649} 727}
650 728
651 729
652/** 730/**
653 * Receive confirmation from test, service is up. 731 * Receive confirmation from test, service is up.
654 * 732 *
655 * @param cls closure 733 * @param cls closure with the 'struct GNUNET_CLIENT_TestHandle'
656 * @param msg message received, NULL on timeout or fatal error 734 * @param msg message received, NULL on timeout or fatal error
657 */ 735 */
658static void 736static void
659confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg) 737confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg)
660{ 738{
661 struct GNUNET_CLIENT_Connection *client = cls; 739 struct GNUNET_CLIENT_TestHandle *th = cls;
662 740
663 /* We may want to consider looking at the reply in more 741 /* We may want to consider looking at the reply in more
664 * detail in the future, for example, is this the 742 * detail in the future, for example, is this the
@@ -667,14 +745,12 @@ confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg)
667 { 745 {
668 LOG (GNUNET_ERROR_TYPE_DEBUG, 746 LOG (GNUNET_ERROR_TYPE_DEBUG,
669 "Received confirmation that service is running.\n"); 747 "Received confirmation that service is running.\n");
670 GNUNET_SCHEDULER_add_continuation (client->test_cb, client->test_cb_cls, 748 service_test_report (th, GNUNET_YES);
671 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
672 } 749 }
673 else 750 else
674 { 751 {
675 service_test_error (client->test_cb, client->test_cb_cls); 752 service_test_report (th, GNUNET_NO);
676 } 753 }
677 GNUNET_CLIENT_disconnect (client);
678} 754}
679 755
680 756
@@ -682,7 +758,7 @@ confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg)
682 * Send the 'TEST' message to the service. If successful, prepare to 758 * Send the 'TEST' message to the service. If successful, prepare to
683 * receive the reply. 759 * receive the reply.
684 * 760 *
685 * @param cls the 'struct GNUNET_CLIENT_Connection' of the connection to test 761 * @param cls the 'struct GNUNET_CLIENT_TestHandle' of the test
686 * @param size number of bytes available in buf 762 * @param size number of bytes available in buf
687 * @param buf where to write the message 763 * @param buf where to write the message
688 * @return number of bytes written to buf 764 * @return number of bytes written to buf
@@ -690,52 +766,61 @@ confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg)
690static size_t 766static size_t
691write_test (void *cls, size_t size, void *buf) 767write_test (void *cls, size_t size, void *buf)
692{ 768{
693 struct GNUNET_CLIENT_Connection *client = cls; 769 struct GNUNET_CLIENT_TestHandle *th = cls;
694 struct GNUNET_MessageHeader *msg; 770 struct GNUNET_MessageHeader *msg;
695 771
772 th->th = NULL;
696 if (size < sizeof (struct GNUNET_MessageHeader)) 773 if (size < sizeof (struct GNUNET_MessageHeader))
697 { 774 {
698 LOG (GNUNET_ERROR_TYPE_DEBUG, _("Failure to transmit TEST request.\n")); 775 LOG (GNUNET_ERROR_TYPE_DEBUG,
699 service_test_error (client->test_cb, client->test_cb_cls); 776 "Failed to transmit TEST request.\n");
700 GNUNET_CLIENT_disconnect (client); 777 service_test_report (th, GNUNET_NO);
701 return 0; /* client disconnected */ 778 return 0; /* client disconnected */
702 } 779 }
703 LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "TEST"); 780 LOG (GNUNET_ERROR_TYPE_DEBUG,
781 "Transmitting `%s' request.\n",
782 "TEST");
704 msg = (struct GNUNET_MessageHeader *) buf; 783 msg = (struct GNUNET_MessageHeader *) buf;
705 msg->type = htons (GNUNET_MESSAGE_TYPE_TEST); 784 msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
706 msg->size = htons (sizeof (struct GNUNET_MessageHeader)); 785 msg->size = htons (sizeof (struct GNUNET_MessageHeader));
707 GNUNET_CLIENT_receive (client, &confirm_handler, client, 786 GNUNET_CLIENT_receive (th->client,
787 &confirm_handler, th,
708 GNUNET_TIME_absolute_get_remaining 788 GNUNET_TIME_absolute_get_remaining
709 (client->test_deadline)); 789 (th->test_deadline));
710 return sizeof (struct GNUNET_MessageHeader); 790 return sizeof (struct GNUNET_MessageHeader);
711} 791}
712 792
713 793
714/** 794/**
715 * Test if the service is running. If we are given a UNIXPATH or a local address, 795 * Test if the service is running. If we are given a UNIXPATH or a
716 * we do this NOT by trying to connect to the service, but by trying to BIND to 796 * local address, we do this NOT by trying to connect to the service,
717 * the same port. If the BIND fails, we know the service is running. 797 * but by trying to BIND to the same port. If the BIND fails, we know
798 * the service is running.
718 * 799 *
719 * @param service name of the service to wait for 800 * @param service name of the service to wait for
720 * @param cfg configuration to use 801 * @param cfg configuration to use
721 * @param timeout how long to wait at most 802 * @param timeout how long to wait at most
722 * @param task task to run if service is running 803 * @param cb function to call with the result
723 * (reason will be "PREREQ_DONE" (service running) 804 * @param cb_cls closure for 'cb'
724 * or "TIMEOUT" (service not known to be running)) 805 * @return handle to cancel the test
725 * @param task_cls closure for task
726 */ 806 */
727void 807struct GNUNET_CLIENT_TestHandle *
728GNUNET_CLIENT_service_test (const char *service, 808GNUNET_CLIENT_service_test (const char *service,
729 const struct GNUNET_CONFIGURATION_Handle *cfg, 809 const struct GNUNET_CONFIGURATION_Handle *cfg,
730 struct GNUNET_TIME_Relative timeout, 810 struct GNUNET_TIME_Relative timeout,
731 GNUNET_SCHEDULER_Task task, void *task_cls) 811 GNUNET_CLIENT_TestResultCallback cb, void *cb_cls)
732{ 812{
813 struct GNUNET_CLIENT_TestHandle *th;
733 char *hostname; 814 char *hostname;
734 unsigned long long port; 815 unsigned long long port;
735 struct GNUNET_NETWORK_Handle *sock; 816 struct GNUNET_NETWORK_Handle *sock;
736 struct GNUNET_CLIENT_Connection *client;
737 817
738 LOG (GNUNET_ERROR_TYPE_DEBUG, "Testing if service `%s' is running.\n", 818 th = GNUNET_new (struct GNUNET_CLIENT_TestHandle);
819 th->cb = cb;
820 th->cb_cls = cb_cls;
821 th->test_deadline = GNUNET_TIME_relative_to_absolute (timeout);
822 LOG (GNUNET_ERROR_TYPE_DEBUG,
823 "Testing if service `%s' is running.\n",
739 service); 824 service);
740#ifdef AF_UNIX 825#ifdef AF_UNIX
741 { 826 {
@@ -783,9 +868,8 @@ GNUNET_CLIENT_service_test (const char *service,
783 /* failed to bind => service must be running */ 868 /* failed to bind => service must be running */
784 GNUNET_free (unixpath); 869 GNUNET_free (unixpath);
785 (void) GNUNET_NETWORK_socket_close (sock); 870 (void) GNUNET_NETWORK_socket_close (sock);
786 GNUNET_SCHEDULER_add_continuation (task, task_cls, 871 service_test_report (th, GNUNET_YES);
787 GNUNET_SCHEDULER_REASON_PREREQ_DONE); 872 return th;
788 return;
789 } 873 }
790 (void) GNUNET_NETWORK_socket_close (sock); 874 (void) GNUNET_NETWORK_socket_close (sock);
791 /* let's try IP */ 875 /* let's try IP */
@@ -804,8 +888,8 @@ GNUNET_CLIENT_service_test (const char *service,
804 &hostname))) 888 &hostname)))
805 { 889 {
806 /* UNIXPATH failed (if possible) AND IP failed => error */ 890 /* UNIXPATH failed (if possible) AND IP failed => error */
807 service_test_error (task, task_cls); 891 service_test_report (th, GNUNET_SYSERR);
808 return; 892 return th;
809 } 893 }
810 894
811 if (0 == strcmp ("localhost", hostname) 895 if (0 == strcmp ("localhost", hostname)
@@ -834,9 +918,8 @@ GNUNET_CLIENT_service_test (const char *service,
834 /* failed to bind => service must be running */ 918 /* failed to bind => service must be running */
835 GNUNET_free (hostname); 919 GNUNET_free (hostname);
836 (void) GNUNET_NETWORK_socket_close (sock); 920 (void) GNUNET_NETWORK_socket_close (sock);
837 GNUNET_SCHEDULER_add_continuation (task, task_cls, 921 service_test_report (th, GNUNET_YES);
838 GNUNET_SCHEDULER_REASON_PREREQ_DONE); 922 return th;
839 return;
840 } 923 }
841 (void) GNUNET_NETWORK_socket_close (sock); 924 (void) GNUNET_NETWORK_socket_close (sock);
842 } 925 }
@@ -868,9 +951,8 @@ GNUNET_CLIENT_service_test (const char *service,
868 /* failed to bind => service must be running */ 951 /* failed to bind => service must be running */
869 GNUNET_free (hostname); 952 GNUNET_free (hostname);
870 (void) GNUNET_NETWORK_socket_close (sock); 953 (void) GNUNET_NETWORK_socket_close (sock);
871 GNUNET_SCHEDULER_add_continuation (task, task_cls, 954 service_test_report (th, GNUNET_YES);
872 GNUNET_SCHEDULER_REASON_PREREQ_DONE); 955 return th;
873 return;
874 } 956 }
875 (void) GNUNET_NETWORK_socket_close (sock); 957 (void) GNUNET_NETWORK_socket_close (sock);
876 } 958 }
@@ -885,35 +967,33 @@ GNUNET_CLIENT_service_test (const char *service,
885 { 967 {
886 /* all binds succeeded => claim service not running right now */ 968 /* all binds succeeded => claim service not running right now */
887 GNUNET_free_non_null (hostname); 969 GNUNET_free_non_null (hostname);
888 service_test_error (task, task_cls); 970 service_test_report (th, GNUNET_NO);
889 return; 971 return th;
890 } 972 }
891 GNUNET_free_non_null (hostname); 973 GNUNET_free_non_null (hostname);
892 974
893 /* non-localhost, try 'connect' method */ 975 /* non-localhost, try 'connect' method */
894 client = GNUNET_CLIENT_connect (service, cfg); 976 th->client = GNUNET_CLIENT_connect (service, cfg);
895 if (NULL == client) 977 if (NULL == th->client)
896 { 978 {
897 LOG (GNUNET_ERROR_TYPE_INFO, 979 LOG (GNUNET_ERROR_TYPE_INFO,
898 _("Could not connect to service `%s', must not be running.\n"), 980 _("Could not connect to service `%s', configuration broken.\n"),
899 service); 981 service);
900 service_test_error (task, task_cls); 982 service_test_report (th, GNUNET_SYSERR);
901 return; 983 return th;
902 } 984 }
903 client->test_cb = task; 985 th->th = GNUNET_CLIENT_notify_transmit_ready (th->client,
904 client->test_cb_cls = task_cls; 986 sizeof (struct GNUNET_MessageHeader),
905 client->test_deadline = GNUNET_TIME_relative_to_absolute (timeout); 987 timeout, GNUNET_YES,
906 if (NULL == GNUNET_CLIENT_notify_transmit_ready (client, 988 &write_test, th);
907 sizeof (struct GNUNET_MessageHeader), 989 if (NULL == th->th)
908 timeout, GNUNET_YES, &write_test,
909 client))
910 { 990 {
911 LOG (GNUNET_ERROR_TYPE_WARNING, 991 LOG (GNUNET_ERROR_TYPE_WARNING,
912 _("Failure to transmit request to service `%s'\n"), service); 992 _("Failure to transmit request to service `%s'\n"), service);
913 service_test_error (task, task_cls); 993 service_test_report (th, GNUNET_SYSERR);
914 GNUNET_CLIENT_disconnect (client); 994 return th;
915 return;
916 } 995 }
996 return th;
917} 997}
918 998
919 999
@@ -1246,5 +1326,4 @@ GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection *client
1246} 1326}
1247 1327
1248 1328
1249
1250/* end of client.c */ 1329/* end of client.c */
diff --git a/src/util/test_service.c b/src/util/test_service.c
index be49d1877..bdd3d8521 100644
--- a/src/util/test_service.c
+++ b/src/util/test_service.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors) 3 (C) 2009, 2013 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -20,6 +20,7 @@
20/** 20/**
21 * @file util/test_service.c 21 * @file util/test_service.c
22 * @brief tests for service.c 22 * @brief tests for service.c
23 * @author Christian Grothoff
23 */ 24 */
24#include "platform.h" 25#include "platform.h"
25#include "gnunet_common.h" 26#include "gnunet_common.h"
@@ -33,6 +34,9 @@
33 34
34#define PORT 12435 35#define PORT 12435
35 36
37/**
38 * Message type we use for testing.
39 */
36#define MY_TYPE 256 40#define MY_TYPE 256
37 41
38static struct GNUNET_SERVICE_Context *sctx; 42static struct GNUNET_SERVICE_Context *sctx;
@@ -42,8 +46,6 @@ static int ok = 1;
42static struct GNUNET_CLIENT_Connection *client; 46static struct GNUNET_CLIENT_Connection *client;
43 47
44 48
45
46
47static void 49static void
48do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 50do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
49{ 51{
@@ -87,11 +89,12 @@ build_msg (void *cls, size_t size, void *buf)
87 89
88 90
89static void 91static void
90ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 92ready (void *cls,
93 int result)
91{ 94{
92 const struct GNUNET_CONFIGURATION_Handle *cfg = cls; 95 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
93 96
94 GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); 97 GNUNET_assert (GNUNET_YES == result);
95 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service confirmed running\n"); 98 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service confirmed running\n");
96 client = GNUNET_CLIENT_connect ("test_service", cfg); 99 client = GNUNET_CLIENT_connect ("test_service", cfg);
97 GNUNET_assert (client != NULL); 100 GNUNET_assert (client != NULL);
@@ -108,8 +111,7 @@ static void
108recv_cb (void *cls, struct GNUNET_SERVER_Client *sc, 111recv_cb (void *cls, struct GNUNET_SERVER_Client *sc,
109 const struct GNUNET_MessageHeader *message) 112 const struct GNUNET_MessageHeader *message)
110{ 113{
111 if (NULL == message) 114 GNUNET_assert (NULL != message);
112 return;
113 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving client message...\n"); 115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving client message...\n");
114 GNUNET_SERVER_receive_done (sc, GNUNET_OK); 116 GNUNET_SERVER_receive_done (sc, GNUNET_OK);
115 GNUNET_SCHEDULER_add_now (&do_stop, NULL); 117 GNUNET_SCHEDULER_add_now (&do_stop, NULL);
@@ -156,13 +158,15 @@ check ()
156 return ok; 158 return ok;
157} 159}
158 160
161
159static void 162static void
160ready6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 163ready6 (void *cls,
164 int result)
161{ 165{
162 const struct GNUNET_CONFIGURATION_Handle *cfg = cls; 166 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
163 167
164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "V6 ready\n"); 168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "V6 ready\n");
165 GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); 169 GNUNET_assert (GNUNET_YES == result);
166 client = GNUNET_CLIENT_connect ("test_service6", cfg); 170 client = GNUNET_CLIENT_connect ("test_service6", cfg);
167 GNUNET_assert (client != NULL); 171 GNUNET_assert (client != NULL);
168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "V6 client connected\n"); 172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "V6 client connected\n");
@@ -172,6 +176,7 @@ ready6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
172 &build_msg, NULL); 176 &build_msg, NULL);
173} 177}
174 178
179
175static void 180static void
176runner6 (void *cls, struct GNUNET_SERVER_Handle *server, 181runner6 (void *cls, struct GNUNET_SERVER_Handle *server,
177 const struct GNUNET_CONFIGURATION_Handle *cfg) 182 const struct GNUNET_CONFIGURATION_Handle *cfg)
@@ -182,6 +187,7 @@ runner6 (void *cls, struct GNUNET_SERVER_Handle *server,
182 &ready6, (void *) cfg); 187 &ready6, (void *) cfg);
183} 188}
184 189
190
185/** 191/**
186 * Main method, starts scheduler with task1, 192 * Main method, starts scheduler with task1,
187 * checks that "ok" is correct at the end. 193 * checks that "ok" is correct at the end.
@@ -205,7 +211,6 @@ check6 ()
205} 211}
206 212
207 213
208
209static void 214static void
210start_stop_main (void *cls, char *const *args, const char *cfgfile, 215start_stop_main (void *cls, char *const *args, const char *cfgfile,
211 const struct GNUNET_CONFIGURATION_Handle *cfg) 216 const struct GNUNET_CONFIGURATION_Handle *cfg)