docu
[oweals/gnunet.git] / src / dht / gnunet-service-dht_datacache.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011 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 dht/gnunet-service-dht_datacache.c
23  * @brief GNUnet DHT service's datacache integration
24  * @author Christian Grothoff
25  * @author Nathan Evans
26  */
27 #include "platform.h"
28 #include "gnunet_datacache_lib.h"
29 #include "gnunet-service-dht_clients.h"
30 #include "gnunet-service-dht_datacache.h"
31 #include "gnunet-service-dht_routing.h"
32 #include "gnunet-service-dht.h"
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 '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 '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, size_t data_size,
59                           const void *data)
60 {
61   if (NULL == datacache)
62   {
63     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
64                 _("%s request received, but have no datacache!\n"), "PUT");
65     return;
66   }
67   if (data_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
68   {
69     GNUNET_break (0);
70     return;
71   }
72   /* Put size is actual data size plus struct overhead plus path length (if any) */
73   GNUNET_STATISTICS_update (GDS_stats,
74                             gettext_noop ("# ITEMS stored in datacache"), 1,
75                             GNUNET_NO);
76   (void) GNUNET_DATACACHE_put (datacache, key, 
77                                data_size, data, type,
78                                expiration, put_path_length, put_path);
79 }
80
81
82 /**
83  * Context containing information about a GET request.
84  */
85 struct GetRequestContext
86 {
87   /**
88    * extended query (see gnunet_block_lib.h).
89    */
90   const void *xquery;
91
92   /**
93    * Bloomfilter to filter out duplicate replies (updated)
94    */
95   struct GNUNET_CONTAINER_BloomFilter **reply_bf;
96
97   /**
98    * The key this request was about
99    */
100   struct GNUNET_HashCode key;
101
102   /**
103    * Number of bytes in xquery.
104    */
105   size_t xquery_size;
106
107   /**
108    * Mutator value for the reply_bf, see gnunet_block_lib.h
109    */
110   uint32_t reply_bf_mutator;
111
112   /**
113    * Return value to give back.
114    */
115   enum GNUNET_BLOCK_EvaluationResult eval;
116 };
117
118
119 /**
120  * Iterator for local get request results,
121  *
122  * @param cls closure for iterator, a DatacacheGetContext
123  * @param exp when does this value expire?
124  * @param key the key this data is stored under
125  * @param size the size of the data identified by key
126  * @param data the actual data
127  * @param type the type of the data
128  * @param put_path_length number of peers in 'put_path'
129  * @param put_path path the reply took on put
130  * @return GNUNET_OK to continue iteration, anything else
131  * to stop iteration.
132  */
133 static int
134 datacache_get_iterator (void *cls, 
135                         const struct GNUNET_HashCode * key, size_t size,
136                         const char *data, enum GNUNET_BLOCK_Type type,
137                         struct GNUNET_TIME_Absolute exp,
138                         unsigned int put_path_length,
139                         const struct GNUNET_PeerIdentity *put_path)
140 {
141   struct GetRequestContext *ctx = cls;
142   enum GNUNET_BLOCK_EvaluationResult eval;
143
144   eval =
145       GNUNET_BLOCK_evaluate (GDS_block_context, type, key, ctx->reply_bf,
146                              ctx->reply_bf_mutator, ctx->xquery,
147                              ctx->xquery_size, data, size);
148   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
149               "Found reply for query %s in datacache, evaluation result is %d\n",
150               GNUNET_h2s (key), (int) eval);
151   ctx->eval = eval;
152   switch (eval)
153   {
154   case GNUNET_BLOCK_EVALUATION_OK_LAST:
155   case GNUNET_BLOCK_EVALUATION_OK_MORE:
156     /* forward to local clients */
157     GNUNET_STATISTICS_update (GDS_stats,
158                               gettext_noop
159                               ("# Good RESULTS found in datacache"), 1,
160                               GNUNET_NO);
161     GDS_CLIENTS_handle_reply (exp, key, 0, NULL, put_path_length, put_path, type,
162                               size, data);
163     /* forward to other peers */
164     GDS_ROUTING_process (type, exp, key, put_path_length, put_path, 0, NULL, data,
165                          size);
166     break;
167   case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
168     GNUNET_STATISTICS_update (GDS_stats,
169                               gettext_noop
170                               ("# Duplicate RESULTS found in datacache"), 1,
171                               GNUNET_NO);
172     break;
173   case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
174     GNUNET_STATISTICS_update (GDS_stats,
175                               gettext_noop
176                               ("# Invalid RESULTS found in datacache"), 1,
177                               GNUNET_NO);
178     break;
179   case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
180     GNUNET_STATISTICS_update (GDS_stats,
181                               gettext_noop
182                               ("# Irrelevant RESULTS found in datacache"), 1,
183                               GNUNET_NO);
184     break;
185   case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
186     GNUNET_break (0);
187     break;
188   case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
189     GNUNET_break_op (0);
190     return GNUNET_SYSERR;
191   case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
192     GNUNET_STATISTICS_update (GDS_stats,
193                               gettext_noop
194                               ("# Unsupported RESULTS found in datacache"), 1,
195                               GNUNET_NO);
196     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
197                 _("Unsupported block type (%u) in local response!\n"), type);
198     break;
199   }
200   return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK;
201 }
202
203
204 /**
205  * Handle a GET request we've received from another peer.
206  *
207  * @param key the query
208  * @param type requested data type
209  * @param xquery extended query
210  * @param xquery_size number of bytes in xquery
211  * @param reply_bf where the reply bf is (to be) stored, possibly updated, can be NULL
212  * @param reply_bf_mutator mutation value for reply_bf
213  * @return evaluation result for the local replies
214  */
215 enum GNUNET_BLOCK_EvaluationResult
216 GDS_DATACACHE_handle_get (const struct GNUNET_HashCode * key,
217                           enum GNUNET_BLOCK_Type type, const void *xquery,
218                           size_t xquery_size,
219                           struct GNUNET_CONTAINER_BloomFilter **reply_bf,
220                           uint32_t reply_bf_mutator)
221 {
222   struct GetRequestContext ctx;
223
224   if (datacache == NULL)
225     return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
226   GNUNET_STATISTICS_update (GDS_stats,
227                             gettext_noop ("# GET requests given to datacache"),
228                             1, GNUNET_NO);
229   ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
230   ctx.key = *key;
231   ctx.xquery = xquery;
232   ctx.xquery_size = xquery_size;
233   ctx.reply_bf = reply_bf;
234   ctx.reply_bf_mutator = reply_bf_mutator;
235   (void) GNUNET_DATACACHE_get (datacache, key, type, &datacache_get_iterator,
236                                &ctx);
237   return ctx.eval;
238 }
239
240
241 /**
242  * Initialize datacache subsystem.
243  */
244 void
245 GDS_DATACACHE_init ()
246 {
247   datacache = GNUNET_DATACACHE_create (GDS_cfg, "dhtcache");
248 }
249
250
251 /**
252  * Shutdown datacache subsystem.
253  */
254 void
255 GDS_DATACACHE_done ()
256 {
257   if (datacache != NULL)
258   {
259     GNUNET_DATACACHE_destroy (datacache);
260     datacache = NULL;
261   }
262 }
263
264
265 /* end of gnunet-service-dht_datacache.c */