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
236 * @param h handle to disconnect
239 GNUNET_PEERSTORE_disconnect(struct GNUNET_PEERSTORE_Handle *h)
241 struct GNUNET_PEERSTORE_StoreContext *sc;
242 struct GNUNET_PEERSTORE_RequestContext *rc;
244 while (NULL != (sc = h->sc_head))
246 GNUNET_break (GNUNET_YES == sc->request_transmitted);
247 sc->request_transmitted = GNUNET_NO;
248 GNUNET_PEERSTORE_store_cancel(sc);
250 while (NULL != (rc = h->rc_head))
252 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
253 if (NULL != rc->cont)
254 rc->cont (rc->cont_cls, _("aborted due to explicit disconnect request"));
259 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
262 if (NULL != h->client)
264 GNUNET_CLIENT_disconnect (h->client);
267 if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
269 GNUNET_SCHEDULER_cancel (h->r_task);
270 h->r_task = GNUNET_SCHEDULER_NO_TASK;
273 LOG(GNUNET_ERROR_TYPE_DEBUG, "Disconnected, BYE!\n");
277 * Close the existing connection to PEERSTORE and reconnect.
279 * @param h handle to the service
282 reconnect (struct GNUNET_PEERSTORE_Handle *h)
284 LOG(GNUNET_ERROR_TYPE_DEBUG, "Reconnecting...\n");
285 if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
287 GNUNET_SCHEDULER_cancel (h->r_task);
288 h->r_task = GNUNET_SCHEDULER_NO_TASK;
292 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
295 if (NULL != h->client)
297 GNUNET_CLIENT_disconnect (h->client);
300 h->in_receive = GNUNET_NO;
301 h->client = GNUNET_CLIENT_connect ("peerstore", h->cfg);
302 if (NULL == h->client)
305 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
309 trigger_transmit (h);
313 * Transmit the request at the head of the transmission queue
314 * and trigger continuation (if any).
316 * @param cls the 'struct GNUNET_PEERSTORE_Handle' (with the queue)
317 * @param size size of the buffer (0 on error)
318 * @param buf where to copy the message
319 * @return number of bytes copied to buf
322 do_transmit (void *cls, size_t size, void *buf)
324 struct GNUNET_PEERSTORE_Handle *h = cls;
325 struct GNUNET_PEERSTORE_RequestContext *rc = h->rc_head;
330 return 0; /* request was canceled in the meantime */
333 /* peerstore service died */
334 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
335 "Failed to transmit message to `%s' service.\n", "PEERSTORE");
336 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
338 if (NULL != rc->cont)
339 rc->cont (rc->cont_cls, _("failed to transmit request (service down?)"));
346 /* change in head of queue (i.e. cancel + add), try again */
347 trigger_transmit (h);
350 LOG (GNUNET_ERROR_TYPE_DEBUG,
351 "Transmitting request of size %u to `%s' service.\n", ret, "PEERSTORE");
352 memcpy (buf, &rc[1], ret);
353 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
354 trigger_transmit (h);
355 if (NULL != rc->cont)
356 rc->cont (rc->cont_cls, NULL);
362 * Check if we have a request pending in the transmission queue and are
363 * able to transmit it right now. If so, schedule transmission.
365 * @param h handle to the service
368 trigger_transmit (struct GNUNET_PEERSTORE_Handle *h)
370 struct GNUNET_PEERSTORE_RequestContext *rc;
372 if (NULL == (rc = h->rc_head))
373 return; /* no requests queued */
375 return; /* request already pending */
376 if (NULL == h->client)
378 /* disconnected, try to reconnect */
383 GNUNET_CLIENT_notify_transmit_ready (h->client, rc->size,
384 GNUNET_TIME_UNIT_FOREVER_REL,
389 /******************************************************************************/
390 /******************* ADD FUNCTIONS *********************/
391 /******************************************************************************/
394 * Cancel a store request
396 * @param sc Store request context
399 GNUNET_PEERSTORE_store_cancel (struct GNUNET_PEERSTORE_StoreContext *sc)
401 struct GNUNET_PEERSTORE_Handle *h;
405 if (GNUNET_YES == sc->request_transmitted)
406 return; /* need to finish processing */
407 GNUNET_CONTAINER_DLL_remove (h->sc_head,
412 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, sc->rc);
413 GNUNET_free (sc->rc);
419 * Function called with server response message
420 * after a store operation is requested
422 * @param cls a 'struct GNUNET_PEERSTORE_Handle'
423 * @param msg message received, NULL on timeout or fatal error
426 store_receive(void *cls, const struct GNUNET_MessageHeader *msg)
428 struct GNUNET_PEERSTORE_Handle *h = cls;
429 struct GNUNET_PEERSTORE_StoreContext *sc = h->sc_head;
430 GNUNET_PEERSTORE_Continuation cont;
432 uint16_t response_type;
433 uint16_t response_size;
434 struct StoreResponseMessage *srm;
435 int malformed = GNUNET_NO;
438 h->in_receive = GNUNET_NO;
441 /* didn't expect a response, reconnect */
446 cont_cls = sc->cont_cls;
447 sc->request_transmitted = GNUNET_NO;
448 //cancel the request since we only need one response
449 GNUNET_PEERSTORE_store_cancel(sc);
452 LOG(GNUNET_ERROR_TYPE_ERROR, "`PEERSTORE' service died\n");
456 _("Failed to receive response from `PEERSTORE' service."));
459 response_type = ntohs(msg->type);
460 response_size = ntohs(msg->size);
461 if(GNUNET_MESSAGE_TYPE_PEERSTORE_STORE_RESULT != response_type)
463 LOG(GNUNET_ERROR_TYPE_ERROR, "Received an unexpected response type: %lu to store request\n", response_type);
467 _("Received an unexpected response from `PEERSTORE' service."));
470 if(response_size < sizeof(struct StoreResponseMessage))
472 malformed = GNUNET_YES;
476 srm = (struct StoreResponseMessage *)msg;
477 if(sizeof(struct StoreResponseMessage) + ntohs(srm->emsg_size) != response_size)
478 malformed = GNUNET_YES;
480 if(GNUNET_YES == malformed)
482 LOG(GNUNET_ERROR_TYPE_ERROR, "Received a malformed response from `PEERSTORE' service.\n");
486 _("Received a malformed response from `PEERSTORE' service."));
489 LOG(GNUNET_ERROR_TYPE_DEBUG, "Received a response of type %lu from server\n", response_type);
491 if ( (GNUNET_NO == h->in_receive) && (NULL != h->sc_head) )
493 LOG(GNUNET_ERROR_TYPE_DEBUG,
494 "A store request was sent but response not received, receiving now.\n");
495 h->in_receive = GNUNET_YES;
496 GNUNET_CLIENT_receive (h->client,
499 GNUNET_TIME_UNIT_FOREVER_REL);
503 LOG(GNUNET_ERROR_TYPE_DEBUG, "Calling continuation of store request\n");
504 srm = (struct StoreResponseMessage *)msg;
506 if(GNUNET_NO == ntohs(srm->success))
508 emsg = GNUNET_malloc(ntohs(srm->emsg_size));
509 memcpy(emsg, &srm[1], ntohs(srm->emsg_size));
511 cont(cont_cls, emsg);
516 * Called after store request is sent
517 * Waits for response from service
519 * @param cls a 'struct GNUNET_PEERSTORE_StoreContext'
520 * @parma emsg error message (or NULL)
522 void store_trigger_receive(void *cls, const char *emsg)
524 struct GNUNET_PEERSTORE_StoreContext *sc = cls;
525 struct GNUNET_PEERSTORE_Handle *h = sc->h;
526 GNUNET_PEERSTORE_Continuation cont;
533 cont_cls = sc->cont_cls;
534 GNUNET_PEERSTORE_store_cancel (sc);
536 if (NULL != sc->cont)
537 sc->cont (sc->cont_cls, emsg);
540 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
542 sc->request_transmitted = GNUNET_YES;
543 if (GNUNET_NO == h->in_receive)
545 h->in_receive = GNUNET_YES;
546 GNUNET_CLIENT_receive (h->client,
549 GNUNET_TIME_UNIT_FOREVER_REL);
554 * Store a new entry in the PEERSTORE
556 * @param h Handle to the PEERSTORE service
557 * @param peer Peer Identity
558 * @param sub_system name of the sub system
559 * @param value entry value BLOB
560 * @param size size of 'value'
561 * @param lifetime relative time after which the entry is (possibly) deleted
562 * @param cont Continuation function after the store request is processed
563 * @param cont_cls Closure for 'cont'
565 struct GNUNET_PEERSTORE_StoreContext *
566 GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h,
567 const struct GNUNET_PeerIdentity *peer,
568 const char *sub_system,
571 struct GNUNET_TIME_Relative lifetime,
572 GNUNET_PEERSTORE_Continuation cont,
575 struct GNUNET_PEERSTORE_RequestContext *rc;
576 struct StoreRequestMessage *entry;
577 struct GNUNET_PEERSTORE_StoreContext *sc;
580 size_t sub_system_size;
583 LOG (GNUNET_ERROR_TYPE_DEBUG,
584 "Storing value (size: %lu) for subsytem `%s' and peer `%s'\n",
585 size, sub_system, GNUNET_i2s (peer));
586 sub_system_size = strlen(sub_system);
587 request_size = sizeof(struct StoreRequestMessage) + sub_system_size + size;
588 rc = GNUNET_malloc(sizeof(struct GNUNET_PEERSTORE_RequestContext) + request_size);
590 rc->size = request_size;
591 entry = (struct StoreRequestMessage *)&rc[1];
592 entry->header.size = htons(request_size);
593 entry->header.type = htons(GNUNET_MESSAGE_TYPE_PEERSTORE_STORE);
595 entry->sub_system_size = htons(sub_system_size);
596 entry->value_size = htons(size);
597 entry->lifetime = lifetime;
598 ss = (char *)&entry[1];
599 memcpy(ss, sub_system, sub_system_size);
600 val = ss + sub_system_size;
601 memcpy(val, value, size);
602 sc = GNUNET_new(struct GNUNET_PEERSTORE_StoreContext);
604 sc->cont_cls = cont_cls;
607 sc->request_transmitted = GNUNET_NO;
608 rc->cont = &store_trigger_receive;
610 GNUNET_CONTAINER_DLL_insert_tail(h->rc_head, h->rc_tail, rc);
611 GNUNET_CONTAINER_DLL_insert_tail(h->sc_head, h->sc_tail, sc);
612 trigger_transmit (h);
618 /* end of peerstore_api.c */