request management
[oweals/gnunet.git] / src / experimentation / gnunet-daemon-experimentation.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 Christian Grothoff (and other contributing authors)
4
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
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file experimentation/gnunet-daemon-experimentation.c
23  * @brief experimentation daemon
24  * @author Christian Grothoff
25  * @author Matthias Wachs
26  */
27 #include "platform.h"
28 #include "gnunet_getopt_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_program_lib.h"
31 #include "gnunet_core_service.h"
32
33 #define EXP_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
34
35 static struct GNUNET_CORE_Handle *ch;
36
37 static struct GNUNET_PeerIdentity me;
38
39 /**
40  * A experimentation node
41  */
42 struct Node
43 {
44         struct GNUNET_PeerIdentity id;
45
46         GNUNET_SCHEDULER_TaskIdentifier timeout_task;
47 };
48
49 /**
50  * Nodes with a pending request
51  */
52
53 struct GNUNET_CONTAINER_MultiHashMap *nodes_requested;
54
55 /**
56  * Active experimentation nodes
57  */
58 struct GNUNET_CONTAINER_MultiHashMap *nodes_active;
59
60 /**
61  * Inactive experimentation nodes
62  * To be excluded from future requests
63  */
64 struct GNUNET_CONTAINER_MultiHashMap *nodes_inactive;
65
66
67 static int
68 cleanup_nodes (void *cls,
69                                                          const struct GNUNET_HashCode * key,
70                                                          void *value)
71 {
72         struct Node *n;
73         struct GNUNET_CONTAINER_MultiHashMap *cur = cls;
74
75         n = value;
76         if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
77         {
78                 GNUNET_SCHEDULER_cancel (n->timeout_task);
79                 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
80         }
81
82         GNUNET_CONTAINER_multihashmap_remove (cur, key, value);
83         GNUNET_free (value);
84         return GNUNET_OK;
85 }
86
87 /**
88  * Task run during shutdown.
89  *
90  * @param cls unused
91  * @param tc unused
92  */
93 static void
94 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
95 {
96   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Experimentation daemon shutting down ...\n"));
97   if (NULL != ch)
98   {
99                 GNUNET_CORE_disconnect (ch);
100                 ch = NULL;
101   }
102
103   if (NULL != nodes_requested)
104   {
105                 GNUNET_CONTAINER_multihashmap_iterate (nodes_requested,
106                                                                                                                                                                          &cleanup_nodes,
107                                                                                                                                                                          nodes_requested);
108                 GNUNET_CONTAINER_multihashmap_destroy (nodes_requested);
109                 nodes_requested = NULL;
110   }
111
112   if (NULL != nodes_active)
113   {
114                 GNUNET_CONTAINER_multihashmap_iterate (nodes_active,
115                                                                                                                                                                          &cleanup_nodes,
116                                                                                                                                                                          nodes_active);
117                 GNUNET_CONTAINER_multihashmap_destroy (nodes_active);
118                 nodes_active = NULL;
119   }
120
121   if (NULL != nodes_inactive)
122   {
123                 GNUNET_CONTAINER_multihashmap_iterate (nodes_inactive,
124                                                                                                                                                                          &cleanup_nodes,
125                                                                                                                                                                          nodes_inactive);
126                 GNUNET_CONTAINER_multihashmap_destroy (nodes_inactive);
127                 nodes_inactive = NULL;
128   }
129 }
130
131 static int is_me (const struct GNUNET_PeerIdentity *id)
132 {
133         if (0 == memcmp (&me, id, sizeof (me)))
134                 return GNUNET_YES;
135         else
136                 return GNUNET_NO;
137 }
138
139 static void
140 core_startup_handler (void *cls,
141                                                                                         struct GNUNET_CORE_Handle * server,
142                       const struct GNUNET_PeerIdentity *my_identity)
143 {
144         me = *my_identity;
145 }
146
147 static void
148 remove_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
149 {
150         struct Node *n = cls;
151
152         if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (nodes_requested, &n->id.hashPubKey))
153                         GNUNET_break (0);
154         else
155         {
156                         GNUNET_CONTAINER_multihashmap_remove (nodes_requested, &n->id.hashPubKey, n);
157                         GNUNET_CONTAINER_multihashmap_put (nodes_inactive, &n->id.hashPubKey, n,
158                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
159                         n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
160         }
161 }
162
163
164 /**
165  * Method called whenever a given peer connects.
166  *
167  * @param cls closure
168  * @param peer peer identity this notification is about
169  */
170 void core_connect_handler (void *cls,
171                            const struct GNUNET_PeerIdentity * peer)
172 {
173         struct Node *n;
174
175         if (GNUNET_YES == is_me(peer))
176                 return;
177
178         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connected to peer %s\n"),
179                         GNUNET_i2s (peer));
180
181         if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (nodes_requested, &peer->hashPubKey))
182                 return; /* We already sent a request */
183
184         if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (nodes_active, &peer->hashPubKey))
185                 return; /*This peer is known as active  */
186
187         if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (nodes_inactive, &peer->hashPubKey))
188                 return; /*This peer is known as inactive  */
189
190         /* Send request */
191         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Sending request to peer %s\n"),
192                         GNUNET_i2s (peer));
193
194         n = GNUNET_malloc (sizeof (struct Node));
195         n->id = *peer;
196         n->timeout_task = GNUNET_SCHEDULER_add_delayed (EXP_RESPONSE_TIMEOUT, &remove_request, n);
197
198         GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (nodes_requested,
199                         &peer->hashPubKey, n, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
200
201
202
203 }
204
205
206 /**
207  * Method called whenever a given peer disconnects.
208  *
209  * @param cls closure
210  * @param peer peer identity this notification is about
211  */
212 void core_disconnect_handler (void *cls,
213                            const struct GNUNET_PeerIdentity * peer)
214 {
215         if (GNUNET_YES == is_me(peer))
216                 return;
217
218         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Disconnected from peer %s\n"),
219                         GNUNET_i2s (peer));
220
221 }
222
223 /**
224  * The main function for the experimentation daemon.
225  *
226  * @param argc number of arguments from the command line
227  * @param argv command line arguments
228  */
229 static void
230 run (void *cls, char *const *args, const char *cfgfile,
231      const struct GNUNET_CONFIGURATION_Handle *cfg)
232 {
233         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Experimentation daemon starting ...\n"));
234
235         nodes_requested = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
236         nodes_active = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
237         nodes_inactive = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
238
239         /* Connecting to core service to find partners */
240         ch = GNUNET_CORE_connect (cfg, NULL,
241                                                                                                                 &core_startup_handler,
242                                                                                                                 &core_connect_handler,
243                                                                                                                 &core_disconnect_handler,
244                                                                                                                 NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
245         if (NULL == ch)
246         {
247                         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Failed to connect to CORE service!\n"));
248                         return;
249         }
250
251   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
252                                 NULL);
253
254 }
255
256
257 /**
258  * The main function for the experimentation daemon.
259  *
260  * @param argc number of arguments from the command line
261  * @param argv command line arguments
262  * @return 0 ok, 1 on error
263  */
264 int
265 main (int argc, char *const *argv)
266 {
267   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
268     GNUNET_GETOPT_OPTION_END
269   };
270
271   return (GNUNET_OK ==
272           GNUNET_PROGRAM_run (argc, argv, "experimentation",
273                                                                                         _("GNUnet hostlist server and client"), options,
274                               &run, NULL)) ? 0 : 1;
275 }
276
277 /* end of gnunet-daemon-experimentation.c */