46b140ac7e7c7c798d5d96a1554d4a22d9be9ff1
[oweals/gnunet.git] / src / gns / gns_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file gns/gns_api.c
23  * @brief library to access the GNS service
24  * @author Martin Schanzenbach
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_constants.h"
30 #include "gnunet_arm_service.h"
31 #include "gnunet_hello_lib.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_dht_service.h"
34
35 #define DEBUG_GNS_API GNUNET_EXTRA_LOGGING
36
37 #define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__)
38
39 /**
40  * Handle to a Lookup request
41  */
42 struct GNUNET_GNS_LookupHandle
43 {
44
45   /**
46    * Iterator to call on data receipt
47    */
48   GNUNET_GNS_LookupIterator iter;
49
50   /**
51    * Closure for the iterator callback
52    */
53   void *iter_cls;
54
55   /**
56    * Main handle to this GNS api
57    */
58   struct GNUNET_GNS_Handle *gns_handle;
59
60   /**
61    * Key that this get request is for
62    */
63   GNUNET_HashCode key;
64
65   /**
66    * Unique identifier for this request (for key collisions).
67    */
68   uint64_t unique_id;
69
70 };
71
72
73 /**
74  * Connection to the GNS service.
75  */
76 struct GNUNET_GNS_Handle
77 {
78
79   /**
80    * Configuration to use.
81    */
82   const struct GNUNET_CONFIGURATION_Handle *cfg;
83
84   /**
85    * Socket (if available).
86    */
87   struct GNUNET_CLIENT_Connection *client;
88
89   /**
90    * Currently pending transmission request (or NULL).
91    */
92   struct GNUNET_CLIENT_TransmitHandle *th;
93
94   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
95
96   /**
97    * How quickly should we retry?  Used for exponential back-off on
98    * connect-errors.
99    */
100   struct GNUNET_TIME_Relative retry_time;
101
102   /**
103    * Generator for unique ids.
104    */
105   uint64_t uid_gen;
106
107   /**
108    * Did we start our receive loop yet?
109    */
110   int in_receive;
111 };
112
113
114 /**
115  * Try to (re)connect to the GNS service.
116  *
117  * @return GNUNET_YES on success, GNUNET_NO on failure.
118  */
119 static int
120 try_connect (struct GNUNET_GNS_Handle *handle)
121 {
122   if (handle->client != NULL)
123     return GNUNET_OK;
124   handle->in_receive = GNUNET_NO;
125   handle->client = GNUNET_CLIENT_connect ("gns", handle->cfg);
126   if (handle->client == NULL)
127   {
128     LOG (GNUNET_ERROR_TYPE_WARNING,
129          _("Failed to connect to the GNS service!\n"));
130     return GNUNET_NO;
131   }
132   return GNUNET_YES;
133 }
134
135 /**
136  * Try reconnecting to the GNS service.
137  *
138  * @param cls GNUNET_GNS_Handle
139  * @param tc scheduler context
140  */
141 static void
142 try_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
143 {
144   struct GNUNET_GNS_Handle *handle = cls;
145
146 #if DEBUG_DHT
147   LOG (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting with GNS %p\n", handle);
148 #endif
149   handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
150   if (handle->retry_time.rel_value < GNUNET_CONSTANTS_SERVICE_RETRY.rel_value)
151     handle->retry_time = GNUNET_CONSTANTS_SERVICE_RETRY;
152   else
153     handle->retry_time = GNUNET_TIME_relative_multiply (handle->retry_time, 2);
154   if (handle->retry_time.rel_value > GNUNET_CONSTANTS_SERVICE_TIMEOUT.rel_value)
155     handle->retry_time = GNUNET_CONSTANTS_SERVICE_TIMEOUT;
156   handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
157   if (GNUNET_YES != try_connect (handle))
158   {
159 #if DEBUG_DHT
160     LOG (GNUNET_ERROR_TYPE_DEBUG, "GNS reconnect failed(!)\n");
161 #endif
162     return;
163   }
164   GNUNET_CONTAINER_multihashmap_iterate (handle->active_requests,
165                                          &add_request_to_pending, handle);
166   process_pending_messages (handle);
167 }
168
169
170 /**
171  * Try reconnecting to the GNS service.
172  *
173  * @param handle handle to gns to (possibly) disconnect and reconnect
174  */
175 static void
176 do_disconnect (struct GNUNET_GNS_Handle *handle)
177 {
178   if (handle->client == NULL)
179     return;
180   GNUNET_assert (handle->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
181   if (NULL != handle->th)
182     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
183   handle->th = NULL;
184   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
185               "Disconnecting from GNS service, will try to reconnect in %llu ms\n",
186               (unsigned long long) handle->retry_time.rel_value);
187   GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
188   handle->client = NULL;
189   handle->reconnect_task =
190       GNUNET_SCHEDULER_add_delayed (handle->retry_time, &try_reconnect, handle);
191 }
192
193
194 /**
195  * Initialize the connection with the GNS service.
196  *
197  * @param cfg configuration to use
198  * @return handle to the GNS service, or NULL on error
199  */
200 struct GNUNET_GNS_Handle *
201 GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
202                     unsigned int ht_len)
203 {
204   struct GNUNET_GNS_Handle *handle;
205
206   handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_Handle));
207   handle->cfg = cfg;
208   handle->uid_gen =
209       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
210   handle->active_requests = GNUNET_CONTAINER_multihashmap_create (ht_len);
211   if (GNUNET_NO == try_connect (handle))
212   {
213     GNUNET_GNS_disconnect (handle);
214     return NULL;
215   }
216   return handle;
217 }
218
219
220 /**
221  * Shutdown connection with the GNS service.
222  *
223  * @param handle handle of the GNS connection to stop
224  */
225 void
226 GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
227 {
228         /* disco from GNS */
229 }
230
231
232 /**
233  * Add a new record to the GNS.
234  *
235  * @param handle handle to GNS service
236  * @param key the key to store under
237  * @param desired_replication_level estimate of how many
238  *                nearest peers this request should reach
239  * @param options routing options for this message
240  * @param type type of the value
241  * @param size number of bytes in data; must be less than 64k
242  * @param data the data to store
243  * @param exp desired expiration time for the value
244  * @param timeout how long to wait for transmission of this request
245  * @param cont continuation to call when done (transmitting request to service)
246  * @param cont_cls closure for cont
247  */
248 void
249 GNUNET_GNS_add_record (struct GNUNET_GNS_Handle *handle, const GNUNET_HashCode * key,
250                 uint32_t desired_replication_level,
251                 enum GNUNET_DHT_RouteOption options,
252                 enum GNUNET_BLOCK_Type type, size_t size, const char *data,
253                 struct GNUNET_TIME_Absolute exp,
254                 struct GNUNET_TIME_Relative timeout, GNUNET_SCHEDULER_Task cont,
255                 void *cont_cls)
256 {
257         /* add record to local db, dht; sign etc */
258 }
259
260
261 /**
262  * Perform an asynchronous Lookup operation on the GNS.
263  *
264  * @param handle handle to the GNS service
265  * @param timeout how long to wait for transmission of this request to the service
266  * @param type expected type of the response object
267  * @param key the key to look up
268  * @param desired_replication_level estimate of how many
269                   nearest peers this request should reach
270  * @param options routing options for this message
271  * @param xquery extended query data (can be NULL, depending on type)
272  * @param xquery_size number of bytes in xquery
273  * @param iter function to call on each result
274  * @param iter_cls closure for iter
275  * @return handle to stop the async get
276  */
277 struct GNUNET_GNS_LookupHandle *
278 GNUNET_GNS_lookup_start (struct GNUNET_GNS_Handle *handle,
279                       struct GNUNET_TIME_Relative timeout,
280                       enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * key,
281                       uint32_t desired_replication_level,
282                       enum GNUNET_DHT_RouteOption options, const void *xquery,
283                       size_t xquery_size, GNUNET_GNS_LookupIterator iter,
284                       void *iter_cls)
285 {
286   /* look for local entries, start dht lookup, return lookup_handle */
287 }
288
289
290 /**
291  * Stop async GNS lookup.
292  *
293  * @param lookup_handle handle to the GNS lookup operation to stop
294  */
295 void
296 GNUNET_GNS_lookup_stop (struct GNUNET_GNS_LookupHandle *lookup_handle)
297 {
298   struct GNUNET_DHT_Handle *handle;
299         /* TODO Stop dht lookups */
300 }
301
302
303 /* end of gns_api.c */