migrate transport_core API to MQ
[oweals/gnunet.git] / src / transport / transport_api_get_hello.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.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_service.h"
33 #include "transport.h"
34
35
36 /**
37  * Functions to call with this peer's HELLO.
38  */
39 struct GNUNET_TRANSPORT_GetHelloHandle
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
79
80 /**
81  * Function we use for checking incoming HELLO messages.
82  *
83  * @param cls closure, a `struct GNUNET_TRANSPORT_Handle *`
84  * @param msg message received
85  * @return #GNUNET_OK if message is well-formed
86  */
87 static int
88 check_hello (void *cls,
89              const struct GNUNET_MessageHeader *msg)
90 {
91   struct GNUNET_PeerIdentity me;
92
93   if (GNUNET_OK !=
94       GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) msg,
95                            &me))
96   {
97     GNUNET_break (0);
98     return GNUNET_SYSERR;
99   }
100   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
101               "Receiving (my own) HELLO message (%u bytes), I am `%s'.\n",
102               (unsigned int) ntohs (msg->size),
103               GNUNET_i2s (&me));
104   return GNUNET_OK;
105 }
106
107
108 /**
109  * Function we use for handling incoming HELLO messages.
110  *
111  * @param cls closure, a `struct GNUNET_TRANSPORT_GetHelloHandle *`
112  * @param msg message received
113  */
114 static void
115 handle_hello (void *cls,
116               const struct GNUNET_MessageHeader *msg)
117 {
118   struct GNUNET_TRANSPORT_GetHelloHandle *ghh = cls;
119
120   ghh->rec (ghh->rec_cls,
121             msg);
122 }
123
124
125 /**
126  * Function that will schedule the job that will try
127  * to connect us again to the client.
128  *
129  * @param ghh transport service to reconnect
130  */
131 static void
132 schedule_reconnect (struct GNUNET_TRANSPORT_GetHelloHandle *ghh);
133
134
135 /**
136  * Generic error handler, called with the appropriate
137  * error code and the same closure specified at the creation of
138  * the message queue.
139  * Not every message queue implementation supports an error handler.
140  *
141  * @param cls closure with the `struct GNUNET_TRANSPORT_Handle *`
142  * @param error error code
143  */
144 static void
145 mq_error_handler (void *cls,
146                   enum GNUNET_MQ_Error error)
147 {
148   struct GNUNET_TRANSPORT_GetHelloHandle *ghh = cls;
149
150   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
151               "Error receiving from transport service, disconnecting temporarily.\n");
152   GNUNET_MQ_destroy (ghh->mq);
153   ghh->mq = NULL;
154   schedule_reconnect (ghh);
155 }
156
157
158 /**
159  * Try again to connect to transport service.
160  *
161  * @param cls the handle to the transport service
162  */
163 static void
164 reconnect (void *cls)
165 {
166   GNUNET_MQ_hd_var_size (hello,
167                          GNUNET_MESSAGE_TYPE_HELLO,
168                          struct GNUNET_MessageHeader);
169   struct GNUNET_TRANSPORT_GetHelloHandle *ghh = cls;
170   struct GNUNET_MQ_MessageHandler handlers[] = {
171     make_hello_handler (ghh),
172     GNUNET_MQ_handler_end ()
173   };
174   struct GNUNET_MQ_Envelope *env;
175   struct StartMessage *s;
176
177   ghh->reconnect_task = NULL;
178   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
179               "Connecting to transport service.\n");
180   GNUNET_assert (NULL == ghh->mq);
181   ghh->mq = GNUNET_CLIENT_connecT (ghh->cfg,
182                                    "transport",
183                                    handlers,
184                                    &mq_error_handler,
185                                    ghh);
186   if (NULL == ghh->mq)
187     return;
188   env = GNUNET_MQ_msg (s,
189                        GNUNET_MESSAGE_TYPE_TRANSPORT_START);
190   s->options = htonl (0);
191   GNUNET_MQ_send (ghh->mq,
192                   env);
193 }
194
195
196 /**
197  * Function that will schedule the job that will try
198  * to connect us again to the client.
199  *
200  * @param ghh transport service to reconnect
201  */
202 static void
203 schedule_reconnect (struct GNUNET_TRANSPORT_GetHelloHandle *ghh)
204 {
205   ghh->reconnect_task =
206       GNUNET_SCHEDULER_add_delayed (ghh->reconnect_delay,
207                                     &reconnect,
208                                     ghh);
209   ghh->reconnect_delay = GNUNET_TIME_STD_BACKOFF (ghh->reconnect_delay);
210 }
211
212
213 /**
214  * Obtain the HELLO message for this peer.  The callback given in this function
215  * is never called synchronously.
216  *
217  * @param cfg configuration
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_GetHelloHandle *
226 GNUNET_TRANSPORT_get_hello (const struct GNUNET_CONFIGURATION_Handle *cfg,
227                             GNUNET_TRANSPORT_HelloUpdateCallback rec,
228                             void *rec_cls)
229 {
230   struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
231
232   ghh = GNUNET_new (struct GNUNET_TRANSPORT_GetHelloHandle);
233   ghh->rec = rec;
234   ghh->rec_cls = rec_cls;
235   ghh->cfg = cfg;
236   reconnect (ghh);
237   if (NULL == ghh->mq)
238   {
239     GNUNET_free (ghh);
240     return NULL;
241   }
242   return ghh;
243 }
244
245
246 /**
247  * Stop receiving updates about changes to our HELLO message.
248  *
249  * @param ghh handle to cancel
250  */
251 void
252 GNUNET_TRANSPORT_get_hello_cancel (struct GNUNET_TRANSPORT_GetHelloHandle *ghh)
253 {
254   if (NULL != ghh->mq)
255   {
256     GNUNET_MQ_destroy (ghh->mq);
257     ghh->mq = NULL;
258   }
259   GNUNET_free (ghh);
260 }
261
262
263 /* end of transport_api_get_hello.c */