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