Mark operations as done when they are finished.
[oweals/gnunet.git] / doc / testbed_test.c
1 #include <unistd.h>
2 #include <gnunet/platform.h>
3 #include <gnunet/gnunet_util_lib.h>
4 #include <gnunet/gnunet_testbed_service.h>
5 #include <gnunet/gnunet_dht_service.h>
6
7 /* Number of peers we want to start */
8 #define NUM_PEERS 20
9
10 static struct GNUNET_TESTBED_Operation *dht_op;
11
12 static struct GNUNET_DHT_Handle *dht_handle;
13
14 static GNUNET_SCHEDULER_TaskIdentifier shutdown_tid;
15
16
17 /**
18  * Closure to 'dht_ca' and 'dht_da' DHT adapters.
19  */
20 struct MyContext
21 {
22   /**
23    * Argument we pass to GNUNET_DHT_connect.
24    */
25   int ht_len;
26 } ctxt;
27
28
29 /**
30  * Global result for testcase.
31  */
32 static int result;
33
34
35 /**
36  * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.).
37  * Cleans up.
38  */
39 static void
40 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
41 {
42   shutdown_tid = GNUNET_SCHEDULER_NO_TASK;
43   if (NULL != dht_op)
44   {
45     GNUNET_TESTBED_operation_done (dht_op); /* indirectly calls the dht_da() for closing
46                                                down the connection to the DHT */
47     dht_op = NULL;
48     dht_handle = NULL;
49   }
50   result = GNUNET_OK;
51   GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */
52 }
53
54
55 /**
56  * This is where the test logic should be, at least that
57  * part of it that uses the DHT of peer "0".
58  *
59  * @param cls closure, for the example: NULL
60  * @param op should be equal to "dht_op"
61  * @param ca_result result of the connect operation, the
62  *        connection to the DHT service
63  * @param emsg error message, if testbed somehow failed to
64  *        connect to the DHT.
65  */
66 static void
67 service_connect_comp (void *cls,
68                       struct GNUNET_TESTBED_Operation *op,
69                       void *ca_result,
70                       const char *emsg)
71 {
72   GNUNET_assert (op == dht_op);
73   dht_handle = ca_result;
74   /* Service to DHT successful; here we'd usually do something
75      with the DHT (ok, if successful) */
76
77   /* for now, just indiscriminately terminate after 10s */
78   GNUNET_SCHEDULER_cancel (shutdown_tid);
79   shutdown_tid = GNUNET_SCHEDULER_add_delayed
80       (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
81        &shutdown_task, NULL);
82 }
83
84
85 /**
86  * Testbed has provided us with the configuration to access one
87  * of the peers and it is time to do "some" connect operation to
88  * "some" subsystem of the peer.  For this example, we connect
89  * to the DHT subsystem.  Testbed doesn't know which subsystem,
90  * so we need these adapters to do the actual connecting (and
91  * possibly pass additional options to the subsystem connect
92  * function, such as the "ht_len" argument for the DHT).
93  *
94  * @param cls closure
95  * @param cfg peer configuration (here: peer[0]
96  * @return NULL on error, otherwise some handle to access the
97  *         subsystem
98  */
99 static void *
100 dht_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
101 {
102   struct MyContext *ctxt = cls;
103
104   /* Use the provided configuration to connect to service */
105   dht_handle = GNUNET_DHT_connect (cfg, ctxt->ht_len);
106   return dht_handle;
107 }
108
109
110 /**
111  * Dual of 'dht_ca' to perform the 'disconnect'/cleanup operation
112  * once we no longer need to access this subsystem.
113  *
114  * @param cls closure
115  * @param op_result whatever we returned from 'dht_ca'
116  */
117 static void
118 dht_da (void *cls, void *op_result)
119 {
120   struct MyContext *ctxt = cls;
121
122   /* Disconnect from DHT service */
123   GNUNET_DHT_disconnect ((struct GNUNET_DHT_Handle *) op_result);
124   dht_handle = NULL;
125 }
126
127
128 /**
129  * Main function inovked from TESTBED once all of the
130  * peers are up and running.  This one then connects
131  * just to the DHT service of peer 0.
132  *
133  * @param cls closure
134  * @param h the run handle
135  * @param peers started peers for the test
136  * @param num_peers size of the 'peers' array
137  * @param links_succeeded number of links between peers that were created
138  * @param links_failed number of links testbed was unable to establish
139  */
140 static void
141 test_master (void *cls,
142              struct GNUNET_TESTBED_RunHandle *h,
143              unsigned int num_peers,
144              struct GNUNET_TESTBED_Peer **peers,
145              unsigned int links_succeeded,
146              unsigned int links_failed)
147 {
148   /* Testbed is ready with peers running and connected in a pre-defined overlay
149      topology  */
150
151   /* do something */
152   ctxt.ht_len = 10;
153
154   /* connect to a peers service */
155   dht_op = GNUNET_TESTBED_service_connect
156       (NULL,                    /* Closure for operation */
157        peers[0],                /* The peer whose service to connect to */
158        "dht",                   /* The name of the service */
159        service_connect_comp,    /* callback to call after a handle to service
160                                    is opened */
161        NULL,                    /* closure for the above callback */
162        dht_ca,                  /* callback to call with peer's configuration;
163                                    this should open the needed service connection */
164        dht_da,                  /* callback to be called when closing the
165                                    opened service connection */
166        &ctxt);                  /* closure for the above two callbacks */
167   shutdown_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
168                                                &shutdown_task, NULL);
169 }
170
171
172 int
173 main (int argc, char **argv)
174 {
175   int ret;
176
177   result = GNUNET_SYSERR;
178   ret = GNUNET_TESTBED_test_run
179       ("awesome-test",  /* test case name */
180        "template.conf", /* template configuration */
181        NUM_PEERS,       /* number of peers to start */
182        0LL, /* Event mask - set to 0 for no event notifications */
183        NULL, /* Controller event callback */
184        NULL, /* Closure for controller event callback */
185        &test_master, /* continuation callback to be called when testbed setup is
186                         complete */
187        NULL); /* Closure for the test_master callback */
188   if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
189     return 1;
190   return 0;
191 }