291113b959fd21c00aeacb089a5fd0f52bae28a8
[oweals/gnunet.git] / src / identity / identity_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2013 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public Liceidentity 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 Liceidentity for more details.
14
15      You should have received a copy of the GNU General Public Liceidentity
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 identity/identity_api.c
23  * @brief api to interact with the identity service
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_client_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_arm_service.h"
31 #include "gnunet_hello_lib.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_server_lib.h"
34 #include "gnunet_time_lib.h"
35 #include "gnunet_identity_service.h"
36 #include "identity.h"
37
38 #define LOG(kind,...) GNUNET_log_from (kind, "identity-api",__VA_ARGS__)
39
40 /** 
41  * Handle for a ego.
42  */
43 struct GNUNET_IDENTITY_Ego
44 {
45   /**
46    * Private key associated with this ego.
47    */
48   struct GNUNET_CRYPTO_EccPrivateKey *pk;
49
50   /**
51    * Current identifier (name) associated with this ego.
52    */
53   char *identifier;
54
55   /**
56    * Client context associated with this ego.
57    */
58   void *ctx;
59
60   /**
61    * Hash of the public key of this ego.
62    */
63   struct GNUNET_HashCode id;
64 };
65
66
67 /** 
68  * Handle for an operation with the identity service.
69  */
70 struct GNUNET_IDENTITY_Operation
71 {
72
73   /**
74    * Main identity handle.
75    */
76   struct GNUNET_IDENTITY_Handle *h;
77   
78   /**
79    * We keep operations in a DLL.
80    */
81   struct GNUNET_IDENTITY_Operation *next;
82
83   /**
84    * We keep operations in a DLL.
85    */
86   struct GNUNET_IDENTITY_Operation *prev;
87
88   /**
89    * Message to send to the identity service.
90    * Allocated at the end of this struct.
91    */
92   const struct GNUNET_MessageHeader *msg;
93
94   /**
95    * Continuation to invoke with the result of the transmission; 'cb'
96    * will be NULL in this case.
97    */
98   GNUNET_IDENTITY_Continuation cont;
99
100   /**
101    * Continuation to invoke with the result of the transmission for
102    * 'get' operations ('cont' will be NULL in this case).
103    */
104   GNUNET_IDENTITY_Callback cb;
105
106   /**
107    * Closure for 'cont' or 'cb'.
108    */
109   void *cls;
110
111 };
112
113
114 /**
115  * Handle for the service.
116  */
117 struct GNUNET_IDENTITY_Handle
118 {
119   /**
120    * Configuration to use.
121    */
122   const struct GNUNET_CONFIGURATION_Handle *cfg;
123
124   /**
125    * Socket (if available).
126    */
127   struct GNUNET_CLIENT_Connection *client;
128
129   /**
130    * Hash map from the hash of the public key to the
131    * respective 'GNUNET_IDENTITY_Ego' handle.
132    */
133   struct GNUNET_CONTAINER_MultiHashMap *egos;
134
135   /**
136    * Function to call when we receive updates.
137    */
138   GNUNET_IDENTITY_Callback cb;
139
140   /**
141    * Closure for 'cb'.
142    */
143   void *cb_cls;
144
145   /**
146    * Head of active operations.
147    */ 
148   struct GNUNET_IDENTITY_Operation *op_head;
149
150   /**
151    * Tail of active operations.
152    */ 
153   struct GNUNET_IDENTITY_Operation *op_tail;
154
155   /**
156    * Currently pending transmission request, or NULL for none.
157    */
158   struct GNUNET_CLIENT_TransmitHandle *th;
159
160   /**
161    * Task doing exponential back-off trying to reconnect.
162    */
163   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
164
165   /**
166    * Time for next connect retry.
167    */
168   struct GNUNET_TIME_Relative reconnect_delay;
169
170   /**
171    * Are we polling for incoming messages right now?
172    */
173   int in_receive;
174
175 };
176
177
178
179 /**
180  * Try again to connect to network size estimation service.
181  *
182  * @param cls the handle to the transport service
183  * @param tc scheduler context
184  */
185 static void
186 reconnect (void *cls,
187            const struct GNUNET_SCHEDULER_TaskContext *tc);
188
189
190 /**
191  * Reschedule a connect attempt to the service.
192  *
193  * @param h transport service to reconnect
194  */
195 static void
196 reschedule_connect (struct GNUNET_IDENTITY_Handle *h)
197 {
198   GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
199
200   if (NULL != h->th)
201   {
202     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
203     h->th = NULL;
204   }
205   if (NULL != h->client)
206   {
207     GNUNET_CLIENT_disconnect (h->client);
208     h->client = NULL;
209   }
210   h->in_receive = GNUNET_NO;
211   LOG (GNUNET_ERROR_TYPE_DEBUG,
212        "Scheduling task to reconnect to identity service in %s.\n",
213        GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
214   h->reconnect_task =
215       GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
216   h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
217 }
218
219
220 /**
221  * Type of a function to call when we receive a message
222  * from the service.
223  *
224  * @param cls closure
225  * @param msg message received, NULL on timeout or fatal error
226  */
227 static void
228 message_handler (void *cls, 
229                  const struct GNUNET_MessageHeader *msg)
230 {
231   struct GNUNET_IDENTITY_Handle *h = cls;
232   struct GNUNET_IDENTITY_Operation *op;
233   struct GNUNET_IDENTITY_Ego *ego;
234   const struct GNUNET_IDENTITY_ResultCodeMessage *rcm;
235   const struct GNUNET_IDENTITY_UpdateMessage *um;
236   const struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
237   struct GNUNET_CRYPTO_EccPrivateKey *priv;
238   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub;
239   struct GNUNET_HashCode id;
240   const char *str;
241   uint16_t size;
242   uint16_t pk_len;
243   uint16_t name_len;
244
245   if (NULL == msg)
246   {
247     reschedule_connect (h);
248     return;
249   }
250   size = ntohs (msg->size);
251   switch (ntohs (msg->type))
252   {
253   case GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE:
254     if (size < sizeof (struct GNUNET_IDENTITY_ResultCodeMessage))
255     {
256       GNUNET_break (0);
257       reschedule_connect (h);
258       return;
259     }
260     rcm = (const struct GNUNET_IDENTITY_ResultCodeMessage *) msg;
261     str = (const char *) &rcm[1];
262     if ( (size > sizeof (struct GNUNET_IDENTITY_ResultCodeMessage)) &&
263          ('\0' != str[size - sizeof (struct GNUNET_IDENTITY_ResultCodeMessage) - 1]) )
264     {
265       GNUNET_break (0);
266       reschedule_connect (h);
267       return;
268     }
269     if (size == sizeof (struct GNUNET_IDENTITY_ResultCodeMessage))
270       str = NULL;
271
272     op = h->op_head;
273     GNUNET_CONTAINER_DLL_remove (h->op_head,
274                                  h->op_tail,
275                                  op);
276     if (NULL != op->cont)
277       op->cont (op->cls,
278                 str);
279     GNUNET_break (NULL == op->cb);
280     GNUNET_free (op);
281     break;
282   case GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE:
283     if (size < sizeof (struct GNUNET_IDENTITY_UpdateMessage))
284     {
285       GNUNET_break (0);
286       reschedule_connect (h);
287       return;
288     }
289     um = (const struct GNUNET_IDENTITY_UpdateMessage *) msg;
290     pk_len = ntohs (um->pk_len);
291     name_len = ntohs (um->name_len);    
292     str = (const char *) &um[1];
293     if ( (size != pk_len + name_len + sizeof (struct GNUNET_IDENTITY_UpdateMessage)) ||
294          ( (0 != name_len) &&
295            ('\0' != str[pk_len + name_len - 1])) )
296     {
297       GNUNET_break (0);
298       reschedule_connect (h);
299       return;
300     }
301     priv = GNUNET_CRYPTO_ecc_decode_key (str, pk_len, GNUNET_YES); 
302     if (NULL == priv)
303     {
304       GNUNET_break (0);
305       reschedule_connect (h);
306       return;
307     }
308     GNUNET_CRYPTO_ecc_key_get_public (priv,
309                                       &pub);
310     GNUNET_CRYPTO_hash (&pub, sizeof (pub), &id);
311     if (0 == name_len)
312       str = NULL;
313     else
314       str = &str[pk_len];
315     ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
316                                              &id);
317     if (NULL == ego)
318     {
319       /* ego was created */
320       if (NULL == str)
321       {
322         /* deletion of unknown ego? not allowed */
323         GNUNET_break (0);
324         GNUNET_CRYPTO_ecc_key_free (priv);
325         reschedule_connect (h);
326         return;
327       }
328       ego = GNUNET_new (struct GNUNET_IDENTITY_Ego);
329       ego->pk = priv;
330       ego->identifier = GNUNET_strdup (str);
331       ego->id = id;
332       GNUNET_assert (GNUNET_YES ==
333                      GNUNET_CONTAINER_multihashmap_put (h->egos,
334                                                         &ego->id,
335                                                         ego,
336                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
337     }
338     else
339     {
340       GNUNET_CRYPTO_ecc_key_free (priv);
341     }
342     /* inform application about change */
343     h->cb (h->cb_cls,
344            ego,
345            &ego->ctx,
346            str);
347     if (NULL == str)
348     {
349       /* ego was deleted */
350       GNUNET_assert (GNUNET_YES ==
351                      GNUNET_CONTAINER_multihashmap_remove (h->egos,
352                                                            &ego->id,
353                                                            ego));
354       GNUNET_CRYPTO_ecc_key_free (ego->pk);
355       GNUNET_free (ego->identifier);
356       GNUNET_free (ego);
357     }
358     else
359       {
360       /* ego changed name */
361       GNUNET_free (ego->identifier);
362       ego->identifier = GNUNET_strdup (str);
363     }    
364     break;
365   case GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT:
366     if (size < sizeof (struct GNUNET_IDENTITY_SetDefaultMessage))
367     {
368       GNUNET_break (0);
369       reschedule_connect (h);
370       return;
371     }
372     sdm = (const struct GNUNET_IDENTITY_SetDefaultMessage *) msg;
373     pk_len = ntohs (sdm->pk_len);
374     name_len = ntohs (sdm->name_len);
375     str = (const char *) &sdm[1];
376     if ( (size != pk_len + name_len + sizeof (struct GNUNET_IDENTITY_SetDefaultMessage)) ||
377          ( (0 != name_len) &&
378            ('\0' != str[pk_len + name_len - 1]) ) )
379     {
380       GNUNET_break (0);
381       reschedule_connect (h);
382       return;
383     }
384     priv = GNUNET_CRYPTO_ecc_decode_key (str, pk_len, GNUNET_YES); 
385     if (NULL == priv)
386     {
387       GNUNET_break (0);
388       reschedule_connect (h);
389       return;
390     }
391     GNUNET_CRYPTO_ecc_key_get_public (priv,
392                                       &pub);
393     GNUNET_CRYPTO_ecc_key_free (priv);
394     GNUNET_CRYPTO_hash (&pub, sizeof (pub), &id);
395     if (0 == name_len)
396       str = NULL;
397     else
398       str = &str[pk_len];
399     ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
400                                              &id);
401     if (NULL == ego)
402     {
403       GNUNET_break (0);
404       reschedule_connect (h);
405       return;
406     }
407     op = h->op_head;
408     GNUNET_CONTAINER_DLL_remove (h->op_head,
409                                  h->op_tail,
410                                  op);
411     if (NULL != op->cb)
412       op->cb (op->cls,
413               ego,
414               &ego->ctx,
415               ego->identifier);
416     GNUNET_break (NULL == op->cont);
417     GNUNET_free (op);
418     break;
419   default:
420     GNUNET_break (0);
421     reschedule_connect (h);
422     return;
423   }
424   GNUNET_CLIENT_receive (h->client, &message_handler, h,
425                          GNUNET_TIME_UNIT_FOREVER_REL);
426 }
427
428
429 /**
430  * Schedule transmission of the next message from our queue.
431  *
432  * @param h identity handle
433  */
434 static void
435 transmit_next (struct GNUNET_IDENTITY_Handle *h);
436
437
438 /**
439  * Transmit next message to service.
440  *
441  * @param cls the 'struct GNUNET_IDENTITY_Handle'.
442  * @param size number of bytes available in buf
443  * @param buf where to copy the message
444  * @return number of bytes copied to buf
445  */
446 static size_t
447 send_next_message (void *cls, 
448                    size_t size, 
449                    void *buf)
450 {
451   struct GNUNET_IDENTITY_Handle *h = cls;
452   struct GNUNET_IDENTITY_Operation *op = h->op_head;
453   size_t ret;
454   
455   h->th = NULL;
456   if (NULL == op)
457     return 0;
458   ret = ntohs (op->msg->size);
459   if (ret > size)
460   {
461     reschedule_connect (h);
462     return 0;
463   }  
464   memcpy (buf, op->msg, ret);
465   if ( (NULL == op->cont) &&
466        (NULL == op->cb) )
467   {
468     GNUNET_CONTAINER_DLL_remove (h->op_head,
469                                  h->op_tail,
470                                  op);
471     GNUNET_free (op);
472     transmit_next (h);
473   }
474   if (GNUNET_NO == h->in_receive)
475   {
476     h->in_receive = GNUNET_YES;
477     GNUNET_CLIENT_receive (h->client,
478                            &message_handler, h,
479                            GNUNET_TIME_UNIT_FOREVER_REL);
480   }
481   return ret;
482 }
483
484
485 /**
486  * Schedule transmission of the next message from our queue.
487  *
488  * @param h identity handle
489  */
490 static void
491 transmit_next (struct GNUNET_IDENTITY_Handle *h)
492 {
493   struct GNUNET_IDENTITY_Operation *op = h->op_head;
494
495   GNUNET_assert (NULL == h->th);
496   if (NULL == op)
497     return;
498   h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
499                                                ntohs (op->msg->size),
500                                                GNUNET_TIME_UNIT_FOREVER_REL,
501                                                GNUNET_NO,
502                                                &send_next_message,
503                                                h);
504                                                
505 }
506
507
508 /**
509  * Try again to connect to network size estimation service.
510  *
511  * @param cls the handle to the transport service
512  * @param tc scheduler context
513  */
514 static void
515 reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
516 {
517   struct GNUNET_IDENTITY_Handle *h = cls;
518   struct GNUNET_IDENTITY_Operation *op;
519   struct GNUNET_MessageHeader msg;
520
521   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
522   LOG (GNUNET_ERROR_TYPE_DEBUG,
523        "Connecting to identity service.\n");
524   GNUNET_assert (NULL == h->client);
525   h->client = GNUNET_CLIENT_connect ("identity", h->cfg);
526   GNUNET_assert (NULL != h->client);
527   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) + 
528                       sizeof (struct GNUNET_MessageHeader));
529   op->h = h;
530   op->msg = (const struct GNUNET_MessageHeader *) &op[1];
531   msg.size = htons (sizeof (msg));
532   msg.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_START);
533   memcpy (&op[1], &msg, sizeof (msg));
534   GNUNET_CONTAINER_DLL_insert (h->op_head,
535                                h->op_tail,
536                                op);
537   transmit_next (h);
538   GNUNET_assert (NULL != h->th);
539 }
540
541
542 /**
543  * Connect to the identity service.
544  *
545  * @param cfg the configuration to use
546  * @param cb function to call on all identity events, can be NULL
547  * @param cb_cls closure for 'cb'
548  * @return handle to use
549  */
550 struct GNUNET_IDENTITY_Handle *
551 GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
552                          GNUNET_IDENTITY_Callback cb,
553                          void *cb_cls)
554 {
555   struct GNUNET_IDENTITY_Handle *h;
556
557   h = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Handle));
558   h->cfg = cfg;
559   h->cb = cb;
560   h->cb_cls = cb_cls;
561   h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
562   h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, h);
563   return h;
564 }
565
566
567 /**
568  * Obtain the ECC key associated with a ego.
569  *
570  * @param ego the ego
571  * @return associated ECC key, valid as long as the ego is valid
572  */
573 const struct GNUNET_CRYPTO_EccPrivateKey *
574 GNUNET_IDENTITY_ego_get_key (struct GNUNET_IDENTITY_Ego *ego)
575 {
576   return ego->pk;
577 }
578
579
580 /**
581  * Obtain the identity that is currently preferred/default
582  * for a service.
583  *
584  * @param id identity service to query
585  * @param service_name for which service is an identity wanted
586  * @param cb function to call with the result (will only be called once)
587  * @param cb_cls closure for cb
588  * @return handle to abort the operation
589  */
590 struct GNUNET_IDENTITY_Operation *
591 GNUNET_IDENTITY_get (struct GNUNET_IDENTITY_Handle *id,
592                      const char *service_name,
593                      GNUNET_IDENTITY_Callback cb,
594                      void *cb_cls)
595 {
596   GNUNET_break (0); // FIXME
597   return NULL;
598 }
599
600
601 /**
602  * Set the preferred/default identity for a service.
603  *
604  * @param id identity service to inform
605  * @param service_name for which service is an identity set
606  * @param ego new default identity to be set for this service
607  * @param cont function to call once the operation finished
608  * @param cont_cls closure for cont
609  * @return handle to abort the operation
610  */
611 struct GNUNET_IDENTITY_Operation *
612 GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *id,
613                      const char *service_name,
614                      struct GNUNET_IDENTITY_Ego *ego,
615                      GNUNET_IDENTITY_Continuation cont,
616                      void *cont_cls)
617 {
618   GNUNET_break (0); // FIXME
619   return NULL;
620 }
621
622
623 /** 
624  * Create a new identity with the given identifier.
625  *
626  * @param id identity service to use
627  * @param identifier desired identifier
628  * @param cb function to call with the result (will only be called once)
629  * @param cb_cls closure for cb
630  * @return handle to abort the operation
631  */
632 struct GNUNET_IDENTITY_Operation *
633 GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *id,
634                         const char *identifier,
635                         GNUNET_IDENTITY_Callback cb,
636                         void *cb_cls)
637 {
638   GNUNET_break (0); // FIXME
639   return NULL;
640 }
641
642
643 /** 
644  * Renames an existing identity.
645  *
646  * @param id identity service to use
647  * @param old_identifier old identifier
648  * @param new_identifier desired new identifier
649  * @param cb function to call with the result (will only be called once)
650  * @param cb_cls closure for cb
651  * @return handle to abort the operation
652  */
653 struct GNUNET_IDENTITY_Operation *
654 GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *id,
655                         const char *old_identifier,
656                         const char *new_identifier,
657                         GNUNET_IDENTITY_Continuation cb,
658                         void *cb_cls)
659 {
660   GNUNET_break (0); // FIXME
661   return NULL;
662 }
663
664
665 /** 
666  * Delete an existing identity.
667  *
668  * @param id identity service to use
669  * @param identifier identifier of the identity to delete
670  * @param cb function to call with the result (will only be called once)
671  * @param cb_cls closure for cb
672  * @return handle to abort the operation
673  */
674 struct GNUNET_IDENTITY_Operation *
675 GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *id,
676                         const char *identifier,
677                         GNUNET_IDENTITY_Continuation cb,
678                         void *cb_cls)
679 {
680   GNUNET_break (0); // FIXME
681   return NULL;
682 }
683
684
685 /**
686  * Cancel an identity operation. Note that the operation MAY still
687  * be executed; this merely cancels the continuation; if the request
688  * was already transmitted, the service may still choose to complete
689  * the operation.
690  *
691  * @param op operation to cancel
692  */
693 void
694 GNUNET_IDENITY_cancel (struct GNUNET_IDENTITY_Operation *op)
695 {
696   struct GNUNET_IDENTITY_Handle *h = op->h;
697
698   if ( (h->op_head != op) ||
699        (NULL == h->client) )
700   {
701     /* request not active, can simply remove */
702     GNUNET_CONTAINER_DLL_remove (h->op_head,
703                                  h->op_tail,
704                                  op);
705     GNUNET_free (op);
706     return;
707   }
708   if (NULL != h->th)
709   {
710     /* request active but not yet with service, can still abort */
711     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
712     h->th = NULL;
713     GNUNET_CONTAINER_DLL_remove (h->op_head,
714                                  h->op_tail,
715                                  op);
716     GNUNET_free (op);
717     transmit_next (h);
718     return;
719   }
720   /* request active with service, simply ensure continuations are not called */
721   op->cont = NULL;
722   op->cb = NULL;
723 }
724
725
726 /**
727  * Disconnect from identity service
728  *
729  * @param h handle to destroy
730  */
731 void
732 GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
733 {
734   GNUNET_assert (NULL != h);
735   if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
736   {
737     GNUNET_SCHEDULER_cancel (h->reconnect_task);
738     h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
739   }
740   if (NULL != h->th)
741   {
742     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
743     h->th = NULL;
744   }
745   if (NULL != h->client)
746   {
747     GNUNET_CLIENT_disconnect (h->client);
748     h->client = NULL;
749   }
750   GNUNET_free (h);
751 }
752
753 /* end of identity_api.c */