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