skel
[oweals/gnunet.git] / src / peerinfo / peerinfo_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001, 2002, 2004, 2005, 2007, 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 2, 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 peerinfo/peerinfo_api.c
23  * @brief API to access peerinfo service
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_client_lib.h"
28 #include "gnunet_peerinfo_service.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_time_lib.h"
31 #include "peerinfo.h"
32
33
34
35 /**
36  * Handle to the peerinfo service.
37  */
38 struct GNUNET_PEERINFO_Handle
39 {
40 };
41
42
43 /**
44  * Connect to the peerinfo service.
45  *
46  * @param cfg configuration to use
47  * @param sched scheduler to use
48  * @return NULL on error (configuration related, actual connection
49  *         etablishment may happen asynchronously).
50  */
51 struct GNUNET_PEERINFO_Handle *
52 GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
53                          struct GNUNET_SCHEDULER_Handle *sched)
54 {
55   return NULL;
56 }
57
58
59 /**
60  * Disconnect from the peerinfo service.  Note that all iterators must
61  * have completed or have been cancelled by the time this function is
62  * called (otherwise, calling this function is a serious error).
63  * Furthermore, if 'GNUNET_PEERINFO_add_peer' operations are still
64  * pending, they will be cancelled silently on disconnect.
65  *
66  * @param h handle to disconnect
67  */
68 void
69 GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h)
70 {
71 }
72
73
74
75
76
77
78 /**
79  * Add a host to the persistent list.  This method operates in 
80  * semi-reliable mode: if the transmission is not completed by
81  * the time 'GNUNET_PEERINFO_disconnect' is called, it will be
82  * aborted.  Furthermore, if a second HELLO is added for the
83  * same peer before the first one was transmitted, PEERINFO may
84  * merge the two HELLOs prior to transmission to the service.
85  *
86  * @param h handle to the peerinfo service
87  * @param peer identity of the peer
88  * @param hello the verified (!) HELLO message
89  */
90 void
91 GNUNET_PEERINFO_add_peer_new (struct GNUNET_PEERINFO_Handle *h,
92                               const struct GNUNET_PeerIdentity *peer,
93                               const struct GNUNET_HELLO_Message *hello)
94 {
95 }
96
97
98 struct GNUNET_PEERINFO_NewIteratorContext
99 {
100 };
101
102
103 /**
104  * Call a method for each known matching host and change its trust
105  * value.  The callback method will be invoked once for each matching
106  * host and then finally once with a NULL pointer.  After that final
107  * invocation, the iterator context must no longer be used.
108  *
109  * Note that the last call can be triggered by timeout or by simply
110  * being done; however, the trust argument will be set to zero if we
111  * are done, 1 if we timed out and 2 for fatal error.
112  *
113  * Instead of calling this function with 'peer == NULL' and 'trust ==
114  * 0', it is often better to use 'GNUNET_PEERINFO_notify'.
115  * 
116  * @param h handle to the peerinfo service
117  * @param peer restrict iteration to this peer only (can be NULL)
118  * @param trust_delta how much to change the trust in all matching peers
119  * @param timeout how long to wait until timing out
120  * @param callback the method to call for each peer
121  * @param callback_cls closure for callback
122  * @return NULL on error (in this case, 'callback' is never called!), 
123  *         otherwise an iterator context
124  */
125 struct GNUNET_PEERINFO_NewIteratorContext *
126 GNUNET_PEERINFO_iterate_new (struct GNUNET_PEERINFO_Handle *h,
127                              const struct GNUNET_PeerIdentity *peer,
128                              int trust_delta,
129                              struct GNUNET_TIME_Relative timeout,
130                              GNUNET_PEERINFO_Processor callback,
131                              void *callback_cls)
132 {
133   return NULL;
134 }
135
136
137
138 /**
139  * Cancel an iteration over peer information.
140  *
141  * @param ic context of the iterator to cancel
142  */
143 void
144 GNUNET_PEERINFO_iterate_cancel_new (struct GNUNET_PEERINFO_NewIteratorContext *ic)
145 {
146 }
147
148
149
150
151
152 /* ***************************** OLD API ****************************** */
153
154
155
156
157 #define ADD_PEER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
158
159
160 struct CAFContext
161 {
162   struct GNUNET_CLIENT_Connection *client;
163   struct GNUNET_MessageHeader *msg;
164 };
165
166
167 static size_t
168 copy_and_free (void *cls, size_t size, void *buf)
169 {
170   struct CAFContext *cc = cls;
171   struct GNUNET_MessageHeader *msg = cc->msg;
172   uint16_t msize;
173
174   if (buf == NULL)
175     {
176 #if DEBUG_PEERINFO
177       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178                   _
179                   ("Failed to transmit message of type %u to `%s' service.\n"),
180                   ntohs (msg->type), "peerinfo");
181 #endif
182       GNUNET_free (msg);
183       GNUNET_CLIENT_disconnect (cc->client, GNUNET_NO);
184       GNUNET_free (cc);
185       return 0;
186     }
187   msize = ntohs (msg->size);
188   GNUNET_assert (size >= msize);
189   memcpy (buf, msg, msize);
190   GNUNET_free (msg);
191   GNUNET_CLIENT_disconnect (cc->client, GNUNET_YES);
192   GNUNET_free (cc);
193   return msize;
194 }
195
196
197
198 /**
199  * Add a host to the persistent list.
200  *
201  * @param cfg configuration to use
202  * @param sched scheduler to use
203  * @param peer identity of the peer
204  * @param hello the verified (!) HELLO message
205  */
206 void
207 GNUNET_PEERINFO_add_peer (const struct GNUNET_CONFIGURATION_Handle *cfg,
208                           struct GNUNET_SCHEDULER_Handle *sched,
209                           const struct GNUNET_PeerIdentity *peer,
210                           const struct GNUNET_HELLO_Message *hello)
211 {
212   struct GNUNET_CLIENT_Connection *client;
213   struct PeerAddMessage *pam;
214   uint16_t hs;
215   struct CAFContext *cc;
216
217 #if DEBUG_PEERINFO
218   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
219               "Adding peer `%s' to peerinfo database\n",
220               GNUNET_i2s(peer));
221 #endif
222   client = GNUNET_CLIENT_connect (sched, "peerinfo", cfg);
223   if (client == NULL)
224     {
225       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
226                   _("Could not connect to `%s' service.\n"), "peerinfo");
227       return;
228     }
229   hs = GNUNET_HELLO_size (hello);
230 #if DEBUG_PEERINFO
231   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
232               "Size of `%s' is %u bytes\n",
233               "HELLO",
234               (unsigned int) GNUNET_HELLO_size (hello));
235 #endif  
236   pam = GNUNET_malloc (sizeof (struct PeerAddMessage) + hs);
237   pam->header.size = htons (hs + sizeof (struct PeerAddMessage));
238   pam->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_ADD);
239   memcpy (&pam->peer, peer, sizeof (struct GNUNET_PeerIdentity));
240   memcpy (&pam[1], hello, hs);
241   cc = GNUNET_malloc (sizeof (struct CAFContext));
242   cc->client = client;
243   cc->msg = &pam->header;
244   GNUNET_CLIENT_notify_transmit_ready (client,
245                                        ntohs (pam->header.size),
246                                        ADD_PEER_TIMEOUT, 
247                                        GNUNET_NO,
248                                        &copy_and_free, cc);
249 }
250
251
252 /**
253  * Context for the info handler.
254  */
255 struct GNUNET_PEERINFO_IteratorContext
256 {
257
258   /**
259    * Our connection to the PEERINFO service.
260    */
261   struct GNUNET_CLIENT_Connection *client;
262
263   /**
264    * Function to call with information.
265    */
266   GNUNET_PEERINFO_Processor callback;
267
268   /**
269    * Closure for callback.
270    */
271   void *callback_cls;
272
273   /**
274    * When should we time out?
275    */
276   struct GNUNET_TIME_Absolute timeout;
277
278 };
279
280
281 /**
282  * Type of a function to call when we receive a message
283  * from the service.
284  *
285  * @param cls closure
286  * @param msg message received, NULL on timeout or fatal error
287  */
288 static void
289 info_handler (void *cls, const struct GNUNET_MessageHeader *msg)
290 {
291   struct GNUNET_PEERINFO_IteratorContext *ic = cls;
292   const struct InfoMessage *im;
293   const struct GNUNET_HELLO_Message *hello;
294   uint16_t ms;
295
296   if (msg == NULL)
297     {
298       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
299                   _("Failed to receive response from `%s' service.\n"),
300                   "peerinfo");
301       ic->callback (ic->callback_cls, NULL, NULL, 1);
302       GNUNET_CLIENT_disconnect (ic->client, GNUNET_NO);
303       GNUNET_free (ic);
304       return;
305     }
306   if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END)
307     {
308 #if DEBUG_PEERINFO
309       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310                   "Received end of list of peers from peerinfo database\n");
311 #endif
312       ic->callback (ic->callback_cls, NULL, NULL, 0);
313       GNUNET_CLIENT_disconnect (ic->client, GNUNET_NO);
314       GNUNET_free (ic);
315       return;
316     }
317   ms = ntohs (msg->size);
318   if ((ms < sizeof (struct InfoMessage)) ||
319       (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO))
320     {
321       GNUNET_break (0);
322       ic->callback (ic->callback_cls, NULL, NULL, 2);
323       GNUNET_CLIENT_disconnect (ic->client, GNUNET_NO);
324       GNUNET_free (ic);
325       return;
326     }
327   im = (const struct InfoMessage *) msg;
328   hello = NULL;
329   if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader))
330     {
331       hello = (const struct GNUNET_HELLO_Message *) &im[1];
332       if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello))
333         {
334           GNUNET_break (0);
335           ic->callback (ic->callback_cls, NULL, NULL, 2);
336           GNUNET_CLIENT_disconnect (ic->client, GNUNET_NO);
337           GNUNET_free (ic);
338           return;
339         }
340     }
341 #if DEBUG_PEERINFO
342   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343               "Received %u bytes of `%s' information about peer `%s' from PEERINFO database\n",
344               (hello == NULL) ? 0 : (unsigned int) GNUNET_HELLO_size (hello),
345               "HELLO",
346               GNUNET_i2s (&im->peer));
347 #endif
348   ic->callback (ic->callback_cls, &im->peer, hello, ntohl (im->trust));
349   GNUNET_CLIENT_receive (ic->client,
350                          &info_handler,
351                          ic,
352                          GNUNET_TIME_absolute_get_remaining (ic->timeout));
353 }
354
355
356 /**
357  * Call a method for each known matching host and change
358  * its trust value.  The method will be invoked once for
359  * each host and then finally once with a NULL pointer.
360  * Note that the last call can be triggered by timeout or
361  * by simply being done; however, the trust argument will
362  * be set to zero if we are done and to 1 if we timed out.
363  *
364  * @param cfg configuration to use
365  * @param sched scheduler to use
366  * @param peer restrict iteration to this peer only (can be NULL)
367  * @param trust_delta how much to change the trust in all matching peers
368  * @param timeout how long to wait until timing out
369  * @param callback the method to call for each peer
370  * @param callback_cls closure for callback
371  * @return NULL on error, otherwise an iterator context
372  */
373 struct GNUNET_PEERINFO_IteratorContext *
374 GNUNET_PEERINFO_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
375                          struct GNUNET_SCHEDULER_Handle *sched,
376                          const struct GNUNET_PeerIdentity *peer,
377                          int trust_delta,
378                          struct GNUNET_TIME_Relative timeout,
379                          GNUNET_PEERINFO_Processor callback,
380                          void *callback_cls)
381 {
382   struct GNUNET_CLIENT_Connection *client;
383   struct ListAllPeersMessage *lapm;
384   struct ListPeerMessage *lpm;
385   struct GNUNET_PEERINFO_IteratorContext *ihc;
386
387   client = GNUNET_CLIENT_connect (sched, "peerinfo", cfg);
388   if (client == NULL)
389     {
390       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
391                   _("Could not connect to `%s' service.\n"), "peerinfo");
392       return NULL;
393     }
394 #if DEBUG_PEERINFO
395   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
396               "Requesting list of peers from peerinfo database\n");
397 #endif
398   if (peer == NULL)
399     {
400       ihc = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_IteratorContext) +
401                            sizeof (struct ListAllPeersMessage));
402       lapm = (struct ListAllPeersMessage *) &ihc[1];
403       lapm->header.size = htons (sizeof (struct ListAllPeersMessage));
404       lapm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
405       lapm->trust_change = htonl (trust_delta);
406     }
407   else
408     {
409       ihc = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_IteratorContext) +
410                            sizeof (struct ListPeerMessage));
411       lpm = (struct ListPeerMessage *) &ihc[1];
412       lpm->header.size = htons (sizeof (struct ListPeerMessage));
413       lpm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET);
414       lpm->trust_change = htonl (trust_delta);
415       memcpy (&lpm->peer, peer, sizeof (struct GNUNET_PeerIdentity));
416     }
417   ihc->client = client;
418   ihc->callback = callback;
419   ihc->callback_cls = callback_cls;
420   ihc->timeout = GNUNET_TIME_relative_to_absolute (timeout);
421   if (GNUNET_OK != 
422       GNUNET_CLIENT_transmit_and_get_response (client,
423                                                (const struct GNUNET_MessageHeader*) &ihc[1],
424                                                timeout,
425                                                GNUNET_YES,
426                                                &info_handler,
427                                                ihc))
428     {
429       GNUNET_break (0);
430       GNUNET_CLIENT_disconnect (ihc->client, GNUNET_NO);
431       GNUNET_free (ihc);
432       return NULL;
433     }
434   return ihc;
435 }
436
437
438 /**
439  * Cancel an iteration over peer information.
440  *
441  * @param ic context of the iterator to cancel
442  */
443 void
444 GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic)
445 {
446   GNUNET_CLIENT_disconnect (ic->client, GNUNET_NO);
447   GNUNET_free (ic);
448 }
449
450
451 /* end of peerinfo_api.c */