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