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