-removed obsolete functions
[oweals/gnunet.git] / src / dht / gnunet-service-xdht_datacache.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2011, 2015 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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file dht/gnunet-service-xdht_datacache.c
22  * @brief GNUnet DHT service's datacache integration
23  * @author Christian Grothoff
24  * @author Nathan Evans
25  */
26 #include "platform.h"
27 #include "gnunet_datacache_lib.h"
28 #include "gnunet-service-xdht_clients.h"
29 #include "gnunet-service-xdht_datacache.h"
30 #include "gnunet-service-xdht_routing.h"
31 #include "gnunet-service-xdht_neighbours.h"
32 #include "gnunet-service-dht.h"
33
34 #define LOG(kind,...) GNUNET_log_from (kind, "dht-dtcache",__VA_ARGS__)
35
36 #define DEBUG(...)                                           \
37   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
38
39 /**
40  * Handle to the datacache service (for inserting/retrieving data)
41  */
42 static struct GNUNET_DATACACHE_Handle *datacache;
43
44
45 /**
46  * Handle a datum we've received from another peer.  Cache if
47  * possible.
48  *
49  * @param expiration when will the reply expire
50  * @param key the query this reply is for
51  * @param put_path_length number of peers in @a put_path
52  * @param put_path path the reply took on put
53  * @param type type of the reply
54  * @param data_size number of bytes in @a data
55  * @param data application payload data
56  */
57 void
58 GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
59                           const struct GNUNET_HashCode *key,
60                           unsigned int put_path_length,
61                           const struct GNUNET_PeerIdentity *put_path,
62                           enum GNUNET_BLOCK_Type type,
63                           size_t data_size,
64                           const void *data)
65 {
66   int r;
67
68   if (NULL == datacache)
69   {
70     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
71                 "PUT request received, but have no datacache!\n");
72     return;
73   }
74   if (data_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
75   {
76     GNUNET_break (0);
77     return;
78   }
79
80   /* Put size is actual data size plus struct overhead plus path length (if any) */
81   r = GNUNET_DATACACHE_put (datacache,
82                             key,
83                             data_size,
84                             data,
85                             type,
86                             expiration,
87                             put_path_length,
88                             put_path);
89   if (GNUNET_OK == r)
90     GNUNET_STATISTICS_update (GDS_stats,
91                               gettext_noop ("# ITEMS stored in datacache"), 1,
92                               GNUNET_NO);
93   LOG (GNUNET_ERROR_TYPE_DEBUG,
94        "DATACACHE PUT for key %s [%u] completed (%d) after %u hops\n",
95        GNUNET_h2s (key),
96        data_size,
97        r,
98        put_path_length);
99 }
100
101
102 /**
103  * List of peers in the get path.
104  */
105 struct GetPath
106 {
107   /**
108    * Pointer to next item in the list
109    */
110   struct GetPath *next;
111
112   /**
113    * Pointer to previous item in the list
114    */
115   struct GetPath *prev;
116
117   /**
118    *  An element in the get path.
119    */
120   struct GNUNET_PeerIdentity peer;
121 };
122
123
124 /**
125  * Context containing information about a GET request.
126  */
127 struct GetRequestContext
128 {
129   /**
130    * extended query (see gnunet_block_lib.h).
131    */
132   const void *xquery;
133
134   /**
135    * Bloomfilter to filter out duplicate replies (updated)
136    */
137   struct GNUNET_CONTAINER_BloomFilter **reply_bf;
138
139   /**
140    * The key this request was about
141    */
142   struct GNUNET_HashCode key;
143
144   /**
145    * Number of bytes in xquery.
146    */
147   size_t xquery_size;
148
149   /**
150    * Mutator value for the @e reply_bf, see gnunet_block_lib.h
151    */
152   uint32_t reply_bf_mutator;
153
154   /**
155    * Total number of peers in get path.
156    */
157   unsigned int get_path_length;
158
159   /**
160    * Return value to give back.
161    */
162   enum GNUNET_BLOCK_EvaluationResult eval;
163
164   /**
165    * Peeer which has the data for the key.
166    */
167   struct GNUNET_PeerIdentity source_peer;
168
169   /**
170    * Next hop to forward the get result to.
171    */
172   struct GNUNET_PeerIdentity next_hop;
173
174   /**
175    * Head of get path.
176    */
177   struct GetPath *head;
178
179   /**
180    * Tail of get path.
181    */
182   struct GetPath *tail;
183
184   /* get_path */
185 };
186
187
188 /**
189  * Iterator for local get request results,
190  *
191  * @param cls closure for iterator, a `struct GetRequestContext`
192  * @param key the key this @a data is stored under
193  * @param size the size of the data identified by key
194  * @param data the actual data
195  * @param type the type of the @a data
196  * @param exp when does this value expire?
197  * @param put_path_length number of peers in @a put_path
198  * @param put_path path the reply took on put
199  * @return #GNUNET_OK to continue iteration, anything else
200  * to stop iteration.
201  */
202 static int
203 datacache_get_iterator (void *cls,
204                         const struct GNUNET_HashCode *key,
205                         size_t size,
206                         const char *data,
207                         enum GNUNET_BLOCK_Type type,
208                         struct GNUNET_TIME_Absolute exp,
209                         unsigned int put_path_length,
210                         const struct GNUNET_PeerIdentity *put_path)
211 {
212   struct GetRequestContext *ctx = cls;
213   enum GNUNET_BLOCK_EvaluationResult eval;
214
215   eval =
216       GNUNET_BLOCK_evaluate (GDS_block_context,
217                              type,
218                              GNUNET_BLOCK_EO_NONE,
219                              key,
220                              ctx->reply_bf,
221                              ctx->reply_bf_mutator,
222                              ctx->xquery,
223                              ctx->xquery_size,
224                              data,
225                              size);
226   LOG (GNUNET_ERROR_TYPE_DEBUG,
227        "Found reply for query %s in datacache, evaluation result is %d\n",
228        GNUNET_h2s (key), (int) eval);
229   ctx->eval = eval;
230
231   switch (eval)
232   {
233   case GNUNET_BLOCK_EVALUATION_OK_MORE:
234   case GNUNET_BLOCK_EVALUATION_OK_LAST:
235     /* forward to local clients */
236     GNUNET_STATISTICS_update (GDS_stats,
237                               gettext_noop
238                               ("# Good RESULTS found in datacache"), 1,
239                               GNUNET_NO);
240     struct GNUNET_PeerIdentity *get_path;
241     get_path = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity) *
242                               ctx->get_path_length);
243     struct GetPath *iterator;
244     iterator = ctx->head;
245     int i = 0;
246     while (i < ctx->get_path_length)
247     {
248       get_path[i] = iterator->peer;
249       i++;
250       iterator = iterator->next;
251     }
252     GDS_NEIGHBOURS_send_get_result (key,type,
253                                     &ctx->next_hop,
254                                     &ctx->source_peer,
255                                     put_path_length,
256                                     put_path,
257                                     ctx->get_path_length,
258                                     get_path,
259                                     exp,
260                                     data,
261                                     size);
262     GNUNET_free_non_null (get_path);
263     break;
264   case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
265     GNUNET_STATISTICS_update (GDS_stats,
266                               gettext_noop
267                               ("# Duplicate RESULTS found in datacache"), 1,
268                               GNUNET_NO);
269     break;
270   case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
271     GNUNET_STATISTICS_update (GDS_stats,
272                               gettext_noop
273                               ("# Invalid RESULTS found in datacache"), 1,
274                               GNUNET_NO);
275     break;
276   case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
277     GNUNET_STATISTICS_update (GDS_stats,
278                               gettext_noop
279                               ("# Irrelevant RESULTS found in datacache"), 1,
280                               GNUNET_NO);
281     break;
282   case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
283     GNUNET_break (0);
284     break;
285   case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
286     GNUNET_break_op (0);
287     return GNUNET_SYSERR;
288   case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
289     GNUNET_STATISTICS_update (GDS_stats,
290                               gettext_noop
291                               ("# Unsupported RESULTS found in datacache"), 1,
292                               GNUNET_NO);
293     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
294                 _("Unsupported block type (%u) in local response!\n"),
295                 type);
296     break;
297   }
298
299   return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK;
300 }
301
302
303 /**
304  * Handle a GET request we've received from another peer.
305  *
306  * @param key the query
307  * @param type requested data type
308  * @param xquery extended query
309  * @param xquery_size number of bytes in @a xquery
310  * @param reply_bf where the reply bf is (to be) stored, possibly updated, can be NULL
311  * @param reply_bf_mutator mutation value for @a reply_bf
312  * @return evaluation result for the local replies
313  * @get_path_length Total number of peers in get path
314  * @get_path Peers in get path.
315  */
316 enum GNUNET_BLOCK_EvaluationResult
317 GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
318                           enum GNUNET_BLOCK_Type type,
319                           const void *xquery,
320                           size_t xquery_size,
321                           struct GNUNET_CONTAINER_BloomFilter **reply_bf,
322                           uint32_t reply_bf_mutator,
323                           uint32_t get_path_length,
324                           struct GNUNET_PeerIdentity *get_path,
325                           struct GNUNET_PeerIdentity *next_hop,
326                           struct GNUNET_PeerIdentity *source_peer)
327 {
328   struct GetRequestContext ctx;
329   unsigned int r;
330
331   if (datacache == NULL)
332     return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
333   GNUNET_STATISTICS_update (GDS_stats,
334                             gettext_noop ("# GET requests given to datacache"),
335                             1, GNUNET_NO);
336   ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
337   ctx.key = *key;
338   ctx.xquery = xquery;
339   ctx.xquery_size = xquery_size;
340   ctx.reply_bf = reply_bf;
341   ctx.reply_bf_mutator = reply_bf_mutator;
342   ctx.get_path_length = get_path_length;
343
344   if (NULL != next_hop)
345     ctx.next_hop = *next_hop;
346   unsigned int i = 0;
347
348   ctx.head = NULL;
349   ctx.tail = NULL;
350   if (NULL != get_path)
351   {
352     while (i < get_path_length)
353     {
354       struct GetPath *element;
355       element = GNUNET_new (struct GetPath);
356       element->next = NULL;
357       element->prev = NULL;
358       element->peer = get_path[i];
359       GNUNET_CONTAINER_DLL_insert_tail (ctx.head, ctx.tail, element);
360       i++;
361     }
362   }
363
364   r = GNUNET_DATACACHE_get (datacache,
365                             key,
366                             type,
367                             &datacache_get_iterator,
368                             &ctx);
369   DEBUG ("DATACACHE_GET for key %s completed (%d). %u results found.\n",
370          GNUNET_h2s (key),
371          ctx.eval,
372          r);
373   return ctx.eval;
374 }
375
376
377 /**
378  * Initialize datacache subsystem.
379  */
380 void
381 GDS_DATACACHE_init ()
382 {
383   datacache = GNUNET_DATACACHE_create (GDS_cfg, "dhtcache");
384 }
385
386
387 /**
388  * Shutdown datacache subsystem.
389  */
390 void
391 GDS_DATACACHE_done ()
392 {
393   if (NULL != datacache)
394   {
395     GNUNET_DATACACHE_destroy (datacache);
396     datacache = NULL;
397   }
398 }
399
400
401 /* end of gnunet-service-xdht_datacache.c */