f03f7b449f505095f8fa7082b50f6ff9ef23b5fe
[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   return NULL;
597 }
598
599
600 /**
601  * Set the preferred/default identity for a service.
602  *
603  * @param id identity service to inform
604  * @param service_name for which service is an identity set
605  * @param ego new default identity to be set for this service
606  * @param cont function to call once the operation finished
607  * @param cont_cls closure for cont
608  * @return handle to abort the operation
609  */
610 struct GNUNET_IDENTITY_Operation *
611 GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *id,
612                      const char *service_name,
613                      struct GNUNET_IDENTITY_Ego *ego,
614                      GNUNET_IDENTITY_Continuation cont,
615                      void *cont_cls)
616 {
617   return NULL;
618 }
619
620
621 /** 
622  * Create a new identity with the given identifier.
623  *
624  * @param id identity service to use
625  * @param identifier desired identifier
626  * @param cb function to call with the result (will only be called once)
627  * @param cb_cls closure for cb
628  * @return handle to abort the operation
629  */
630 struct GNUNET_IDENTITY_Operation *
631 GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *id,
632                         const char *identifier,
633                         GNUNET_IDENTITY_Callback cb,
634                         void *cb_cls)
635 {
636   return NULL;
637 }
638
639
640 /** 
641  * Renames an existing identity.
642  *
643  * @param id identity service to use
644  * @param old_identifier old identifier
645  * @param new_identifier desired new identifier
646  * @param cb function to call with the result (will only be called once)
647  * @param cb_cls closure for cb
648  * @return handle to abort the operation
649  */
650 struct GNUNET_IDENTITY_Operation *
651 GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *id,
652                         const char *old_identifier,
653                         const char *new_identifier,
654                         GNUNET_IDENTITY_Continuation cb,
655                         void *cb_cls)
656 {
657   return NULL;
658 }
659
660
661 /** 
662  * Delete an existing identity.
663  *
664  * @param id identity service to use
665  * @param identifier identifier of the identity to delete
666  * @param cb function to call with the result (will only be called once)
667  * @param cb_cls closure for cb
668  * @return handle to abort the operation
669  */
670 struct GNUNET_IDENTITY_Operation *
671 GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *id,
672                         const char *identifier,
673                         GNUNET_IDENTITY_Continuation cb,
674                         void *cb_cls)
675 {
676   return NULL;
677 }
678
679
680 /**
681  * Cancel an identity operation. Note that the operation MAY still
682  * be executed; this merely cancels the continuation; if the request
683  * was already transmitted, the service may still choose to complete
684  * the operation.
685  *
686  * @param op operation to cancel
687  */
688 void
689 GNUNET_IDENITY_cancel (struct GNUNET_IDENTITY_Operation *op)
690 {
691   struct GNUNET_IDENTITY_Handle *h = op->h;
692
693   if ( (h->op_head != op) ||
694        (NULL == h->client) )
695   {
696     /* request not active, can simply remove */
697     GNUNET_CONTAINER_DLL_remove (h->op_head,
698                                  h->op_tail,
699                                  op);
700     GNUNET_free (op);
701     return;
702   }
703   if (NULL != h->th)
704   {
705     /* request active but not yet with service, can still abort */
706     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
707     h->th = NULL;
708     GNUNET_CONTAINER_DLL_remove (h->op_head,
709                                  h->op_tail,
710                                  op);
711     GNUNET_free (op);
712     transmit_next (h);
713     return;
714   }
715   /* request active with service, simply ensure continuations are not called */
716   op->cont = NULL;
717   op->cb = NULL;
718 }
719
720
721 /**
722  * Disconnect from identity service
723  *
724  * @param h handle to destroy
725  */
726 void
727 GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
728 {
729   GNUNET_assert (NULL != h);
730   if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
731   {
732     GNUNET_SCHEDULER_cancel (h->reconnect_task);
733     h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
734   }
735   if (NULL != h->th)
736   {
737     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
738     h->th = NULL;
739   }
740   if (NULL != h->client)
741   {
742     GNUNET_CLIENT_disconnect (h->client);
743     h->client = NULL;
744   }
745   GNUNET_free (h);
746 }
747
748 /* end of identity_api.c */