-remove debug message
[oweals/gnunet.git] / src / peerinfo / peerinfo_api_notify.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file peerinfo/peerinfo_api_notify.c
23  * @brief notify API to access peerinfo service
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_peerinfo_service.h"
29 #include "gnunet_protocols.h"
30 #include "peerinfo.h"
31
32 #define LOG(kind, ...) GNUNET_log_from (kind, "peerinfo-api", __VA_ARGS__)
33
34 /**
35  * Context for the info handler.
36  */
37 struct GNUNET_PEERINFO_NotifyContext
38 {
39   /**
40    * Our connection to the PEERINFO service.
41    */
42   struct GNUNET_MQ_Handle *mq;
43
44   /**
45    * Function to call with information.
46    */
47   GNUNET_PEERINFO_Processor callback;
48
49   /**
50    * Closure for @e callback.
51    */
52   void *callback_cls;
53
54   /**
55    * Configuration.
56    */
57   const struct GNUNET_CONFIGURATION_Handle *cfg;
58
59   /**
60    * Tasked used for delayed re-connection attempt.
61    */
62   struct GNUNET_SCHEDULER_Task *task;
63
64   /**
65    * Include friend only HELLOs in callbacks
66    */
67   int include_friend_only;
68 };
69
70
71 /**
72  * Task to re-try connecting to peerinfo.
73  *
74  * @param cls the `struct GNUNET_PEERINFO_NotifyContext *`
75  */
76 static void
77 reconnect (void *cls);
78
79
80 /**
81  * We encountered an error, reconnect to the service.
82  *
83  * @param nc context to reconnect
84  */
85 static void
86 do_reconnect (struct GNUNET_PEERINFO_NotifyContext *nc)
87 {
88   GNUNET_MQ_destroy (nc->mq);
89   nc->mq = NULL;
90   nc->task = GNUNET_SCHEDULER_add_now (&reconnect,
91                                        nc);
92 }
93
94
95 /**
96  * We got a disconnect after asking regex to do the announcement.
97  * Retry.
98  *
99  * @param cls the `struct GNUNET_PEERINFO_NotifyContext` to retry
100  * @param error error code
101  */
102 static void
103 mq_error_handler (void *cls,
104                   enum GNUNET_MQ_Error error)
105 {
106   struct GNUNET_PEERINFO_NotifyContext *nc = cls;
107
108   do_reconnect (nc);
109 }
110
111
112 /**
113  * Check that a peerinfo information message is well-formed.
114  *
115  * @param cls closure
116  * @param im message received
117  * @return #GNUNET_OK if the message is well-formed
118  */
119 static int
120 check_notification (void *cls,
121                     const struct InfoMessage *im)
122 {
123   uint16_t ms = ntohs (im->header.size) - sizeof(*im);
124
125   if (ms >= sizeof(struct GNUNET_MessageHeader))
126   {
127     const struct GNUNET_HELLO_Message *hello;
128
129     hello = (const struct GNUNET_HELLO_Message *) &im[1];
130     if (ms != GNUNET_HELLO_size (hello))
131     {
132       GNUNET_break (0);
133       return GNUNET_SYSERR;
134     }
135     return GNUNET_OK;
136   }
137   if (0 != ms)
138   {
139     GNUNET_break (0);
140     return GNUNET_SYSERR;
141   }
142   return GNUNET_OK;  /* odd... */
143 }
144
145
146 /**
147  * Receive a peerinfo information message, process it.
148  *
149  * @param cls closure
150  * @param im message received
151  */
152 static void
153 handle_notification (void *cls,
154                      const struct InfoMessage *im)
155 {
156   struct GNUNET_PEERINFO_NotifyContext *nc = cls;
157   const struct GNUNET_HELLO_Message *hello;
158   uint16_t ms = ntohs (im->header.size) - sizeof(struct InfoMessage);
159
160   if (0 == ms)
161     return;
162   hello = (const struct GNUNET_HELLO_Message *) &im[1];
163   LOG (GNUNET_ERROR_TYPE_DEBUG,
164        "Received information about peer `%s' from peerinfo database\n",
165        GNUNET_i2s (&im->peer));
166   nc->callback (nc->callback_cls,
167                 &im->peer,
168                 hello,
169                 NULL);
170 }
171
172
173 /**
174  * Type of a function to call when we receive a message from the
175  * service.  Call the iterator with the result and (if applicable)
176  * continue to receive more messages or trigger processing the next
177  * event (if applicable).
178  *
179  * @param cls closure
180  * @param msg message received, NULL on timeout or fatal error
181  */
182 static void
183 handle_end_iteration (void *cls,
184                       const struct GNUNET_MessageHeader *msg)
185 {
186   /* these are ignored by the notify API */
187 }
188
189
190 /**
191  * Task to re-try connecting to peerinfo.
192  *
193  * @param cls the `struct GNUNET_PEERINFO_NotifyContext *`
194  */
195 static void
196 reconnect (void *cls)
197 {
198   struct GNUNET_PEERINFO_NotifyContext *nc = cls;
199   struct GNUNET_MQ_MessageHandler handlers[] = {
200     GNUNET_MQ_hd_var_size (notification,
201                            GNUNET_MESSAGE_TYPE_PEERINFO_INFO,
202                            struct InfoMessage,
203                            nc),
204     GNUNET_MQ_hd_fixed_size (end_iteration,
205                              GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END,
206                              struct GNUNET_MessageHeader,
207                              nc),
208     GNUNET_MQ_handler_end ()
209   };
210   struct GNUNET_MQ_Envelope *env;
211   struct NotifyMessage *nm;
212
213   nc->task = NULL;
214   nc->mq = GNUNET_CLIENT_connect (nc->cfg,
215                                   "peerinfo",
216                                   handlers,
217                                   &mq_error_handler,
218                                   nc);
219   if (NULL == nc->mq)
220     return;
221   env = GNUNET_MQ_msg (nm,
222                        GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY);
223   nm->include_friend_only = htonl (nc->include_friend_only);
224   GNUNET_MQ_send (nc->mq,
225                   env);
226 }
227
228
229 /**
230  * Call a method whenever our known information about peers
231  * changes.  Initially calls the given function for all known
232  * peers and then only signals changes.
233  *
234  * If @a include_friend_only is set to #GNUNET_YES peerinfo will include HELLO
235  * messages which are intended for friend to friend mode and which do not
236  * have to be gossiped. Otherwise these messages are skipped.
237  *
238  * @param cfg configuration to use
239  * @param include_friend_only include HELLO messages for friends only
240  * @param callback the method to call for each peer
241  * @param callback_cls closure for @a callback
242  * @return NULL on error
243  */
244 struct GNUNET_PEERINFO_NotifyContext *
245 GNUNET_PEERINFO_notify (const struct GNUNET_CONFIGURATION_Handle *cfg,
246                         int include_friend_only,
247                         GNUNET_PEERINFO_Processor callback,
248                         void *callback_cls)
249 {
250   struct GNUNET_PEERINFO_NotifyContext *nc;
251
252   nc = GNUNET_new (struct GNUNET_PEERINFO_NotifyContext);
253   nc->cfg = cfg;
254   nc->callback = callback;
255   nc->callback_cls = callback_cls;
256   nc->include_friend_only = include_friend_only;
257   reconnect (nc);
258   if (NULL == nc->mq)
259   {
260     LOG (GNUNET_ERROR_TYPE_WARNING,
261          "Could not connect to PEERINFO service.\n");
262     GNUNET_free (nc);
263     return NULL;
264   }
265   return nc;
266 }
267
268
269 /**
270  * Stop notifying about changes.
271  *
272  * @param nc context to stop notifying
273  */
274 void
275 GNUNET_PEERINFO_notify_cancel (struct GNUNET_PEERINFO_NotifyContext *nc)
276 {
277   if (NULL != nc->mq)
278   {
279     GNUNET_MQ_destroy (nc->mq);
280     nc->mq = NULL;
281   }
282   if (NULL != nc->task)
283   {
284     GNUNET_SCHEDULER_cancel (nc->task);
285     nc->task = NULL;
286   }
287   GNUNET_free (nc);
288 }
289
290
291 /* end of peerinfo_api_notify.c */