5a2455014286f372656848b955b6cad8cf1c1782
[oweals/gnunet.git] / src / peerstore / peerstore_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 
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 peerstore/peerstore_api.c
23  * @brief API for peerstore
24  * @author Omar Tarabai
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "peerstore.h"
29 #include "peerstore_common.h"
30
31 #define LOG(kind,...) GNUNET_log_from (kind, "peerstore-api",__VA_ARGS__)
32
33 /******************************************************************************/
34 /************************      DATA STRUCTURES     ****************************/
35 /******************************************************************************/
36
37 /**
38  * Handle to the PEERSTORE service.
39  */
40 struct GNUNET_PEERSTORE_Handle
41 {
42
43   /**
44    * Our configuration.
45    */
46   const struct GNUNET_CONFIGURATION_Handle *cfg;
47
48   /**
49    * Connection to the service.
50    */
51   struct GNUNET_CLIENT_Connection *client;
52
53   /**
54    * Message queue
55    */
56   struct GNUNET_MQ_Handle *mq;
57
58   /**
59    * Head of active STORE requests.
60    */
61   struct GNUNET_PEERSTORE_StoreContext *store_head;
62
63   /**
64    * Tail of active STORE requests.
65    */
66   struct GNUNET_PEERSTORE_StoreContext *store_tail;
67
68 };
69
70 /**
71  * Context for a store request
72  */
73 struct GNUNET_PEERSTORE_StoreContext
74 {
75   /**
76    * Kept in a DLL.
77    */
78   struct GNUNET_PEERSTORE_StoreContext *next;
79
80   /**
81    * Kept in a DLL.
82    */
83   struct GNUNET_PEERSTORE_StoreContext *prev;
84
85   /**
86    * Handle to the PEERSTORE service.
87    */
88   struct GNUNET_PEERSTORE_Handle *h;
89
90   /**
91    * MQ Envelope with store request message
92    */
93   struct GNUNET_MQ_Envelope *ev;
94
95   /**
96    * Continuation called with service response
97    */
98   GNUNET_PEERSTORE_Continuation cont;
99
100   /**
101    * Closure for 'cont'
102    */
103   void *cont_cls;
104
105   /**
106    * #GNUNET_YES / #GNUNET_NO
107    * if sent, cannot be canceled
108    */
109   int request_sent;
110
111 };
112
113 /******************************************************************************/
114 /*******************             DECLARATIONS             *********************/
115 /******************************************************************************/
116
117 /**
118  * When a response for store request is received
119  *
120  * @param cls a 'struct GNUNET_PEERSTORE_StoreContext *'
121  * @param msg message received, NULL on timeout or fatal error
122  */
123 void handle_store_result (void *cls, const struct GNUNET_MessageHeader *msg);
124
125 static void
126 reconnect (struct GNUNET_PEERSTORE_Handle *h);
127
128 /**
129  * MQ message handlers
130  */
131 static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
132     {&handle_store_result, GNUNET_MESSAGE_TYPE_PEERSTORE_STORE_RESULT_OK, sizeof(struct GNUNET_MessageHeader)},
133     {&handle_store_result, GNUNET_MESSAGE_TYPE_PEERSTORE_STORE_RESULT_FAIL, sizeof(struct GNUNET_MessageHeader)},
134     GNUNET_MQ_HANDLERS_END
135 };
136
137 /******************************************************************************/
138 /*******************         CONNECTION FUNCTIONS         *********************/
139 /******************************************************************************/
140
141 static void
142 handle_client_error (void *cls, enum GNUNET_MQ_Error error)
143 {
144   struct GNUNET_PEERSTORE_Handle *h = cls;
145
146   GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Received an error notification from MQ of type: %d\n", error);
147   reconnect(h);
148 }
149
150 /**
151  * Close the existing connection to PEERSTORE and reconnect.
152  *
153  * @param h handle to the service
154  */
155 static void
156 reconnect (struct GNUNET_PEERSTORE_Handle *h)
157 {
158
159   LOG(GNUNET_ERROR_TYPE_DEBUG, "Reconnecting...\n");
160   if (NULL != h->mq)
161   {
162     GNUNET_MQ_destroy(h->mq);
163     h->mq = NULL;
164   }
165   if (NULL != h->client)
166   {
167     GNUNET_CLIENT_disconnect (h->client);
168     h->client = NULL;
169   }
170   h->client = GNUNET_CLIENT_connect ("peerstore", h->cfg);
171   h->mq = GNUNET_MQ_queue_for_connection_client(h->client,
172       mq_handlers,
173       &handle_client_error,
174       h);
175
176 }
177
178 /**
179  * Connect to the PEERSTORE service.
180  *
181  * @return NULL on error
182  */
183 struct GNUNET_PEERSTORE_Handle *
184 GNUNET_PEERSTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
185 {
186   struct GNUNET_PEERSTORE_Handle *h;
187
188   h = GNUNET_new (struct GNUNET_PEERSTORE_Handle);
189   h->client = GNUNET_CLIENT_connect ("peerstore", cfg);
190   if(NULL == h->client)
191   {
192     GNUNET_free(h);
193     return NULL;
194   }
195   h->cfg = cfg;
196   h->mq = GNUNET_MQ_queue_for_connection_client(h->client,
197       mq_handlers,
198       &handle_client_error,
199       h);
200   if(NULL == h->mq)
201   {
202     GNUNET_free(h);
203     return NULL;
204   }
205   LOG(GNUNET_ERROR_TYPE_DEBUG, "New connection created\n");
206   return h;
207 }
208
209 /**
210  * Disconnect from the PEERSTORE service
211  * Do not call in case of pending requests
212  *
213  * @param h handle to disconnect
214  */
215 void
216 GNUNET_PEERSTORE_disconnect(struct GNUNET_PEERSTORE_Handle *h)
217 {
218   if(NULL != h->mq)
219   {
220     GNUNET_MQ_destroy(h->mq);
221     h->mq = NULL;
222   }
223   if (NULL != h->client)
224   {
225     GNUNET_CLIENT_disconnect (h->client);
226     h->client = NULL;
227   }
228   GNUNET_free(h);
229   LOG(GNUNET_ERROR_TYPE_DEBUG, "Disconnected, BYE!\n");
230 }
231
232
233 /******************************************************************************/
234 /*******************            STORE FUNCTIONS           *********************/
235 /******************************************************************************/
236
237 /**
238  * When a response for store request is received
239  *
240  * @param cls a 'struct GNUNET_PEERSTORE_StoreContext *'
241  * @param msg message received, NULL on timeout or fatal error
242  */
243 void handle_store_result (void *cls, const struct GNUNET_MessageHeader *msg)
244 {
245   struct GNUNET_PEERSTORE_Handle *h = cls;
246   struct GNUNET_PEERSTORE_StoreContext *sc;
247   uint16_t msg_type;
248   GNUNET_PEERSTORE_Continuation cont;
249   void *cont_cls;
250
251   sc = h->store_head;
252   if(NULL == sc)
253   {
254     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Unexpected store response, this should not happen.\n");
255     reconnect(h);
256     return;
257   }
258   cont = sc->cont;
259   cont_cls = sc->cont_cls;
260   GNUNET_CONTAINER_DLL_remove(h->store_head, h->store_tail, sc);
261   GNUNET_free(sc);
262   if(NULL == msg) /* Connection error */
263   {
264     if(NULL != cont)
265       cont(cont_cls, GNUNET_SYSERR);
266     reconnect(h);
267     return;
268   }
269   if(NULL != cont) /* Run continuation */
270   {
271     msg_type = ntohs(msg->type);
272     if(GNUNET_MESSAGE_TYPE_PEERSTORE_STORE_RESULT_OK == msg_type)
273       cont(cont_cls, GNUNET_OK);
274     else if(GNUNET_MESSAGE_TYPE_PEERSTORE_STORE_RESULT_FAIL == msg_type)
275       cont(cont_cls, GNUNET_SYSERR);
276   }
277
278 }
279
280 /**
281  * Callback after MQ envelope is sent
282  *
283  * @param cls a 'struct GNUNET_PEERSTORE_StoreContext *'
284  */
285 void store_request_sent (void *cls)
286 {
287   struct GNUNET_PEERSTORE_StoreContext *sc = cls;
288
289   sc->request_sent = GNUNET_YES;
290 }
291
292 /**
293  * Cancel a store request
294  *
295  * @param sc Store request context
296  */
297 void
298 GNUNET_PEERSTORE_store_cancel (struct GNUNET_PEERSTORE_StoreContext *sc)
299 {
300   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
301           "Canceling store request.\n");
302   if(GNUNET_NO == sc->request_sent)
303   {
304     if(NULL != sc->ev)
305       GNUNET_MQ_discard(sc->ev);
306     GNUNET_CONTAINER_DLL_remove(sc->h->store_head, sc->h->store_tail, sc);
307     GNUNET_free(sc);
308   }
309   else
310   { /* request already sent, will have to wait for response */
311     sc->cont = NULL;
312   }
313
314 }
315
316 /**
317  * Store a new entry in the PEERSTORE
318  *
319  * @param h Handle to the PEERSTORE service
320  * @param sub_system name of the sub system
321  * @param peer Peer Identity
322  * @param key entry key
323  * @param value entry value BLOB
324  * @param size size of 'value'
325  * @param expiry absolute time after which the entry is (possibly) deleted
326  * @param cont Continuation function after the store request is processed
327  * @param cont_cls Closure for 'cont'
328  */
329 struct GNUNET_PEERSTORE_StoreContext *
330 GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h,
331     const char *sub_system,
332     const struct GNUNET_PeerIdentity *peer,
333     const char *key,
334     const void *value,
335     size_t size,
336     struct GNUNET_TIME_Absolute expiry,
337     GNUNET_PEERSTORE_Continuation cont,
338     void *cont_cls)
339 {
340   struct GNUNET_MQ_Envelope *ev;
341   struct GNUNET_PEERSTORE_StoreContext *sc;
342
343   LOG (GNUNET_ERROR_TYPE_DEBUG,
344       "Storing value (size: %lu) for subsytem `%s', peer `%s', key `%s'\n",
345       size, sub_system, GNUNET_i2s (peer), key);
346   ev = PEERSTORE_create_record_mq_envelope(sub_system,
347       peer,
348       key,
349       value,
350       size,
351       expiry,
352       GNUNET_MESSAGE_TYPE_PEERSTORE_STORE);
353   GNUNET_MQ_send(h->mq, ev);
354   GNUNET_MQ_notify_sent(ev, &store_request_sent, ev);
355   sc = GNUNET_new(struct GNUNET_PEERSTORE_StoreContext);
356   sc->ev = ev;
357   sc->cont = cont;
358   sc->cont_cls = cont_cls;
359   sc->h = h;
360   sc->request_sent = GNUNET_NO;
361   GNUNET_CONTAINER_DLL_insert(h->store_head, h->store_tail, sc);
362   return sc;
363
364 }
365
366 /* end of peerstore_api.c */