14efa17082531543514440bca234b50759a8bfcd
[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 #define ADD_PEER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
34
35
36 struct CAFContext
37 {
38   struct GNUNET_CLIENT_Connection *client;
39   struct GNUNET_MessageHeader *msg;
40 };
41
42
43 static size_t
44 copy_and_free (void *cls, size_t size, void *buf)
45 {
46   struct CAFContext *cc = cls;
47   struct GNUNET_MessageHeader *msg = cc->msg;
48   uint16_t msize;
49
50   if (buf == NULL)
51     {
52       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
53                   _
54                   ("Failed to transmit message of type %u to `%s' service.\n"),
55                   ntohs (msg->type), "peerinfo");
56       GNUNET_free (msg);
57       GNUNET_CLIENT_disconnect (cc->client);
58       GNUNET_free (cc);
59       return 0;
60     }
61   msize = ntohs (msg->size);
62   GNUNET_assert (size >= msize);
63   memcpy (buf, msg, msize);
64   GNUNET_free (msg);
65   GNUNET_CLIENT_disconnect (cc->client);
66   GNUNET_free (cc);
67   return msize;
68 }
69
70
71
72 /**
73  * Add a host to the persistent list.
74  *
75  * @param cfg configuration to use
76  * @param sched scheduler to use
77  * @param peer identity of the peer
78  * @param hello the verified (!) HELLO message
79  */
80 void
81 GNUNET_PEERINFO_add_peer (const struct GNUNET_CONFIGURATION_Handle *cfg,
82                           struct GNUNET_SCHEDULER_Handle *sched,
83                           const struct GNUNET_PeerIdentity *peer,
84                           const struct GNUNET_HELLO_Message *hello)
85 {
86   struct GNUNET_CLIENT_Connection *client;
87   struct PeerAddMessage *pam;
88   uint16_t hs;
89   struct CAFContext *cc;
90
91   client = GNUNET_CLIENT_connect (sched, "peerinfo", cfg);
92   if (client == NULL)
93     {
94       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
95                   _("Could not connect to `%s' service.\n"), "peerinfo");
96       return;
97     }
98   hs = GNUNET_HELLO_size (hello);
99   pam = GNUNET_malloc (sizeof (struct PeerAddMessage) + hs);
100   pam->header.size = htons (hs + sizeof (struct PeerAddMessage));
101   pam->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_ADD);
102   memcpy (&pam->peer, peer, sizeof (struct GNUNET_PeerIdentity));
103   memcpy (&pam[1], hello, hs);
104   cc = GNUNET_malloc (sizeof (struct CAFContext));
105   cc->client = client;
106   cc->msg = &pam->header;
107   GNUNET_CLIENT_notify_transmit_ready (client,
108                                        ntohs (pam->header.size),
109                                        ADD_PEER_TIMEOUT, &copy_and_free, cc);
110 }
111
112
113 /**
114  * Context for the info handler.
115  */
116 struct InfoContext
117 {
118
119   /**
120    * Our connection to the PEERINFO service.
121    */
122   struct GNUNET_CLIENT_Connection *client;
123
124   /**
125    * Function to call with information.
126    */
127   GNUNET_PEERINFO_Processor callback;
128
129   /**
130    * Closure for callback.
131    */
132   void *callback_cls;
133
134   /**
135    * When should we time out?
136    */
137   struct GNUNET_TIME_Absolute timeout;
138
139 };
140
141
142 /**
143  * Type of a function to call when we receive a message
144  * from the service.
145  *
146  * @param cls closure
147  * @param msg message received, NULL on timeout or fatal error
148  */
149 static void
150 info_handler (void *cls, const struct GNUNET_MessageHeader *msg)
151 {
152   struct InfoContext *ic = cls;
153   const struct InfoMessage *im;
154   const struct GNUNET_HELLO_Message *hello;
155   uint16_t ms;
156
157   if (msg == NULL)
158     {
159       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
160                   _("Failed to receive response from `%s' service.\n"),
161                   "peerinfo");
162       ic->callback (ic->callback_cls, NULL, NULL, 1);
163       GNUNET_CLIENT_disconnect (ic->client);
164       GNUNET_free (ic);
165       return;
166     }
167   if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END)
168     {
169       ic->callback (ic->callback_cls, NULL, NULL, 0);
170       GNUNET_CLIENT_disconnect (ic->client);
171       GNUNET_free (ic);
172       return;
173     }
174   ms = ntohs (msg->size);
175   if ((ms < sizeof (struct InfoMessage)) ||
176       (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO))
177     {
178       GNUNET_break (0);
179       ic->callback (ic->callback_cls, NULL, NULL, 2);
180       GNUNET_CLIENT_disconnect (ic->client);
181       GNUNET_free (ic);
182       return;
183     }
184   im = (const struct InfoMessage *) msg;
185   hello = NULL;
186   if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader))
187     {
188       hello = (const struct GNUNET_HELLO_Message *) &im[1];
189       if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello))
190         {
191           GNUNET_break (0);
192           ic->callback (ic->callback_cls, NULL, NULL, 2);
193           GNUNET_CLIENT_disconnect (ic->client);
194           GNUNET_free (ic);
195           return;
196         }
197     }
198   ic->callback (ic->callback_cls, &im->peer, hello, ntohl (im->trust));
199   GNUNET_CLIENT_receive (ic->client,
200                          &info_handler,
201                          ic,
202                          GNUNET_TIME_absolute_get_remaining (ic->timeout));
203 }
204
205
206 static size_t
207 copy_then_receive (void *cls, size_t size, void *buf)
208 {
209   struct InfoContext *ic = cls;
210   const struct GNUNET_MessageHeader *msg =
211     (const struct GNUNET_MessageHeader *) &ic[1];
212   uint16_t msize;
213
214   if (buf == NULL)
215     {
216       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
217                   _
218                   ("Failed to transmit message of type %u to `%s' service.\n"),
219                   ntohs (msg->type), "peerinfo");
220       ic->callback (ic->callback_cls, NULL, NULL, 1);
221       GNUNET_CLIENT_disconnect (ic->client);
222       GNUNET_free (ic);
223       return 0;
224     }
225   msize = ntohs (msg->size);
226   GNUNET_assert (size >= msize);
227   memcpy (buf, msg, msize);
228   GNUNET_CLIENT_receive (ic->client,
229                          &info_handler,
230                          ic,
231                          GNUNET_TIME_absolute_get_remaining (ic->timeout));
232   return msize;
233 }
234
235
236 /**
237  * Call a method for each known matching host and change
238  * its trust value.  The method will be invoked once for
239  * each host and then finally once with a NULL pointer.
240  * Note that the last call can be triggered by timeout or
241  * by simply being done; however, the trust argument will
242  * be set to zero if we are done and to 1 if we timed out.
243  *
244  * @param cfg configuration to use
245  * @param sched scheduler to use
246  * @param peer restrict iteration to this peer only (can be NULL)
247  * @param trust_delta how much to change the trust in all matching peers
248  * @param timeout how long to wait until timing out
249  * @param callback the method to call for each peer
250  * @param callback_cls closure for callback
251  */
252 void
253 GNUNET_PEERINFO_for_all (const struct GNUNET_CONFIGURATION_Handle *cfg,
254                          struct GNUNET_SCHEDULER_Handle *sched,
255                          const struct GNUNET_PeerIdentity *peer,
256                          int trust_delta,
257                          struct GNUNET_TIME_Relative timeout,
258                          GNUNET_PEERINFO_Processor callback,
259                          void *callback_cls)
260 {
261   struct GNUNET_CLIENT_Connection *client;
262   struct ListAllPeersMessage *lapm;
263   struct ListPeerMessage *lpm;
264   struct InfoContext *ihc;
265   size_t hs;
266
267   client = GNUNET_CLIENT_connect (sched, "peerinfo", cfg);
268   if (client == NULL)
269     {
270       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
271                   _("Could not connect to `%s' service.\n"), "peerinfo");
272       callback (callback_cls, NULL, NULL, 2);
273       return;
274     }
275   ihc = GNUNET_malloc (sizeof (struct InfoContext) +
276                        sizeof (struct ListPeerMessage));
277   ihc->client = client;
278   ihc->callback = callback;
279   ihc->callback_cls = callback_cls;
280   ihc->timeout = GNUNET_TIME_relative_to_absolute (timeout);
281   if (peer == NULL)
282     {
283       lapm = (struct ListAllPeersMessage *) &ihc[1];
284       lapm->header.size = htons (hs = sizeof (struct ListAllPeersMessage));
285       lapm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
286       lapm->trust_change = htonl (trust_delta);
287     }
288   else
289     {
290       lpm = (struct ListPeerMessage *) &ihc[1];
291       lpm->header.size = htons (hs = sizeof (struct ListPeerMessage));
292       lpm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET);
293       lpm->trust_change = htonl (trust_delta);
294       memcpy (&lpm->peer, peer, sizeof (struct GNUNET_PeerIdentity));
295     }
296   GNUNET_CLIENT_notify_transmit_ready (client,
297                                        hs, timeout, &copy_then_receive, ihc);
298 }
299
300 /* end of peerinfo_api.c */