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