refactor DHT for new service API
[oweals/gnunet.git] / src / dht / gnunet-service-dht_datacache.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2011, 2015 GNUnet e.V.
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-dht_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-dht_datacache.h"
29 #include "gnunet-service-dht_routing.h"
30 #include "gnunet-service-dht.h"
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "dht-dhtcache",__VA_ARGS__)
33
34
35 /**
36  * Handle to the datacache service (for inserting/retrieving data)
37  */
38 static struct GNUNET_DATACACHE_Handle *datacache;
39
40
41 /**
42  * Handle a datum we've received from another peer.  Cache if
43  * possible.
44  *
45  * @param expiration when will the reply expire
46  * @param key the query this reply is for
47  * @param put_path_length number of peers in @a put_path
48  * @param put_path path the reply took on put
49  * @param type type of the reply
50  * @param data_size number of bytes in @a data
51  * @param data application payload data
52  */
53 void
54 GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
55                           const struct GNUNET_HashCode *key,
56                           unsigned int put_path_length,
57                           const struct GNUNET_PeerIdentity *put_path,
58                           enum GNUNET_BLOCK_Type type,
59                           size_t data_size,
60                           const void *data)
61 {
62   int r;
63
64   if (NULL == datacache)
65   {
66     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
67                 _("%s request received, but have no datacache!\n"), "PUT");
68     return;
69   }
70   if (data_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
71   {
72     GNUNET_break (0);
73     return;
74   }
75   /* Put size is actual data size plus struct overhead plus path length (if any) */
76   GNUNET_STATISTICS_update (GDS_stats,
77                             gettext_noop ("# ITEMS stored in datacache"), 1,
78                             GNUNET_NO);
79   r = GNUNET_DATACACHE_put (datacache,
80                             key,
81                             data_size,
82                             data,
83                             type,
84                             expiration,
85                             put_path_length,
86                             put_path);
87   LOG (GNUNET_ERROR_TYPE_DEBUG,
88        "DATACACHE PUT for key %s [%u] completed (%d) after %u hops\n",
89        GNUNET_h2s (key),
90        data_size,
91        r,
92        put_path_length);
93 }
94
95
96 /**
97  * Context containing information about a GET request.
98  */
99 struct GetRequestContext
100 {
101   /**
102    * extended query (see gnunet_block_lib.h).
103    */
104   const void *xquery;
105
106   /**
107    * Bloomfilter to filter out duplicate replies (updated)
108    */
109   struct GNUNET_CONTAINER_BloomFilter **reply_bf;
110
111   /**
112    * The key this request was about
113    */
114   struct GNUNET_HashCode key;
115
116   /**
117    * Number of bytes in xquery.
118    */
119   size_t xquery_size;
120
121   /**
122    * Mutator value for the @e reply_bf, see gnunet_block_lib.h
123    */
124   uint32_t reply_bf_mutator;
125
126   /**
127    * Return value to give back.
128    */
129   enum GNUNET_BLOCK_EvaluationResult eval;
130 };
131
132
133 /**
134  * Iterator for local get request results,
135  *
136  * @param cls closure for iterator, a `struct GetRequestContext`
137  * @param exp when does this value expire?
138  * @param key the key this data is stored under
139  * @param size the size of the data identified by key
140  * @param data the actual data
141  * @param type the type of the @a data
142  * @param put_path_length number of peers in @a put_path
143  * @param put_path path the reply took on put
144  * @return #GNUNET_OK to continue iteration, anything else
145  * to stop iteration.
146  */
147 static int
148 datacache_get_iterator (void *cls,
149                         const struct GNUNET_HashCode *key,
150                         size_t size,
151                         const char *data,
152                         enum GNUNET_BLOCK_Type type,
153                         struct GNUNET_TIME_Absolute exp,
154                         unsigned int put_path_length,
155                         const struct GNUNET_PeerIdentity *put_path)
156 {
157   struct GetRequestContext *ctx = cls;
158   enum GNUNET_BLOCK_EvaluationResult eval;
159
160   eval =
161       GNUNET_BLOCK_evaluate (GDS_block_context,
162                              type,
163                              GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
164                              key,
165                              ctx->reply_bf,
166                              ctx->reply_bf_mutator,
167                              ctx->xquery,
168                              ctx->xquery_size,
169                              data,
170                              size);
171   LOG (GNUNET_ERROR_TYPE_DEBUG,
172        "Found reply for query %s in datacache, evaluation result is %d\n",
173        GNUNET_h2s (key),
174        (int) eval);
175   ctx->eval = eval;
176   switch (eval)
177   {
178   case GNUNET_BLOCK_EVALUATION_OK_MORE:
179   case GNUNET_BLOCK_EVALUATION_OK_LAST:
180     /* forward to local clients */
181     GNUNET_STATISTICS_update (GDS_stats,
182                               gettext_noop
183                               ("# Good RESULTS found in datacache"), 1,
184                               GNUNET_NO);
185     GDS_CLIENTS_handle_reply (exp, key,
186                               0, NULL,
187                               put_path_length, put_path,
188                               type,
189                               size, data);
190     /* forward to other peers */
191     GDS_ROUTING_process (type,
192                          exp,
193                          key,
194                          put_path_length, put_path,
195                          0, NULL,
196                          data, size);
197     break;
198   case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
199     GNUNET_STATISTICS_update (GDS_stats,
200                               gettext_noop ("# Duplicate RESULTS found in datacache"),
201                               1,
202                               GNUNET_NO);
203     break;
204   case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
205     GNUNET_STATISTICS_update (GDS_stats,
206                               gettext_noop ("# Invalid RESULTS found in datacache"),
207                               1,
208                               GNUNET_NO);
209     break;
210   case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
211     GNUNET_STATISTICS_update (GDS_stats,
212                               gettext_noop ("# Irrelevant RESULTS found in datacache"),
213                               1,
214                               GNUNET_NO);
215     break;
216   case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
217     GNUNET_break (0);
218     break;
219   case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
220     GNUNET_break_op (0);
221     return GNUNET_SYSERR;
222   case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
223     GNUNET_STATISTICS_update (GDS_stats,
224                               gettext_noop ("# Unsupported RESULTS found in datacache"),
225                               1,
226                               GNUNET_NO);
227     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
228                 _("Unsupported block type (%u) in local response!\n"),
229                 type);
230     break;
231   }
232   return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK;
233 }
234
235
236 /**
237  * Handle a GET request we've received from another peer.
238  *
239  * @param key the query
240  * @param type requested data type
241  * @param xquery extended query
242  * @param xquery_size number of bytes in @a xquery
243  * @param reply_bf where the reply bf is (to be) stored, possibly updated, can be NULL
244  * @param reply_bf_mutator mutation value for @a reply_bf
245  * @return evaluation result for the local replies
246  */
247 enum GNUNET_BLOCK_EvaluationResult
248 GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
249                           enum GNUNET_BLOCK_Type type,
250                           const void *xquery,
251                           size_t xquery_size,
252                           struct GNUNET_CONTAINER_BloomFilter **reply_bf,
253                           uint32_t reply_bf_mutator)
254 {
255   struct GetRequestContext ctx;
256   unsigned int r;
257
258   if (NULL == datacache)
259     return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
260   GNUNET_STATISTICS_update (GDS_stats,
261                             gettext_noop ("# GET requests given to datacache"),
262                             1,
263                             GNUNET_NO);
264   ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
265   ctx.key = *key;
266   ctx.xquery = xquery;
267   ctx.xquery_size = xquery_size;
268   ctx.reply_bf = reply_bf;
269   ctx.reply_bf_mutator = reply_bf_mutator;
270   r = GNUNET_DATACACHE_get (datacache,
271                             key,
272                             type,
273                             &datacache_get_iterator,
274                             &ctx);
275   LOG (GNUNET_ERROR_TYPE_DEBUG,
276        "DATACACHE GET for key %s completed (%d). %u results found.\n",
277        GNUNET_h2s (key),
278        ctx.eval,
279        r);
280   return ctx.eval;
281 }
282
283
284 /**
285  * Initialize datacache subsystem.
286  */
287 void
288 GDS_DATACACHE_init ()
289 {
290   datacache = GNUNET_DATACACHE_create (GDS_cfg, "dhtcache");
291 }
292
293
294 /**
295  * Shutdown datacache subsystem.
296  */
297 void
298 GDS_DATACACHE_done ()
299 {
300   if (NULL != datacache)
301   {
302     GNUNET_DATACACHE_destroy (datacache);
303     datacache = NULL;
304   }
305 }
306
307
308 /* end of gnunet-service-dht_datacache.c */