2 This file is part of GNUnet.
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.
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.
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.
22 * @file peerstore/peerstore_api.c
23 * @brief API for peerstore
24 * @author Omar Tarabai
27 #include "gnunet_util_lib.h"
28 #include "peerstore.h"
30 #define LOG(kind,...) GNUNET_log_from (kind, "peerstore-api",__VA_ARGS__)
32 /******************************************************************************/
33 /************************ DATA STRUCTURES ****************************/
34 /******************************************************************************/
37 * Handle to the PEERSTORE service.
39 struct GNUNET_PEERSTORE_Handle
45 const struct GNUNET_CONFIGURATION_Handle *cfg;
48 * Connection to the service.
50 struct GNUNET_CLIENT_Connection *client;
53 * Head of transmission queue.
55 struct GNUNET_PEERSTORE_RequestContext *rc_head;
58 * Tail of transmission queue.
60 struct GNUNET_PEERSTORE_RequestContext *rc_tail;
63 * Handle for the current transmission request, or NULL if none is pending.
65 struct GNUNET_CLIENT_TransmitHandle *th;
68 * Head of store requests DLL.
70 struct GNUNET_PEERSTORE_StoreContext *sc_head;
73 * Tail of store requests DLL.
75 struct GNUNET_PEERSTORE_StoreContext *sc_tail;
78 * ID for a reconnect task.
80 GNUNET_SCHEDULER_TaskIdentifier r_task;
83 * Are we now receiving?
90 * Entry in the transmission queue to PEERSTORE service.
93 struct GNUNET_PEERSTORE_RequestContext
96 * This is a linked list.
98 struct GNUNET_PEERSTORE_RequestContext *next;
101 * This is a linked list.
103 struct GNUNET_PEERSTORE_RequestContext *prev;
106 * Handle to the PEERSTORE service.
108 struct GNUNET_PEERSTORE_Handle *h;
111 * Function to call after request has been transmitted, or NULL.
113 GNUNET_PEERSTORE_Continuation cont;
116 * Closure for 'cont'.
121 * Number of bytes of the request message (follows after this struct).
128 * Context for a store request
131 struct GNUNET_PEERSTORE_StoreContext
136 struct GNUNET_PEERSTORE_StoreContext *next;
141 struct GNUNET_PEERSTORE_StoreContext *prev;
144 * Handle to the PEERSTORE service.
146 struct GNUNET_PEERSTORE_Handle *h;
149 * Our entry in the transmission queue.
151 struct GNUNET_PEERSTORE_RequestContext *rc;
154 * Function to call with store operation result
156 GNUNET_PEERSTORE_Continuation cont;
159 * Closure for 'cont'.
164 * Set to GNUNET_YES if we are currently receiving replies from the
167 int request_transmitted;
171 /******************************************************************************/
172 /*********************** DECLARATIONS *************************/
173 /******************************************************************************/
176 * Close the existing connection to PEERSTORE and reconnect.
178 * @param h handle to the service
181 reconnect (struct GNUNET_PEERSTORE_Handle *h);
184 * Check if we have a request pending in the transmission queue and are
185 * able to transmit it right now. If so, schedule transmission.
187 * @param h handle to the service
190 trigger_transmit (struct GNUNET_PEERSTORE_Handle *h);
192 /******************************************************************************/
193 /******************* CONNECTION FUNCTIONS *********************/
194 /******************************************************************************/
197 * Task scheduled to re-try connecting to the peerstore service.
199 * @param cls the 'struct GNUNET_PEERSTORE_Handle'
200 * @param tc scheduler context
203 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
205 struct GNUNET_PEERSTORE_Handle *h = cls;
207 h->r_task = GNUNET_SCHEDULER_NO_TASK;
212 * Connect to the PEERSTORE service.
214 * @return NULL on error
216 struct GNUNET_PEERSTORE_Handle *
217 GNUNET_PEERSTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
219 struct GNUNET_CLIENT_Connection *client;
220 struct GNUNET_PEERSTORE_Handle *h;
222 client = GNUNET_CLIENT_connect ("peerstore", cfg);
225 h = GNUNET_new (struct GNUNET_PEERSTORE_Handle);
232 * Disconnect from the PEERSTORE service
234 * @param h handle to disconnect
237 GNUNET_PEERSTORE_disconnect(struct GNUNET_PEERSTORE_Handle *h)
239 if (NULL != h->client)
241 GNUNET_CLIENT_disconnect (h->client);
248 * Close the existing connection to PEERSTORE and reconnect.
250 * @param h handle to the service
253 reconnect (struct GNUNET_PEERSTORE_Handle *h)
255 if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
257 GNUNET_SCHEDULER_cancel (h->r_task);
258 h->r_task = GNUNET_SCHEDULER_NO_TASK;
262 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
265 if (NULL != h->client)
267 GNUNET_CLIENT_disconnect (h->client);
270 h->client = GNUNET_CLIENT_connect ("peerstore", h->cfg);
271 if (NULL == h->client)
274 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
278 trigger_transmit (h);
282 * Transmit the request at the head of the transmission queue
283 * and trigger continuation (if any).
285 * @param cls the 'struct GNUNET_PEERSTORE_Handle' (with the queue)
286 * @param size size of the buffer (0 on error)
287 * @param buf where to copy the message
288 * @return number of bytes copied to buf
291 do_transmit (void *cls, size_t size, void *buf)
293 struct GNUNET_PEERSTORE_Handle *h = cls;
294 struct GNUNET_PEERSTORE_RequestContext *rc = h->rc_head;
299 return 0; /* request was canceled in the meantime */
302 /* peerstore service died */
303 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
304 "Failed to transmit message to `%s' service.\n", "PEERSTORE");
305 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
307 if (NULL != rc->cont)
308 rc->cont (rc->cont_cls, _("failed to transmit request (service down?)"));
315 /* change in head of queue (i.e. cancel + add), try again */
316 trigger_transmit (h);
319 LOG (GNUNET_ERROR_TYPE_DEBUG,
320 "Transmitting request of size %u to `%s' service.\n", ret, "PEERSTORE");
321 memcpy (buf, &rc[1], ret);
322 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
323 trigger_transmit (h);
324 if (NULL != rc->cont)
325 rc->cont (rc->cont_cls, NULL);
331 * Check if we have a request pending in the transmission queue and are
332 * able to transmit it right now. If so, schedule transmission.
334 * @param h handle to the service
337 trigger_transmit (struct GNUNET_PEERSTORE_Handle *h)
339 struct GNUNET_PEERSTORE_RequestContext *rc;
341 if (NULL == (rc = h->rc_head))
342 return; /* no requests queued */
344 return; /* request already pending */
345 if (NULL == h->client)
347 /* disconnected, try to reconnect */
352 GNUNET_CLIENT_notify_transmit_ready (h->client, rc->size,
353 GNUNET_TIME_UNIT_FOREVER_REL,
358 /******************************************************************************/
359 /******************* GENERAL FUNCTIONS *********************/
360 /******************************************************************************/
363 * Function called with server response message
364 * after a store operation is request
366 * @param cls a 'struct GNUNET_PEERSTORE_StoreContext'
367 * @param msg message received, NULL on timeout or fatal error
370 peerstore_handler (void *cls, const struct GNUNET_MessageHeader *msg)
372 struct GNUNET_PEERSTORE_Handle *h = cls;
373 struct GNUNET_PEERSTORE_StoreContext *sc;
374 struct StoreResponseMessage *srm;
375 uint16_t response_type;
376 uint16_t response_size;
379 h->in_receive = GNUNET_NO;
385 response_type = ntohs(msg->type);
386 response_size = ntohs(msg->size);
387 switch(response_type)
389 case GNUNET_MESSAGE_TYPE_PEERSTORE_STORE_RESULT:
390 GNUNET_assert(response_size >= sizeof(struct GNUNET_MessageHeader) + sizeof(struct StoreResponseMessage));
394 LOG(GNUNET_ERROR_TYPE_ERROR, "Received a response to a non-existent store request\n");
397 GNUNET_PEERSTORE_store_cancel(sc);
398 trigger_transmit (h);
399 if (NULL != h->sc_head)
401 h->in_receive = GNUNET_YES;
402 GNUNET_CLIENT_receive (h->client,
405 GNUNET_TIME_UNIT_FOREVER_REL);
409 srm = (struct StoreResponseMessage *)&msg[1];
411 if(GNUNET_NO == ntohs(srm->success))
413 emsg = GNUNET_malloc(ntohs(srm->emsg_size));
414 memcpy(emsg, &srm[1], ntohs(srm->emsg_size));
416 sc->cont(sc->cont_cls, emsg);
423 /******************************************************************************/
424 /******************* ADD FUNCTIONS *********************/
425 /******************************************************************************/
428 * Cancel a store request
430 * @param sc Store request context
433 GNUNET_PEERSTORE_store_cancel (struct GNUNET_PEERSTORE_StoreContext *sc)
435 struct GNUNET_PEERSTORE_Handle *h;
439 if (GNUNET_YES == sc->request_transmitted)
440 return; /* need to finish processing */
441 GNUNET_CONTAINER_DLL_remove (h->sc_head,
446 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, sc->rc);
447 GNUNET_free (sc->rc);
453 * Called after store request is sent
454 * Waits for response from service
456 * @param cls a 'struct GNUNET_PEERSTORE_StoreContext'
457 * @parma emsg error message (or NULL)
459 void store_receive_result(void *cls, const char *emsg)
461 struct GNUNET_PEERSTORE_StoreContext *sc = cls;
462 struct GNUNET_PEERSTORE_Handle *h = sc->h;
467 GNUNET_PEERSTORE_store_cancel (sc);
469 if (NULL != sc->cont)
470 sc->cont (sc->cont_cls, emsg);
473 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
475 sc->request_transmitted = GNUNET_YES;
476 if (GNUNET_NO == h->in_receive)
478 h->in_receive = GNUNET_YES;
479 GNUNET_CLIENT_receive (h->client,
482 GNUNET_TIME_UNIT_FOREVER_REL);
487 * Store a new entry in the PEERSTORE
489 * @param h Handle to the PEERSTORE service
490 * @param peer Peer Identity
491 * @param sub_system name of the sub system
492 * @param value entry value BLOB
493 * @param size size of 'value'
494 * @param lifetime relative time after which the entry is (possibly) deleted
495 * @param cont Continuation function after the store request is processed
496 * @param cont_cls Closure for 'cont'
498 struct GNUNET_PEERSTORE_StoreContext *
499 GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h,
500 const struct GNUNET_PeerIdentity *peer,
501 const char *sub_system,
504 struct GNUNET_TIME_Relative lifetime,
505 GNUNET_PEERSTORE_Continuation cont,
508 struct GNUNET_PEERSTORE_RequestContext *rc;
509 struct StoreRequestMessage *entry;
510 struct GNUNET_PEERSTORE_StoreContext *sc;
513 size_t sub_system_size;
516 LOG (GNUNET_ERROR_TYPE_DEBUG,
517 "Storing value (size: %lu) for subsytem `%s' and peer `%s'",
518 size, sub_system, GNUNET_i2s (peer));
519 sub_system_size = strlen(sub_system);
520 request_size = sizeof(struct StoreRequestMessage) + sub_system_size + size;
521 rc = GNUNET_malloc(sizeof(struct GNUNET_PEERSTORE_RequestContext) + request_size);
523 rc->size = request_size;
524 entry = (struct StoreRequestMessage *)&rc[1];
525 entry->header.size = htons(request_size);
526 entry->header.type = htons(GNUNET_MESSAGE_TYPE_PEERSTORE_STORE);
528 entry->sub_system_size = htons(sub_system_size);
529 entry->value_size = htons(size);
530 entry->lifetime = lifetime;
531 ss = (char *)&entry[1];
532 memcpy(ss, sub_system, sub_system_size);
533 val = ss + sub_system_size;
534 memcpy(val, value, size);
535 sc = GNUNET_new(struct GNUNET_PEERSTORE_StoreContext);
537 sc->cont_cls = cont_cls;
540 rc->cont = &store_receive_result;
542 GNUNET_CONTAINER_DLL_insert_tail(h->rc_head, h->rc_tail, rc);
543 GNUNET_CONTAINER_DLL_insert_tail(h->sc_head, h->sc_tail, sc);
544 trigger_transmit (h);
550 /* end of peerstore_api.c */