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 if (NULL != h->client)
243 GNUNET_CLIENT_disconnect (h->client);
247 LOG(GNUNET_ERROR_TYPE_DEBUG, "Disconnected, BYE!\n");
251 * Close the existing connection to PEERSTORE and reconnect.
253 * @param h handle to the service
256 reconnect (struct GNUNET_PEERSTORE_Handle *h)
258 LOG(GNUNET_ERROR_TYPE_DEBUG, "Reconnecting...\n");
259 if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
261 GNUNET_SCHEDULER_cancel (h->r_task);
262 h->r_task = GNUNET_SCHEDULER_NO_TASK;
266 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
269 if (NULL != h->client)
271 GNUNET_CLIENT_disconnect (h->client);
274 h->client = GNUNET_CLIENT_connect ("peerstore", h->cfg);
275 if (NULL == h->client)
278 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
282 trigger_transmit (h);
286 * Transmit the request at the head of the transmission queue
287 * and trigger continuation (if any).
289 * @param cls the 'struct GNUNET_PEERSTORE_Handle' (with the queue)
290 * @param size size of the buffer (0 on error)
291 * @param buf where to copy the message
292 * @return number of bytes copied to buf
295 do_transmit (void *cls, size_t size, void *buf)
297 struct GNUNET_PEERSTORE_Handle *h = cls;
298 struct GNUNET_PEERSTORE_RequestContext *rc = h->rc_head;
303 return 0; /* request was canceled in the meantime */
306 /* peerstore service died */
307 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
308 "Failed to transmit message to `%s' service.\n", "PEERSTORE");
309 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
311 if (NULL != rc->cont)
312 rc->cont (rc->cont_cls, _("failed to transmit request (service down?)"));
319 /* change in head of queue (i.e. cancel + add), try again */
320 trigger_transmit (h);
323 LOG (GNUNET_ERROR_TYPE_DEBUG,
324 "Transmitting request of size %u to `%s' service.\n", ret, "PEERSTORE");
325 memcpy (buf, &rc[1], ret);
326 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
327 trigger_transmit (h);
328 if (NULL != rc->cont)
329 rc->cont (rc->cont_cls, NULL);
335 * Check if we have a request pending in the transmission queue and are
336 * able to transmit it right now. If so, schedule transmission.
338 * @param h handle to the service
341 trigger_transmit (struct GNUNET_PEERSTORE_Handle *h)
343 struct GNUNET_PEERSTORE_RequestContext *rc;
345 if (NULL == (rc = h->rc_head))
346 return; /* no requests queued */
348 return; /* request already pending */
349 if (NULL == h->client)
351 /* disconnected, try to reconnect */
356 GNUNET_CLIENT_notify_transmit_ready (h->client, rc->size,
357 GNUNET_TIME_UNIT_FOREVER_REL,
362 /******************************************************************************/
363 /******************* GENERAL FUNCTIONS *********************/
364 /******************************************************************************/
367 * Function called with server response message
368 * after a store operation is request
370 * @param cls a 'struct GNUNET_PEERSTORE_StoreContext'
371 * @param msg message received, NULL on timeout or fatal error
374 peerstore_handler (void *cls, const struct GNUNET_MessageHeader *msg)
376 struct GNUNET_PEERSTORE_Handle *h = cls;
377 struct GNUNET_PEERSTORE_StoreContext *sc;
378 struct StoreResponseMessage *srm;
379 uint16_t response_type;
380 uint16_t response_size;
382 GNUNET_PEERSTORE_Continuation cont;
385 h->in_receive = GNUNET_NO;
391 response_type = ntohs(msg->type);
392 response_size = ntohs(msg->size);
393 LOG(GNUNET_ERROR_TYPE_DEBUG, "Received a response of type %lu from server\n", response_type);
394 switch(response_type)
396 case GNUNET_MESSAGE_TYPE_PEERSTORE_STORE_RESULT:
397 GNUNET_assert(response_size >= sizeof(struct GNUNET_MessageHeader) + sizeof(struct StoreResponseMessage));
401 LOG(GNUNET_ERROR_TYPE_ERROR, "Received a response to a non-existent store request\n");
405 cont_cls = sc->cont_cls;
406 GNUNET_PEERSTORE_store_cancel(sc);
407 trigger_transmit (h);
408 if (NULL != h->sc_head)
410 LOG(GNUNET_ERROR_TYPE_DEBUG, "Another store request awaiting response, triggering receive for it\n");
411 h->in_receive = GNUNET_YES;
412 GNUNET_CLIENT_receive (h->client,
415 GNUNET_TIME_UNIT_FOREVER_REL);
419 LOG(GNUNET_ERROR_TYPE_DEBUG, "Calling continuation of store request\n");
420 srm = (struct StoreResponseMessage *)msg;
422 if(GNUNET_NO == ntohs(srm->success))
424 emsg = GNUNET_malloc(ntohs(srm->emsg_size));
425 memcpy(emsg, &srm[1], ntohs(srm->emsg_size));
427 cont(cont_cls, emsg);
434 /******************************************************************************/
435 /******************* ADD FUNCTIONS *********************/
436 /******************************************************************************/
439 * Cancel a store request
441 * @param sc Store request context
444 GNUNET_PEERSTORE_store_cancel (struct GNUNET_PEERSTORE_StoreContext *sc)
446 struct GNUNET_PEERSTORE_Handle *h;
450 if (GNUNET_YES == sc->request_transmitted)
451 return; /* need to finish processing */
452 GNUNET_CONTAINER_DLL_remove (h->sc_head,
457 GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, sc->rc);
458 GNUNET_free (sc->rc);
464 * Called after store request is sent
465 * Waits for response from service
467 * @param cls a 'struct GNUNET_PEERSTORE_StoreContext'
468 * @parma emsg error message (or NULL)
470 void store_receive_result(void *cls, const char *emsg)
472 struct GNUNET_PEERSTORE_StoreContext *sc = cls;
473 struct GNUNET_PEERSTORE_Handle *h = sc->h;
478 GNUNET_PEERSTORE_store_cancel (sc);
480 if (NULL != sc->cont)
481 sc->cont (sc->cont_cls, emsg);
484 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
486 sc->request_transmitted = GNUNET_YES;
487 if (GNUNET_NO == h->in_receive)
489 h->in_receive = GNUNET_YES;
490 GNUNET_CLIENT_receive (h->client,
493 GNUNET_TIME_UNIT_FOREVER_REL);
498 * Store a new entry in the PEERSTORE
500 * @param h Handle to the PEERSTORE service
501 * @param peer Peer Identity
502 * @param sub_system name of the sub system
503 * @param value entry value BLOB
504 * @param size size of 'value'
505 * @param lifetime relative time after which the entry is (possibly) deleted
506 * @param cont Continuation function after the store request is processed
507 * @param cont_cls Closure for 'cont'
509 struct GNUNET_PEERSTORE_StoreContext *
510 GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h,
511 const struct GNUNET_PeerIdentity *peer,
512 const char *sub_system,
515 struct GNUNET_TIME_Relative lifetime,
516 GNUNET_PEERSTORE_Continuation cont,
519 struct GNUNET_PEERSTORE_RequestContext *rc;
520 struct StoreRequestMessage *entry;
521 struct GNUNET_PEERSTORE_StoreContext *sc;
524 size_t sub_system_size;
527 LOG (GNUNET_ERROR_TYPE_DEBUG,
528 "Storing value (size: %lu) for subsytem `%s' and peer `%s'\n",
529 size, sub_system, GNUNET_i2s (peer));
530 sub_system_size = strlen(sub_system);
531 request_size = sizeof(struct StoreRequestMessage) + sub_system_size + size;
532 rc = GNUNET_malloc(sizeof(struct GNUNET_PEERSTORE_RequestContext) + request_size);
534 rc->size = request_size;
535 entry = (struct StoreRequestMessage *)&rc[1];
536 entry->header.size = htons(request_size);
537 entry->header.type = htons(GNUNET_MESSAGE_TYPE_PEERSTORE_STORE);
539 entry->sub_system_size = htons(sub_system_size);
540 entry->value_size = htons(size);
541 entry->lifetime = lifetime;
542 ss = (char *)&entry[1];
543 memcpy(ss, sub_system, sub_system_size);
544 val = ss + sub_system_size;
545 memcpy(val, value, size);
546 sc = GNUNET_new(struct GNUNET_PEERSTORE_StoreContext);
548 sc->cont_cls = cont_cls;
551 rc->cont = &store_receive_result;
553 GNUNET_CONTAINER_DLL_insert_tail(h->rc_head, h->rc_tail, rc);
554 GNUNET_CONTAINER_DLL_insert_tail(h->sc_head, h->sc_tail, sc);
555 trigger_transmit (h);
561 /* end of peerstore_api.c */