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