error handling
[oweals/gnunet.git] / src / abd / abd_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2013, 2016 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19 */
20 /**
21  * @file abd/abd_api.c
22  * @brief library to access the ABD service
23  * @author Martin Schanzenbach
24  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_arm_service.h"
29 #include "gnunet_hello_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_signatures.h"
32 #include "abd.h"
33 #include "abd_serialization.h"
34 #include "gnunet_abd_service.h"
35 #include "gnunet_identity_service.h"
36
37
38 #define LOG(kind, ...) GNUNET_log_from (kind, "abd-api", __VA_ARGS__)
39
40 /**
41  * Handle to a verify request
42  */
43 struct GNUNET_ABD_Request
44 {
45
46   /**
47    * DLL
48    */
49   struct GNUNET_ABD_Request *next;
50
51   /**
52    * DLL
53    */
54   struct GNUNET_ABD_Request *prev;
55
56   /**
57    * handle to abd service
58    */
59   struct GNUNET_ABD_Handle *abd_handle;
60
61   /**
62    * processor to call on verify result
63    */
64   GNUNET_ABD_CredentialResultProcessor verify_proc;
65
66   /**
67    * @e verify_proc closure
68    */
69   void *proc_cls;
70
71   /**
72    * processor to call on intermediate result
73    */
74   GNUNET_ABD_IntermediateResultProcessor int_proc;
75
76   /**
77    * @e verify_proc2 closure
78    */
79   void *proc2_cls;
80
81   /**
82    * Envelope with the message for this queue entry.
83    */
84   struct GNUNET_MQ_Envelope *env;
85
86   /**
87    * request id
88    */
89   uint32_t r_id;
90 };
91
92
93 /**
94  * Connection to the ABD service.
95  */
96 struct GNUNET_ABD_Handle
97 {
98
99   /**
100    * Configuration to use.
101    */
102   const struct GNUNET_CONFIGURATION_Handle *cfg;
103
104   /**
105    * Connection to service (if available).
106    */
107   struct GNUNET_MQ_Handle *mq;
108
109   /**
110    * Head of linked list of active verify requests.
111    */
112   struct GNUNET_ABD_Request *request_head;
113
114   /**
115    * Tail of linked list of active verify requests.
116    */
117   struct GNUNET_ABD_Request *request_tail;
118
119   /**
120    * Reconnect task
121    */
122   struct GNUNET_SCHEDULER_Task *reconnect_task;
123
124   /**
125    * How long do we wait until we try to reconnect?
126    */
127   struct GNUNET_TIME_Relative reconnect_backoff;
128
129   /**
130    * Request Id generator.  Incremented by one for each request.
131    */
132   uint32_t r_id_gen;
133 };
134
135
136 /**
137  * Reconnect to ABD service.
138  *
139  * @param handle the handle to the ABD service
140  */
141 static void
142 reconnect (struct GNUNET_ABD_Handle *handle);
143
144
145 /**
146  * Reconnect to ABD
147  *
148  * @param cls the handle
149  */
150 static void
151 reconnect_task (void *cls)
152 {
153   struct GNUNET_ABD_Handle *handle = cls;
154
155   handle->reconnect_task = NULL;
156   reconnect (handle);
157 }
158
159
160 /**
161  * Disconnect from service and then reconnect.
162  *
163  * @param handle our handle
164  */
165 static void
166 force_reconnect (struct GNUNET_ABD_Handle *handle)
167 {
168   GNUNET_MQ_destroy (handle->mq);
169   handle->mq = NULL;
170   handle->reconnect_backoff =
171     GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
172   handle->reconnect_task =
173     GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
174                                   &reconnect_task,
175                                   handle);
176 }
177
178
179 /**
180  * Generic error handler, called with the appropriate error code and
181  * the same closure specified at the creation of the message queue.
182  * Not every message queue implementation supports an error handler.
183  *
184  * @param cls closure with the `struct GNUNET_ABD_Handle *`
185  * @param error error code
186  */
187 static void
188 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
189 {
190   struct GNUNET_ABD_Handle *handle = cls;
191
192   force_reconnect (handle);
193 }
194
195
196 /**
197  * Check validity of message received from the ABD service
198  *
199  * @param cls the `struct GNUNET_ABD_Handle *`
200  * @param vr_msg the incoming message
201  */
202 static int
203 check_result (void *cls, const struct DelegationChainResultMessage *vr_msg)
204 {
205   // TODO
206   return GNUNET_OK;
207 }
208
209
210 /**
211  * Handler for messages received from the ABD service
212  *
213  * @param cls the `struct GNUNET_ABD_Handle *`
214  * @param vr_msg the incoming message
215  */
216 static void
217 handle_result (void *cls, const struct DelegationChainResultMessage *vr_msg)
218 {
219   struct GNUNET_ABD_Handle *handle = cls;
220   uint32_t r_id = ntohl (vr_msg->id);
221   struct GNUNET_ABD_Request *vr;
222   size_t mlen = ntohs (vr_msg->header.size) - sizeof (*vr_msg);
223   uint32_t d_count = ntohl (vr_msg->d_count);
224   uint32_t c_count = ntohl (vr_msg->c_count);
225   struct GNUNET_ABD_Delegation d_chain[d_count];
226   struct GNUNET_ABD_Delegate dels[c_count];
227   GNUNET_ABD_CredentialResultProcessor proc;
228   void *proc_cls;
229
230   LOG (GNUNET_ERROR_TYPE_DEBUG,
231        "Received verify reply from ABD service\n");
232   for (vr = handle->request_head; NULL != vr; vr = vr->next)
233     if (vr->r_id == r_id)
234       break;
235   if (NULL == vr)
236     return;
237   proc = vr->verify_proc;
238   proc_cls = vr->proc_cls;
239   GNUNET_CONTAINER_DLL_remove (handle->request_head, handle->request_tail, vr);
240   GNUNET_MQ_discard (vr->env);
241   GNUNET_free (vr);
242   GNUNET_assert (
243     GNUNET_OK ==
244     GNUNET_ABD_delegation_chain_deserialize (mlen,
245                                              (const char *) &vr_msg[1],
246                                              d_count,
247                                              d_chain,
248                                              c_count,
249                                              dels));
250   if (GNUNET_NO == ntohl (vr_msg->del_found))
251   {
252     proc (proc_cls, 0, NULL, 0,
253           NULL);
254   }
255   else
256   {
257     proc (proc_cls, d_count, d_chain, c_count, dels);
258   }
259 }
260
261
262 static int
263 check_intermediate (void *cls, const struct
264                     DelegationChainIntermediateMessage *vr_msg)
265 {
266   // TODO
267   return GNUNET_OK;
268 }
269
270
271 static void
272 handle_intermediate (void *cls, const struct
273                      DelegationChainIntermediateMessage *vr_msg)
274 {
275   struct GNUNET_ABD_Handle *handle = cls;
276   uint32_t r_id = ntohl (vr_msg->id);
277   uint32_t size = ntohl (vr_msg->size);
278   bool is_bw = ntohs (vr_msg->is_bw);
279   struct GNUNET_ABD_Request *vr;
280   GNUNET_ABD_IntermediateResultProcessor proc;
281   void *proc_cls;
282   struct GNUNET_ABD_Delegation *dd;
283
284
285   LOG (GNUNET_ERROR_TYPE_DEBUG,
286        "Received intermediate reply from ABD service\n");
287
288   for (vr = handle->request_head; NULL != vr; vr = vr->next)
289     if (vr->r_id == r_id)
290       break;
291   if (NULL == vr)
292     return;
293
294   proc = vr->int_proc;
295   proc_cls = vr->proc2_cls;
296
297   dd = GNUNET_new (struct GNUNET_ABD_Delegation);
298   GNUNET_assert (
299     GNUNET_OK ==
300     GNUNET_ABD_delegation_chain_deserialize (size,
301                                              (const char *) &vr_msg[1],
302                                              1,
303                                              dd,
304                                              0,
305                                              NULL));
306   proc (proc_cls, dd, is_bw);
307 }
308
309
310 /**
311  * Reconnect to ABD service.
312  *
313  * @param handle the handle to the ABD service
314  */
315 static void
316 reconnect (struct GNUNET_ABD_Handle *handle)
317 {
318   struct GNUNET_MQ_MessageHandler handlers[] =
319   {GNUNET_MQ_hd_var_size (result,
320                           GNUNET_MESSAGE_TYPE_ABD_VERIFY_RESULT,
321                           struct DelegationChainResultMessage,
322                           handle),
323    GNUNET_MQ_hd_var_size (result,
324                           GNUNET_MESSAGE_TYPE_ABD_COLLECT_RESULT,
325                           struct DelegationChainResultMessage,
326                           handle),
327    GNUNET_MQ_hd_var_size (intermediate,
328                           GNUNET_MESSAGE_TYPE_ABD_INTERMEDIATE_RESULT,
329                           struct DelegationChainIntermediateMessage,
330                           handle),
331    GNUNET_MQ_handler_end ()};
332   struct GNUNET_ABD_Request *vr;
333
334   GNUNET_assert (NULL == handle->mq);
335   LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to ABD\n");
336   handle->mq = GNUNET_CLIENT_connect (handle->cfg,
337                                       "abd",
338                                       handlers,
339                                       &mq_error_handler,
340                                       handle);
341   if (NULL == handle->mq)
342     return;
343   for (vr = handle->request_head; NULL != vr; vr = vr->next)
344     GNUNET_MQ_send_copy (handle->mq, vr->env);
345 }
346
347
348 /**
349  * Initialize the connection with the ABD service.
350  *
351  * @param cfg configuration to use
352  * @return handle to the ABD service, or NULL on error
353  */
354 struct GNUNET_ABD_Handle *
355 GNUNET_ABD_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
356 {
357   struct GNUNET_ABD_Handle *handle;
358
359   handle = GNUNET_new (struct GNUNET_ABD_Handle);
360   handle->cfg = cfg;
361   reconnect (handle);
362   if (NULL == handle->mq)
363   {
364     GNUNET_free (handle);
365     return NULL;
366   }
367   return handle;
368 }
369
370
371 /**
372  * Shutdown connection with the ABD service.
373  *
374  * @param handle handle of the ABD connection to stop
375  */
376 void
377 GNUNET_ABD_disconnect (struct GNUNET_ABD_Handle *handle)
378 {
379   if (NULL != handle->mq)
380   {
381     GNUNET_MQ_destroy (handle->mq);
382     handle->mq = NULL;
383   }
384   if (NULL != handle->reconnect_task)
385   {
386     GNUNET_SCHEDULER_cancel (handle->reconnect_task);
387     handle->reconnect_task = NULL;
388   }
389   GNUNET_assert (NULL == handle->request_head);
390   GNUNET_free (handle);
391 }
392
393
394 /**
395  * Cancel pending verify request
396  *
397  * @param lr the verify request to cancel
398  */
399 void
400 GNUNET_ABD_request_cancel (struct GNUNET_ABD_Request *lr)
401 {
402   struct GNUNET_ABD_Handle *handle = lr->abd_handle;
403
404   GNUNET_CONTAINER_DLL_remove (handle->request_head, handle->request_tail, lr);
405   GNUNET_MQ_discard (lr->env);
406   GNUNET_free (lr);
407 }
408
409
410 /**
411  * Performs attribute collection.
412  * Collects all abds of subject to fulfill the
413  * attribute, if possible
414  *
415  * @param handle handle to the Credential service
416  * @param issuer_key the issuer public key
417  * @param issuer_attribute the issuer attribute
418  * @param subject_key the subject public key
419  * @param proc function to call on result
420  * @param proc_cls closure for processor
421  * @return handle to the queued request
422  */
423 struct GNUNET_ABD_Request *
424 GNUNET_ABD_collect (
425   struct GNUNET_ABD_Handle *handle,
426   const struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key,
427   const char *issuer_attribute,
428   const struct GNUNET_CRYPTO_EcdsaPrivateKey *subject_key,
429   enum GNUNET_ABD_AlgoDirectionFlags direction,
430   GNUNET_ABD_CredentialResultProcessor proc,
431   void *proc_cls,
432   GNUNET_ABD_IntermediateResultProcessor proc2,
433   void *proc2_cls)
434 {
435   /* IPC to shorten abd names, return shorten_handle */
436   struct CollectMessage *c_msg;
437   struct GNUNET_ABD_Request *vr;
438   size_t nlen;
439
440   if (NULL == issuer_attribute)
441   {
442     GNUNET_break (0);
443     return NULL;
444   }
445
446   // DEBUG LOG
447   LOG (GNUNET_ERROR_TYPE_DEBUG,
448        "Trying to collect `%s' in ABD\n",
449        issuer_attribute);
450   nlen = strlen (issuer_attribute) + 1;
451   if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*vr))
452   {
453     GNUNET_break (0);
454     return NULL;
455   }
456   vr = GNUNET_new (struct GNUNET_ABD_Request);
457   vr->abd_handle = handle;
458   vr->verify_proc = proc;
459   vr->proc_cls = proc_cls;
460   vr->int_proc =  proc2;
461   vr->proc2_cls = proc2_cls;
462   vr->r_id = handle->r_id_gen++;
463   vr->env =
464     GNUNET_MQ_msg_extra (c_msg, nlen, GNUNET_MESSAGE_TYPE_ABD_COLLECT);
465   c_msg->id = htonl (vr->r_id);
466   c_msg->subject_key = *subject_key;
467   c_msg->issuer_key = *issuer_key;
468   c_msg->issuer_attribute_len = htons (strlen (issuer_attribute));
469   c_msg->resolution_algo = htons (direction);
470
471   GNUNET_memcpy (&c_msg[1], issuer_attribute, strlen (issuer_attribute));
472   GNUNET_CONTAINER_DLL_insert (handle->request_head, handle->request_tail, vr);
473   if (NULL != handle->mq)
474     GNUNET_MQ_send_copy (handle->mq, vr->env);
475   return vr;
476 }
477
478
479 /**
480  * Performs attribute verification.
481  * Checks if there is a delegation chain from
482  * attribute ``issuer_attribute'' issued by the issuer
483  * with public key ``issuer_key'' maps to the attribute
484  * ``subject_attribute'' claimed by the subject with key
485  * ``subject_key''
486  *
487  * @param handle handle to the Credential service
488  * @param issuer_key the issuer public key
489  * @param issuer_attribute the issuer attribute
490  * @param subject_key the subject public key
491  * @param delegate_count number of delegates provided
492  * @param delegates subject delegates
493  * @param proc function to call on result
494  * @param proc_cls closure for processor
495  * @return handle to the queued request
496  */
497 struct GNUNET_ABD_Request *
498 GNUNET_ABD_verify (
499   struct GNUNET_ABD_Handle *handle,
500   const struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key,
501   const char *issuer_attribute,
502   const struct GNUNET_CRYPTO_EcdsaPublicKey *subject_key,
503   uint32_t delegate_count,
504   const struct GNUNET_ABD_Delegate *delegates,
505   enum GNUNET_ABD_AlgoDirectionFlags direction,
506   GNUNET_ABD_CredentialResultProcessor proc,
507   void *proc_cls,
508   GNUNET_ABD_IntermediateResultProcessor proc2,
509   void *proc2_cls)
510 {
511   /* IPC to shorten abd names, return shorten_handle */
512   struct VerifyMessage *v_msg;
513   struct GNUNET_ABD_Request *vr;
514   size_t nlen;
515   size_t clen;
516
517   if ((NULL == issuer_attribute) || (NULL == delegates))
518   {
519     GNUNET_break (0);
520     return NULL;
521   }
522
523   clen = GNUNET_ABD_delegates_get_size (delegate_count, delegates);
524
525   // DEBUG LOG
526   LOG (GNUNET_ERROR_TYPE_DEBUG,
527        "Trying to verify `%s' in ABD\n",
528        issuer_attribute);
529   nlen = strlen (issuer_attribute) + 1 + clen;
530   if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*vr))
531   {
532     GNUNET_break (0);
533     return NULL;
534   }
535   vr = GNUNET_new (struct GNUNET_ABD_Request);
536   vr->abd_handle = handle;
537   vr->verify_proc = proc;
538   vr->proc_cls = proc_cls;
539   vr->int_proc =  proc2;
540   vr->proc2_cls = proc2_cls;
541   vr->r_id = handle->r_id_gen++;
542   vr->env =
543     GNUNET_MQ_msg_extra (v_msg, nlen, GNUNET_MESSAGE_TYPE_ABD_VERIFY);
544   v_msg->id = htonl (vr->r_id);
545   v_msg->subject_key = *subject_key;
546   v_msg->d_count = htonl (delegate_count);
547   v_msg->issuer_key = *issuer_key;
548   v_msg->issuer_attribute_len = htons (strlen (issuer_attribute));
549   v_msg->resolution_algo = htons (direction);
550
551   GNUNET_memcpy (&v_msg[1], issuer_attribute, strlen (issuer_attribute));
552   GNUNET_ABD_delegates_serialize (delegate_count,
553                                   delegates,
554                                   clen,
555                                   ((char *) &v_msg[1])
556                                   + strlen (issuer_attribute) + 1);
557   GNUNET_CONTAINER_DLL_insert (handle->request_head, handle->request_tail, vr);
558   if (NULL != handle->mq)
559     GNUNET_MQ_send_copy (handle->mq, vr->env);
560   return vr;
561 }
562
563
564 /* end of abd_api.c */