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