fix div by zero
[oweals/gnunet.git] / src / transport / transport_api_hello_get.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2013, 2016 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
19 /**
20  * @file transport/transport_api_hello_get.c
21  * @brief library to obtain our HELLO from our transport service
22  * @author Christian Grothoff
23  */
24 #include "platform.h"
25 #include "gnunet_util_lib.h"
26 #include "gnunet_constants.h"
27 #include "gnunet_arm_service.h"
28 #include "gnunet_hello_lib.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_transport_hello_service.h"
31 #include "transport.h"
32
33
34 /**
35  * Functions to call with this peer's HELLO.
36  */
37 struct GNUNET_TRANSPORT_HelloGetHandle
38 {
39
40   /**
41    * Our configuration.
42    */
43   const struct GNUNET_CONFIGURATION_Handle *cfg;
44
45   /**
46    * Transport handle.
47    */
48   struct GNUNET_MQ_Handle *mq;
49
50   /**
51    * Callback to call once we got our HELLO.
52    */
53   GNUNET_TRANSPORT_HelloUpdateCallback rec;
54
55   /**
56    * Closure for @e rec.
57    */
58   void *rec_cls;
59
60   /**
61    * Task for calling the HelloUpdateCallback when we already have a HELLO
62    */
63   struct GNUNET_SCHEDULER_Task *notify_task;
64
65   /**
66    * ID of the task trying to reconnect to the service.
67    */
68   struct GNUNET_SCHEDULER_Task *reconnect_task;
69
70   /**
71    * Delay until we try to reconnect.
72    */
73   struct GNUNET_TIME_Relative reconnect_delay;
74
75   /**
76    * Type of HELLOs client cares about.
77    */
78   enum GNUNET_TRANSPORT_AddressClass ac;
79 };
80
81
82 /**
83  * Function we use for checking incoming HELLO messages.
84  *
85  * @param cls closure, a `struct GNUNET_TRANSPORT_Handle *`
86  * @param msg message received
87  * @return #GNUNET_OK if message is well-formed
88  */
89 static int
90 check_hello (void *cls,
91              const struct GNUNET_MessageHeader *msg)
92 {
93   struct GNUNET_PeerIdentity me;
94
95   if (GNUNET_OK !=
96       GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) msg,
97                            &me))
98   {
99     GNUNET_break (0);
100     return GNUNET_SYSERR;
101   }
102   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
103               "Receiving (my own) HELLO message (%u bytes), I am `%s'.\n",
104               (unsigned int) ntohs (msg->size),
105               GNUNET_i2s (&me));
106   return GNUNET_OK;
107 }
108
109
110 /**
111  * Function we use for handling incoming HELLO messages.
112  *
113  * @param cls closure, a `struct GNUNET_TRANSPORT_HelloGetHandle *`
114  * @param msg message received
115  */
116 static void
117 handle_hello (void *cls,
118               const struct GNUNET_MessageHeader *msg)
119 {
120   struct GNUNET_TRANSPORT_HelloGetHandle *ghh = cls;
121
122   ghh->rec (ghh->rec_cls,
123             msg);
124 }
125
126
127 /**
128  * Function that will schedule the job that will try
129  * to connect us again to the client.
130  *
131  * @param ghh transport service to reconnect
132  */
133 static void
134 schedule_reconnect (struct GNUNET_TRANSPORT_HelloGetHandle *ghh);
135
136
137 /**
138  * Generic error handler, called with the appropriate
139  * error code and the same closure specified at the creation of
140  * the message queue.
141  * Not every message queue implementation supports an error handler.
142  *
143  * @param cls closure with the `struct GNUNET_TRANSPORT_Handle *`
144  * @param error error code
145  */
146 static void
147 mq_error_handler (void *cls,
148                   enum GNUNET_MQ_Error error)
149 {
150   struct GNUNET_TRANSPORT_HelloGetHandle *ghh = cls;
151
152   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
153               "Error receiving from transport service, disconnecting temporarily.\n");
154   GNUNET_MQ_destroy (ghh->mq);
155   ghh->mq = NULL;
156   schedule_reconnect (ghh);
157 }
158
159
160 /**
161  * Try again to connect to transport service.
162  *
163  * @param cls the handle to the transport service
164  */
165 static void
166 reconnect (void *cls)
167 {
168   struct GNUNET_TRANSPORT_HelloGetHandle *ghh = cls;
169   struct GNUNET_MQ_MessageHandler handlers[] = {
170     GNUNET_MQ_hd_var_size (hello,
171                            GNUNET_MESSAGE_TYPE_HELLO,
172                            struct GNUNET_MessageHeader,
173                            ghh),
174     GNUNET_MQ_handler_end ()
175   };
176   struct GNUNET_MQ_Envelope *env;
177   struct StartMessage *s;
178
179   ghh->reconnect_task = NULL;
180   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
181               "Connecting to transport service.\n");
182   GNUNET_assert (NULL == ghh->mq);
183   ghh->mq = GNUNET_CLIENT_connect (ghh->cfg,
184                                    "transport",
185                                    handlers,
186                                    &mq_error_handler,
187                                    ghh);
188   if (NULL == ghh->mq)
189     return;
190   env = GNUNET_MQ_msg (s,
191                        GNUNET_MESSAGE_TYPE_TRANSPORT_START);
192   s->options = htonl (0);
193   GNUNET_MQ_send (ghh->mq,
194                   env);
195 }
196
197
198 /**
199  * Function that will schedule the job that will try
200  * to connect us again to the client.
201  *
202  * @param ghh transport service to reconnect
203  */
204 static void
205 schedule_reconnect (struct GNUNET_TRANSPORT_HelloGetHandle *ghh)
206 {
207   ghh->reconnect_task =
208       GNUNET_SCHEDULER_add_delayed (ghh->reconnect_delay,
209                                     &reconnect,
210                                     ghh);
211   ghh->reconnect_delay = GNUNET_TIME_STD_BACKOFF (ghh->reconnect_delay);
212 }
213
214
215 /**
216  * Obtain the HELLO message for this peer.  The callback given in this function
217  * is never called synchronously.
218  *
219  * @param cfg configuration
220  * @param ac which network type should the addresses from the HELLO belong to?
221  * @param rec function to call with the HELLO, sender will be our peer
222  *            identity; message and sender will be NULL on timeout
223  *            (handshake with transport service pending/failed).
224  *             cost estimate will be 0.
225  * @param rec_cls closure for @a rec
226  * @return handle to cancel the operation
227  */
228 struct GNUNET_TRANSPORT_HelloGetHandle *
229 GNUNET_TRANSPORT_hello_get (const struct GNUNET_CONFIGURATION_Handle *cfg,
230                             enum GNUNET_TRANSPORT_AddressClass ac,
231                             GNUNET_TRANSPORT_HelloUpdateCallback rec,
232                             void *rec_cls)
233 {
234   struct GNUNET_TRANSPORT_HelloGetHandle *ghh;
235
236   ghh = GNUNET_new (struct GNUNET_TRANSPORT_HelloGetHandle);
237   ghh->rec = rec;
238   ghh->rec_cls = rec_cls;
239   ghh->cfg = cfg;
240   ghh->ac = ac;
241   reconnect (ghh);
242   if (NULL == ghh->mq)
243   {
244     GNUNET_free (ghh);
245     return NULL;
246   }
247   return ghh;
248 }
249
250
251 /**
252  * Stop receiving updates about changes to our HELLO message.
253  *
254  * @param ghh handle to cancel
255  */
256 void
257 GNUNET_TRANSPORT_hello_get_cancel (struct GNUNET_TRANSPORT_HelloGetHandle *ghh)
258 {
259   if (NULL != ghh->reconnect_task)
260   {
261     GNUNET_SCHEDULER_cancel (ghh->reconnect_task);
262     ghh->reconnect_task = NULL;
263   }
264   if (NULL != ghh->mq)
265   {
266     GNUNET_MQ_destroy (ghh->mq);
267     ghh->mq = NULL;
268   }
269   GNUNET_free (ghh);
270 }
271
272
273 /* end of transport_api_hello_get.c */