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 LOG(GNUNET_ERROR_TYPE_DEBUG, "Reconnect task executed\n");
208 h->r_task = GNUNET_SCHEDULER_NO_TASK;
213 * Connect to the PEERSTORE service.
215 * @return NULL on error
217 struct GNUNET_PEERSTORE_Handle *
218 GNUNET_PEERSTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
220 struct GNUNET_CLIENT_Connection *client;
221 struct GNUNET_PEERSTORE_Handle *h;
223 client = GNUNET_CLIENT_connect ("peerstore", cfg);
226 h = GNUNET_new (struct GNUNET_PEERSTORE_Handle);
229 LOG(GNUNET_ERROR_TYPE_DEBUG, "New connection created\n");
234 * Disconnect from the PEERSTORE service
235 * Do not call in case of pending requests
237 * @param h handle to disconnect
240 GNUNET_PEERSTORE_disconnect(struct GNUNET_PEERSTORE_Handle *h)
242 struct GNUNET_PEERSTORE_StoreContext *sc;
243 struct GNUNET_PEERSTORE_RequestContext *rc;
245 while (NULL != (sc = h->sc_head))
247 GNUNET_break (GNUNET_YES == sc->request_transmitted);
248 sc->request_transmitted = GNUNET_NO;
249 GNUNET_PEERSTORE_store_cancel(sc);
251 while (NULL != (rc = h->rc_head))
253 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
254 if (NULL != rc->cont)
255 rc->cont (rc->cont_cls, _("aborted due to explicit disconnect request"));
260 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
263 if (NULL != h->client)
265 GNUNET_CLIENT_disconnect (h->client);
268 if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
270 GNUNET_SCHEDULER_cancel (h->r_task);
271 h->r_task = GNUNET_SCHEDULER_NO_TASK;
274 LOG(GNUNET_ERROR_TYPE_DEBUG, "Disconnected, BYE!\n");
278 * Close the existing connection to PEERSTORE and reconnect.
280 * @param h handle to the service
283 reconnect (struct GNUNET_PEERSTORE_Handle *h)
285 LOG(GNUNET_ERROR_TYPE_DEBUG, "Reconnecting...\n");
286 if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
288 GNUNET_SCHEDULER_cancel (h->r_task);
289 h->r_task = GNUNET_SCHEDULER_NO_TASK;
293 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
296 if (NULL != h->client)
298 GNUNET_CLIENT_disconnect (h->client);
301 h->in_receive = GNUNET_NO;
302 h->client = GNUNET_CLIENT_connect ("peerstore", h->cfg);
303 if (NULL == h->client)
306 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
310 trigger_transmit (h);
314 * Transmit the request at the head of the transmission queue
315 * and trigger continuation (if any).
317 * @param cls the 'struct GNUNET_PEERSTORE_Handle' (with the queue)
318 * @param size size of the buffer (0 on error)
319 * @param buf where to copy the message
320 * @return number of bytes copied to buf
323 do_transmit (void *cls, size_t size, void *buf)
325 struct GNUNET_PEERSTORE_Handle *h = cls;
326 struct GNUNET_PEERSTORE_RequestContext *rc = h->rc_head;
331 return 0; /* request was canceled in the meantime */
334 /* peerstore service died */
335 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
336 "Failed to transmit message to `%s' service.\n", "PEERSTORE");
337 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
339 if (NULL != rc->cont)
340 rc->cont (rc->cont_cls, _("failed to transmit request (service down?)"));
347 /* change in head of queue (i.e. cancel + add), try again */
348 trigger_transmit (h);
351 LOG (GNUNET_ERROR_TYPE_DEBUG,
352 "Transmitting request of size %u to `%s' service.\n", ret, "PEERSTORE");
353 memcpy (buf, &rc[1], ret);
354 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
355 trigger_transmit (h);
356 if (NULL != rc->cont)
357 rc->cont (rc->cont_cls, NULL);
363 * Check if we have a request pending in the transmission queue and are
364 * able to transmit it right now. If so, schedule transmission.
366 * @param h handle to the service
369 trigger_transmit (struct GNUNET_PEERSTORE_Handle *h)
371 struct GNUNET_PEERSTORE_RequestContext *rc;
373 if (NULL == (rc = h->rc_head))
374 return; /* no requests queued */
376 return; /* request already pending */
377 if (NULL == h->client)
379 /* disconnected, try to reconnect */
384 GNUNET_CLIENT_notify_transmit_ready (h->client, rc->size,
385 GNUNET_TIME_UNIT_FOREVER_REL,
390 /******************************************************************************/
391 /******************* ADD FUNCTIONS *********************/
392 /******************************************************************************/
395 * Cancel a store request
397 * @param sc Store request context
400 GNUNET_PEERSTORE_store_cancel (struct GNUNET_PEERSTORE_StoreContext *sc)
402 struct GNUNET_PEERSTORE_Handle *h;
406 if (GNUNET_YES == sc->request_transmitted)
407 return; /* need to finish processing */
408 GNUNET_CONTAINER_DLL_remove (h->sc_head,
413 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, sc->rc);
414 GNUNET_free (sc->rc);
420 * Function called with server response message
421 * after a store operation is requested
423 * @param cls a 'struct GNUNET_PEERSTORE_Handle'
424 * @param msg message received, NULL on timeout or fatal error
427 store_receive(void *cls, const struct GNUNET_MessageHeader *msg)
429 struct GNUNET_PEERSTORE_Handle *h = cls;
430 struct GNUNET_PEERSTORE_StoreContext *sc = h->sc_head;
431 GNUNET_PEERSTORE_Continuation cont;
433 uint16_t response_type;
434 uint16_t response_size;
435 struct StoreResponseMessage *srm;
436 int malformed = GNUNET_NO;
439 h->in_receive = GNUNET_NO;
442 /* didn't expect a response, reconnect */
447 cont_cls = sc->cont_cls;
448 sc->request_transmitted = GNUNET_NO;
449 //cancel the request since we only need one response
450 GNUNET_PEERSTORE_store_cancel(sc);
453 LOG(GNUNET_ERROR_TYPE_ERROR, "`PEERSTORE' service died\n");
457 _("Failed to receive response from `PEERSTORE' service."));
460 response_type = ntohs(msg->type);
461 response_size = ntohs(msg->size);
462 if(GNUNET_MESSAGE_TYPE_PEERSTORE_STORE_RESULT != response_type)
464 LOG(GNUNET_ERROR_TYPE_ERROR, "Received an unexpected response type: %lu to store request\n", response_type);
468 _("Received an unexpected response from `PEERSTORE' service."));
471 if(response_size < sizeof(struct StoreResponseMessage))
473 malformed = GNUNET_YES;
477 srm = (struct StoreResponseMessage *)msg;
478 if(sizeof(struct StoreResponseMessage) + ntohs(srm->emsg_size) != response_size)
479 malformed = GNUNET_YES;
481 if(GNUNET_YES == malformed)
483 LOG(GNUNET_ERROR_TYPE_ERROR, "Received a malformed response from `PEERSTORE' service.\n");
487 _("Received a malformed response from `PEERSTORE' service."));
490 LOG(GNUNET_ERROR_TYPE_DEBUG, "Received a response of type %lu from server\n", response_type);
492 if ( (GNUNET_NO == h->in_receive) && (NULL != h->sc_head) )
494 LOG(GNUNET_ERROR_TYPE_DEBUG,
495 "A store request was sent but response not received, receiving now.\n");
496 h->in_receive = GNUNET_YES;
497 GNUNET_CLIENT_receive (h->client,
500 GNUNET_TIME_UNIT_FOREVER_REL);
504 LOG(GNUNET_ERROR_TYPE_DEBUG, "Calling continuation of store request\n");
505 srm = (struct StoreResponseMessage *)msg;
507 if(GNUNET_NO == ntohs(srm->success))
509 emsg = GNUNET_malloc(ntohs(srm->emsg_size));
510 memcpy(emsg, &srm[1], ntohs(srm->emsg_size));
512 cont(cont_cls, emsg);
517 * Called after store request is sent
518 * Waits for response from service
520 * @param cls a 'struct GNUNET_PEERSTORE_StoreContext'
521 * @parma emsg error message (or NULL)
523 void store_trigger_receive(void *cls, const char *emsg)
525 struct GNUNET_PEERSTORE_StoreContext *sc = cls;
526 struct GNUNET_PEERSTORE_Handle *h = sc->h;
527 GNUNET_PEERSTORE_Continuation cont;
534 cont_cls = sc->cont_cls;
535 GNUNET_PEERSTORE_store_cancel (sc);
538 cont (cont_cls, emsg);
541 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
543 sc->request_transmitted = GNUNET_YES;
544 if (GNUNET_NO == h->in_receive)
546 h->in_receive = GNUNET_YES;
547 GNUNET_CLIENT_receive (h->client,
550 GNUNET_TIME_UNIT_FOREVER_REL);
555 * Store a new entry in the PEERSTORE
557 * @param h Handle to the PEERSTORE service
558 * @param peer Peer Identity
559 * @param sub_system name of the sub system
560 * @param value entry value BLOB
561 * @param size size of 'value'
562 * @param lifetime relative time after which the entry is (possibly) deleted
563 * @param cont Continuation function after the store request is processed
564 * @param cont_cls Closure for 'cont'
566 struct GNUNET_PEERSTORE_StoreContext *
567 GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h,
568 const struct GNUNET_PeerIdentity *peer,
569 const char *sub_system,
572 struct GNUNET_TIME_Relative lifetime,
573 GNUNET_PEERSTORE_Continuation cont,
576 struct GNUNET_PEERSTORE_RequestContext *rc;
577 struct StoreRequestMessage *entry;
578 struct GNUNET_PEERSTORE_StoreContext *sc;
581 size_t sub_system_size;
584 LOG (GNUNET_ERROR_TYPE_DEBUG,
585 "Storing value (size: %lu) for subsytem `%s' and peer `%s'\n",
586 size, sub_system, GNUNET_i2s (peer));
587 sub_system_size = strlen(sub_system) + 1;
588 request_size = sizeof(struct StoreRequestMessage) + sub_system_size + size;
589 rc = GNUNET_malloc(sizeof(struct GNUNET_PEERSTORE_RequestContext) + request_size);
591 rc->size = request_size;
592 entry = (struct StoreRequestMessage *)&rc[1];
593 entry->header.size = htons(request_size);
594 entry->header.type = htons(GNUNET_MESSAGE_TYPE_PEERSTORE_STORE);
596 entry->sub_system_size = htons(sub_system_size);
597 entry->value_size = htons(size);
598 entry->lifetime = lifetime;
599 ss = (char *)&entry[1];
600 memcpy(ss, sub_system, sub_system_size);
601 val = ss + sub_system_size;
602 memcpy(val, value, size);
603 sc = GNUNET_new(struct GNUNET_PEERSTORE_StoreContext);
605 sc->cont_cls = cont_cls;
608 sc->request_transmitted = GNUNET_NO;
609 rc->cont = &store_trigger_receive;
611 GNUNET_CONTAINER_DLL_insert_tail(h->rc_head, h->rc_tail, rc);
612 GNUNET_CONTAINER_DLL_insert_tail(h->sc_head, h->sc_tail, sc);
613 trigger_transmit (h);
619 /* end of peerstore_api.c */