aboutsummaryrefslogtreecommitdiff
path: root/src/fs/gnunet-service-fs_lc.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-01-30 16:02:52 +0000
committerChristian Grothoff <christian@grothoff.org>2011-01-30 16:02:52 +0000
commitbc0e1c956bef848d2569e0c56ccbda13597418f7 (patch)
tree88d82a018890ed112c61f21fe2f38e2fe1edc89f /src/fs/gnunet-service-fs_lc.c
parentdee60c25690117fabb90b497dbe23378b3e00db1 (diff)
downloadgnunet-bc0e1c956bef848d2569e0c56ccbda13597418f7.tar.gz
gnunet-bc0e1c956bef848d2569e0c56ccbda13597418f7.zip
stuff
Diffstat (limited to 'src/fs/gnunet-service-fs_lc.c')
-rw-r--r--src/fs/gnunet-service-fs_lc.c420
1 files changed, 420 insertions, 0 deletions
diff --git a/src/fs/gnunet-service-fs_lc.c b/src/fs/gnunet-service-fs_lc.c
new file mode 100644
index 000000000..2113a4498
--- /dev/null
+++ b/src/fs/gnunet-service-fs_lc.c
@@ -0,0 +1,420 @@
1/*
2 This file is part of GNUnet.
3 (C) 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 fs/gnunet-service-fs_lc.c
23 * @brief API to handle 'connected peers'
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet-service-fs_lc.h"
29
30
31/**
32 * Doubly-linked list of requests we are performing
33 * on behalf of the same client.
34 */
35struct ClientRequest
36{
37
38 /**
39 * This is a doubly-linked list.
40 */
41 struct ClientRequest *next;
42
43 /**
44 * This is a doubly-linked list.
45 */
46 struct ClientRequest *prev;
47
48 /**
49 * Request this entry represents.
50 */
51 struct GSF_PendingRequest *pr;
52
53 /**
54 * Client list this request belongs to.
55 */
56 struct GSF_LocalClient *lc;
57
58};
59
60
61
62/**
63 * Replies to be transmitted to the client. The actual
64 * response message is allocated after this struct.
65 */
66struct ClientResponse
67{
68 /**
69 * This is a doubly-linked list.
70 */
71 struct ClientResponse *next;
72
73 /**
74 * This is a doubly-linked list.
75 */
76 struct ClientResponse *prev;
77
78 /**
79 * Client list entry this response belongs to.
80 */
81 struct GSF_LocalClient *lc;
82
83 /**
84 * Number of bytes in the response.
85 */
86 size_t msize;
87};
88
89
90
91/**
92 * A local client.
93 */
94struct GSF_LocalClient
95{
96
97 /**
98 * We keep clients in a DLL.
99 */
100 struct GSF_LocalClient *next;
101
102 /**
103 * We keep clients in a DLL.
104 */
105 struct GSF_LocalClient *prev;
106
107 /**
108 * ID of the client.
109 */
110 struct GNUNET_SERVER_Client *client;
111
112 /**
113 * Head of list of requests performed on behalf
114 * of this client right now.
115 */
116 struct ClientRequest *cr_head;
117
118 /**
119 * Tail of list of requests performed on behalf
120 * of this client right now.
121 */
122 struct ClientRequest *cr_tail;
123
124 /**
125 * Head of linked list of responses.
126 */
127 struct ClientResponse *res_head;
128
129 /**
130 * Tail of linked list of responses.
131 */
132 struct ClientResponse *res_tail;
133
134 /**
135 * Context for sending replies.
136 */
137 struct GNUNET_CONNECTION_TransmitHandle *th;
138
139};
140
141
142/**
143 * Head of linked list of our local clients.
144 */
145static struct GSF_LocalClient *client_head;
146
147
148/**
149 * Head of linked list of our local clients.
150 */
151static struct GSF_LocalClient *client_tail;
152
153
154/**
155 * Look up a local client record or create one if it
156 * doesn't exist yet.
157 *
158 * @param client handle of the client
159 * @return handle to local client entry
160 */
161struct GSF_LocalClient *
162GSF_local_client_lookup_ (struct GNUNET_SERVER_Client *client)
163{
164 struct GSF_LocalClient *pos;
165
166 pos = client_head;
167 while ( (pos != NULL) &&
168 (pos->client != client) )
169 pos = pos->next;
170 if (pos != NULL)
171 return pos;
172 pos = GNUNET_malloc (sizeof (struct GSF_LocalClient));
173 pos->client = client;
174 GNUNET_CONTAINER_DLL_insert (client_head,
175 client_tail,
176 pos);
177 return pos;
178}
179
180
181/**
182 * Handle START_SEARCH-message (search request from local client).
183 *
184 * @param cls closure
185 * @param client identification of the client
186 * @param message the actual message
187 */
188void
189GSF_local_client_start_search_handler_ (void *cls,
190 struct GNUNET_SERVER_Client *client,
191 const struct GNUNET_MessageHeader *message)
192{
193 static GNUNET_HashCode all_zeros;
194 const struct SearchMessage *sm;
195 struct GSF_LocalClient *lc;
196 struct ClientRequest *cr;
197 struct GSF_PendingRequest *pr;
198 uint16_t msize;
199 unsigned int sc;
200 enum GNUNET_BLOCK_Type type;
201 enum GSF_PendingRequestOptions options;
202
203 msize = ntohs (message->size);
204 if ( (msize < sizeof (struct SearchMessage)) ||
205 (0 != (msize - sizeof (struct SearchMessage)) % sizeof (GNUNET_HashCode)) )
206 {
207 GNUNET_break (0);
208 GNUNET_SERVER_receive_done (client,
209 GNUNET_SYSERR);
210 return;
211 }
212 GNUNET_STATISTICS_update (stats,
213 gettext_noop ("# client searches received"),
214 1,
215 GNUNET_NO);
216 sc = (msize - sizeof (struct SearchMessage)) / sizeof (GNUNET_HashCode);
217 sm = (const struct SearchMessage*) message;
218 type = ntohl (sm->type);
219#if DEBUG_FS
220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
221 "Received request for `%s' of type %u from local client\n",
222 GNUNET_h2s (&sm->query),
223 (unsigned int) type);
224#endif
225 lc = GSF_local_client_lookup_ (client);
226
227
228 /* detect duplicate KBLOCK requests */
229 if ( (type == GNUNET_BLOCK_TYPE_FS_KBLOCK) ||
230 (type == GNUNET_BLOCK_TYPE_FS_NBLOCK) ||
231 (type == GNUNET_BLOCK_TYPE_ANY) )
232 {
233 cr = lc->cr_head;
234 while ( (cl != NULL) &&
235 ( (0 != memcmp (GSF_pending_request_get_query_ (cr->pr),
236 &sm->query,
237 sizeof (GNUNET_HashCode))) ||
238 (GSF_pending_request_get_type_ (cr->pr) != type) ) )
239 cr = cr->next;
240 if (crl != NULL)
241 {
242#if DEBUG_FS
243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
244 "Have existing request, merging content-seen lists.\n");
245#endif
246 GSF_pending_request_update_ (cr->pr,
247 &sm[1],
248 sc);
249 GNUNET_STATISTICS_update (stats,
250 gettext_noop ("# client searches updated (merged content seen list)"),
251 1,
252 GNUNET_NO);
253 GNUNET_SERVER_receive_done (client,
254 GNUNET_OK);
255 return;
256 }
257 }
258
259 GNUNET_STATISTICS_update (stats,
260 gettext_noop ("# client searches active"),
261 1,
262 GNUNET_NO);
263 cr = GNUNET_malloc (sizeof (struct ClientRequest));
264 cr->lc = lc;
265 GNUNET_CONTAINER_DLL_insert (lc->cr_head,
266 lc->cr_tail,
267 cr);
268 options = GSF_PRO_LOCAL_REQUEST;
269 if (0 != (1 & ntohl (sm->options)))
270 options |= GSF_PRO_LOCAL_ONLY;
271 cr->pr = GSF_pending_request_create (options,
272
273 type,
274 &sm->query,
275 (type == GNUNET_BLOCK_TYPE_SBLOCK)
276 ? &sm->target /* namespace */
277 : NULL,
278 (0 != memcmp (&sm->target,
279 &all_zeros,
280 sizeof (GNUNET_HashCode)))
281 ? &sm->target,
282 : NULL,
283 NULL /* bf */, 0 /* mingle */,
284 ntohl (sm->anonymity_level),
285 0 /* priority */,
286 &sm[1], sc,
287 &client_response_handler,
288 cr);
289 // FIXME: start local processing and/or P2P processing?
290}
291
292
293/**
294 * Transmit the given message by copying it to the target buffer
295 * "buf". "buf" will be NULL and "size" zero if the socket was closed
296 * for writing in the meantime. In that case, do nothing
297 * (the disconnect or shutdown handler will take care of the rest).
298 * If we were able to transmit messages and there are still more
299 * pending, ask core again for further calls to this function.
300 *
301 * @param cls closure, pointer to the 'struct GSF_LocalClient'
302 * @param size number of bytes available in buf
303 * @param buf where the callee should write the message
304 * @return number of bytes written to buf
305 */
306static size_t
307transmit_to_client (void *cls,
308 size_t size,
309 void *buf)
310{
311 struct GSF_LocalClient *lc = cls;
312 char *cbuf = buf;
313 struct ClientResponse *res;
314 size_t msize;
315
316 cl->th = NULL;
317 if (NULL == buf)
318 return 0;
319 msize = 0;
320 while ( (NULL != (res = lc->res_head) ) &&
321 (res->msize <= size) )
322 {
323 memcpy (&cbuf[msize], &res[1], res->msize);
324 msize += res->msize;
325 size -= res->msize;
326 GNUNET_CONTAINER_DLL_remove (cl->res_head,
327 cl->res_tail,
328 res);
329 GNUNET_free (res);
330 }
331 if (NULL != res)
332 lc->th = GNUNET_SERVER_notify_transmit_ready (lc->client,
333 res->msize,
334 GNUNET_TIME_UNIT_FOREVER_REL,
335 &transmit_to_client,
336 lc);
337 return msize;
338}
339
340
341/**
342 * Transmit a message to the given local client as soon as possible.
343 * If the client disconnects before transmission, the message is
344 * simply discarded.
345 *
346 * @param lc recipient
347 * @param msg message to transmit to client
348 */
349void
350GSF_local_client_transmit_ (struct GSF_LocalClient *lc,
351 const struct GNUNET_MessageHeader *msg)
352{
353 struct ClientResponse *res;
354 size_t msize;
355
356 msize = ntohs (msg->size);
357 res = GNUNET_malloc (sizeof (struct ClientResponse) + msize);
358 res->lc = lc;
359 res->msize = msize;
360 GNUNET_CONTAINER_DLL_insert_tail (lc->res_head,
361 lc->res_tail,
362 res);
363 if (NULL == lc->tc)
364 lc->tc = GNUNET_CLIENT_notify_transmit_ready (lc->client,
365 msize,
366 GNUNET_TIME_UNIT_FOREVER_REL,
367 GNUNET_NO,
368 &transmit_to_client,
369 lc);
370}
371
372
373/**
374 * A client disconnected from us. Tear down the local client
375 * record.
376 *
377 * @param cls unused
378 * @param client handle of the client
379 */
380void
381GSF_client_disconnect_handler_ (void *cls,
382 const struct GNUNET_SERVER_Client *client)
383{
384 struct GSF_LocalClient *pos;
385 struct DisconnectCallback *dc;
386 struct ClientRequest *cr;
387 struct ClientResponse *res;
388
389 pos = client_head;
390 while ( (pos != NULL) &&
391 (pos->client != client) )
392 pos = pos->next;
393 if (pos == NULL)
394 return pos;
395 while (NULL != (cr = pos->cr_head))
396 {
397 GNUNET_CONTAINER_DLL_remove (pos->cr_head,
398 pos->cr_tail,
399 cr);
400 GSF_pending_request_cancel_ (cr->pr);
401 GNUNET_free (cr);
402 }
403 while (NULL != (res = pos->res_head))
404 {
405 GNUNET_CONTAINER_DLL_remove (pos->res_head,
406 pos->res_tail,
407 res);
408 GNUNET_free (res);
409 }
410 if (pos->th != NULL)
411 {
412 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
413 pos->th = NULL;
414 }
415 GSF_handle_local_client_disconnect_ (pos);
416 GNUNET_free (pos);
417}
418
419
420/* end of gnunet-service-fs_lc.c */