make copy of transport_api_core.c
[oweals/gnunet.git] / src / transport / transport_api_manipulation.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_manipulation.c
21  * @brief library to access the low-level P2P IO 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_service.h"
31 #include "transport.h"
32
33 #define LOG(kind,...) GNUNET_log_from (kind, "transport-api",__VA_ARGS__)
34
35
36 /**
37  * Handle for the transport service (includes all of the
38  * state for the transport service).
39  */
40 struct GNUNET_TRANSPORT_ManipulationHandle
41 {
42
43   /**
44    * My client connection to the transport service.
45    */
46   struct GNUNET_MQ_Handle *mq;
47
48   /**
49    * My configuration.
50    */
51   const struct GNUNET_CONFIGURATION_Handle *cfg;
52
53   /**
54    * ID of the task trying to reconnect to the service.
55    */
56   struct GNUNET_SCHEDULER_Task *reconnect_task;
57
58   /**
59    * Delay until we try to reconnect.
60    */
61   struct GNUNET_TIME_Relative reconnect_delay;
62
63   /**
64    * Reconnect in progress
65    */
66   int reconnecting;
67 };
68
69
70 /**
71  * Function that will schedule the job that will try
72  * to connect us again to the client.
73  *
74  * @param h transport service to reconnect
75  */
76 static void
77 disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_ManipulationHandle *h);
78
79
80 /**
81  * Generic error handler, called with the appropriate
82  * error code and the same closure specified at the creation of
83  * the message queue.
84  * Not every message queue implementation supports an error handler.
85  *
86  * @param cls closure with the `struct GNUNET_TRANSPORT_ManipulationHandle *`
87  * @param error error code
88  */
89 static void
90 mq_error_handler (void *cls,
91                   enum GNUNET_MQ_Error error)
92 {
93   struct GNUNET_TRANSPORT_ManipulationHandle *h = cls;
94
95   LOG (GNUNET_ERROR_TYPE_DEBUG,
96        "Error receiving from transport service, disconnecting temporarily.\n");
97   h->reconnecting = GNUNET_YES;
98   disconnect_and_schedule_reconnect (h);
99 }
100
101
102 /**
103  * Try again to connect to transport service.
104  *
105  * @param cls the handle to the transport service
106  */
107 static void
108 reconnect (void *cls)
109 {
110   struct GNUNET_TRANSPORT_ManipulationHandle *h = cls;
111   struct GNUNET_MQ_MessageHandler handlers[] = {
112     GNUNET_MQ_handler_end ()
113   };
114   struct GNUNET_MQ_Envelope *env;
115   struct StartMessage *s;
116
117   h->reconnect_task = NULL;
118   LOG (GNUNET_ERROR_TYPE_DEBUG,
119        "Connecting to transport service.\n");
120   GNUNET_assert (NULL == h->mq);
121   h->reconnecting = GNUNET_NO;
122   h->mq = GNUNET_CLIENT_connect (h->cfg,
123                                  "transport",
124                                  handlers,
125                                  &mq_error_handler,
126                                  h);
127   if (NULL == h->mq)
128     return;
129   env = GNUNET_MQ_msg (s,
130                        GNUNET_MESSAGE_TYPE_TRANSPORT_START);
131   GNUNET_MQ_send (h->mq,
132                   env);
133 }
134
135
136 /**
137  * Function that will schedule the job that will try
138  * to connect us again to the client.
139  *
140  * @param h transport service to reconnect
141  */
142 static void
143 disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_ManipulationHandle *h)
144 {
145   GNUNET_assert (NULL == h->reconnect_task);
146   if (NULL != h->mq)
147   {
148     GNUNET_MQ_destroy (h->mq);
149     h->mq = NULL;
150   }
151   h->reconnect_task =
152       GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
153                                     &reconnect,
154                                     h);
155   h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
156 }
157
158
159 /**
160  * Set transport metrics for a peer and a direction.
161  *
162  * @param handle transport handle
163  * @param peer the peer to set the metric for
164  * @param prop the performance metrics to set
165  * @param delay_in inbound delay to introduce
166  * @param delay_out outbound delay to introduce
167  *
168  * Note: Delay restrictions in receiving direction will be enforced
169  * with one message delay.
170  */
171 void
172 GNUNET_TRANSPORT_manipulation_set (struct GNUNET_TRANSPORT_ManipulationHandle *handle,
173                                    const struct GNUNET_PeerIdentity *peer,
174                                    const struct GNUNET_ATS_Properties *prop,
175                                    struct GNUNET_TIME_Relative delay_in,
176                                    struct GNUNET_TIME_Relative delay_out)
177 {
178   struct GNUNET_MQ_Envelope *env;
179   struct TrafficMetricMessage *msg;
180
181   if (NULL == handle->mq)
182     return;
183   env = GNUNET_MQ_msg (msg,
184                        GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC);
185   msg->reserved = htonl (0);
186   msg->peer = *peer;
187   GNUNET_ATS_properties_hton (&msg->properties,
188                               prop);
189   msg->delay_in = GNUNET_TIME_relative_hton (delay_in);
190   msg->delay_out = GNUNET_TIME_relative_hton (delay_out);
191   GNUNET_MQ_send (handle->mq,
192                   env);
193 }
194
195
196 /**
197  * Connect to the transport service.  Note that the connection may
198  * complete (or fail) asynchronously.
199  *
200  * @param cfg configuration to use
201  * @return NULL on error
202  */
203 struct GNUNET_TRANSPORT_ManipulationHandle *
204 GNUNET_TRANSPORT_manipulation_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
205 {
206   struct GNUNET_TRANSPORT_ManipulationHandle *h;
207
208   h = GNUNET_new (struct GNUNET_TRANSPORT_ManipulationHandle);
209   h->cfg = cfg;
210   LOG (GNUNET_ERROR_TYPE_DEBUG,
211        "Connecting to transport service.\n");
212   reconnect (h);
213   if (NULL == h->mq)
214   {
215     GNUNET_free (h);
216     return NULL;
217   }
218   return h;
219 }
220
221
222 /**
223  * Disconnect from the transport service.
224  *
225  * @param handle handle to the service as returned from #GNUNET_TRANSPORT_manipulation_connect()
226  */
227 void
228 GNUNET_TRANSPORT_manipulation_disconnect (struct GNUNET_TRANSPORT_ManipulationHandle *handle)
229 {
230   if (NULL == handle->reconnect_task)
231     disconnect_and_schedule_reconnect (handle);
232   /* and now we stop trying to connect again... */
233   if (NULL != handle->reconnect_task)
234   {
235     GNUNET_SCHEDULER_cancel (handle->reconnect_task);
236     handle->reconnect_task = NULL;
237   }
238   GNUNET_free (handle);
239 }
240
241
242 /* end of transport_api_manipulation.c */