Implement asynchronous scope identifiers.
[oweals/gnunet.git] / src / transport / transport_api2_address.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2013, 2016, 2018, 2019 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 transport/transport_api2_address.c
23  * @brief library to inform the transport service about addresses to be validated
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_transport_address_service.h"
31 #include "gnunet_ats_transport_service.h"
32 #include "transport.h"
33
34 #define LOG(kind, ...) \
35   GNUNET_log_from (kind, "transport-api-address", __VA_ARGS__)
36
37
38 /**
39  * Handle for the transport service (includes all of the
40  * state for the transport service).
41  */
42 struct GNUNET_TRANSPORT_AddressHandle
43 {
44
45   /**
46    * My client connection to the transport service.
47    */
48   struct GNUNET_MQ_Handle *mq;
49
50   /**
51    * My configuration.
52    */
53   const struct GNUNET_CONFIGURATION_Handle *cfg;
54
55   /**
56    * ID of the task trying to reconnect to the service.
57    */
58   struct GNUNET_SCHEDULER_Task *reconnect_task;
59
60   /**
61    * Delay until we try to reconnect.
62    */
63   struct GNUNET_TIME_Relative reconnect_delay;
64 };
65
66
67 /**
68  * Function that will schedule the job that will try
69  * to connect us again to the client.
70  *
71  * @param h transport service to reconnect
72  */
73 static void
74 disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_AddressHandle *h);
75
76
77 /**
78  * Generic error handler, called with the appropriate
79  * error code and the same closure specified at the creation of
80  * the message queue.
81  * Not every message queue implementation supports an error handler.
82  *
83  * @param cls closure with the `struct GNUNET_TRANSPORT_AddressHandle *`
84  * @param error error code
85  */
86 static void
87 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
88 {
89   struct GNUNET_TRANSPORT_AddressHandle *h = cls;
90
91   LOG (GNUNET_ERROR_TYPE_DEBUG,
92        "Error receiving from transport service, disconnecting temporarily.\n");
93   disconnect_and_schedule_reconnect (h);
94 }
95
96
97 /**
98  * Try again to connect to transport service.
99  *
100  * @param cls the handle to the transport service
101  */
102 static void
103 reconnect (void *cls)
104 {
105   struct GNUNET_TRANSPORT_AddressHandle *h = cls;
106   struct GNUNET_MQ_MessageHandler handlers[] = {GNUNET_MQ_handler_end ()};
107
108   h->reconnect_task = NULL;
109   LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service.\n");
110   GNUNET_assert (NULL == h->mq);
111   h->mq =
112     GNUNET_CLIENT_connect (h->cfg, "transport", handlers, &mq_error_handler, h);
113 }
114
115
116 /**
117  * Disconnect from the transport service.
118  *
119  * @param h transport service to disconnect
120  */
121 static void
122 disconnect (struct GNUNET_TRANSPORT_AddressHandle *h)
123 {
124   if (NULL != h->mq)
125   {
126     GNUNET_MQ_destroy (h->mq);
127     h->mq = NULL;
128   }
129 }
130
131
132 /**
133  * Function that will schedule the job that will try
134  * to connect us again to the client.
135  *
136  * @param h transport service to reconnect
137  */
138 static void
139 disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_AddressHandle *h)
140 {
141   GNUNET_assert (NULL == h->reconnect_task);
142   disconnect (h);
143   LOG (GNUNET_ERROR_TYPE_DEBUG,
144        "Scheduling task to reconnect to transport service in %s.\n",
145        GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
146   h->reconnect_task =
147     GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
148   h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
149 }
150
151
152 /**
153  * Connect to the transport service.
154  *
155  * @param cfg configuration to use
156  * @return NULL on error
157  */
158 struct GNUNET_TRANSPORT_AddressHandle *
159 GNUNET_TRANSPORT_address_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
160 {
161   struct GNUNET_TRANSPORT_AddressHandle *h;
162
163   h = GNUNET_new (struct GNUNET_TRANSPORT_AddressHandle);
164   h->cfg = cfg;
165   h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
166   LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service\n");
167   reconnect (h);
168   if (NULL == h->mq)
169   {
170     GNUNET_free (h);
171     return NULL;
172   }
173   return h;
174 }
175
176
177 /**
178  * Disconnect from the transport service.
179  *
180  * @param handle handle to the service as returned from #GNUNET_TRANSPORT_address_connect()
181  */
182 void
183 GNUNET_TRANSPORT_address_disconnect (
184   struct GNUNET_TRANSPORT_AddressHandle *handle)
185 {
186   LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n");
187   /* this disconnects all neighbours... */
188   disconnect (handle);
189   /* and now we stop trying to connect again... */
190   if (NULL != handle->reconnect_task)
191   {
192     GNUNET_SCHEDULER_cancel (handle->reconnect_task);
193     handle->reconnect_task = NULL;
194   }
195   GNUNET_free (handle);
196 }
197
198
199 /**
200  * The client has learned about a possible address for peer @a pid
201  * (i.e. via broadcast, multicast, DHT, ...).  The transport service
202  * should consider validating it. Note that the plugin is NOT expected
203  * to have verified the signature, the transport service must decide
204  * whether to check the signature.
205  *
206  * While the notification is sent to @a ch asynchronously, this API
207  * does not return a handle as the delivery of addresses is simply
208  * unreliable, and if @a ch is down, the data provided will simply be
209  * lost.
210  *
211  * @param ch communicator handle
212  * @param pid peer the address is for
213  * @param raw raw address data
214  * @param raw_size number of bytes in @a raw
215  */
216 void
217 GNUNET_TRANSPORT_address_try (struct GNUNET_TRANSPORT_AddressHandle *ch,
218                               const struct GNUNET_PeerIdentity *pid,
219                               const void *raw,
220                               const size_t raw_size)
221 {
222   struct GNUNET_MQ_Envelope *env;
223   struct GNUNET_TRANSPORT_AddressToVerify *hdr;
224
225   env =
226     GNUNET_MQ_msg_extra (hdr,
227                          raw_size,
228                          GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY);
229   hdr->peer = *pid;
230   memcpy (&hdr[1], raw, raw_size);
231   GNUNET_MQ_send (ch->mq, env);
232 }
233
234
235 /* end of transport_api2_address.c */