glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / identity / identity_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 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
16 /**
17  * @file identity/identity_api.c
18  * @brief api to interact with the identity service
19  * @author Christian Grothoff
20  */
21 #include "platform.h"
22 #include "gnunet_util_lib.h"
23 #include "gnunet_constants.h"
24 #include "gnunet_protocols.h"
25 #include "gnunet_identity_service.h"
26 #include "identity.h"
27
28 #define LOG(kind,...) GNUNET_log_from (kind, "identity-api",__VA_ARGS__)
29
30 /**
31  * Handle for an ego.
32  */
33 struct GNUNET_IDENTITY_Ego
34 {
35   /**
36    * Private key associated with this ego.
37    */
38   struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
39
40   /**
41    * Current name associated with this ego.
42    */
43   char *name;
44
45   /**
46    * Client context associated with this ego.
47    */
48   void *ctx;
49
50   /**
51    * Hash of the public key of this ego.
52    */
53   struct GNUNET_HashCode id;
54 };
55
56
57 /**
58  * Handle for an operation with the identity service.
59  */
60 struct GNUNET_IDENTITY_Operation
61 {
62
63   /**
64    * Main identity handle.
65    */
66   struct GNUNET_IDENTITY_Handle *h;
67
68   /**
69    * We keep operations in a DLL.
70    */
71   struct GNUNET_IDENTITY_Operation *next;
72
73   /**
74    * We keep operations in a DLL.
75    */
76   struct GNUNET_IDENTITY_Operation *prev;
77
78   /**
79    * Message to send to the identity service.
80    * Allocated at the end of this struct.
81    */
82   const struct GNUNET_MessageHeader *msg;
83
84   /**
85    * Continuation to invoke with the result of the transmission; @e cb
86    * will be NULL in this case.
87    */
88   GNUNET_IDENTITY_Continuation cont;
89
90   /**
91    * Continuation to invoke with the result of the transmission for
92    * 'get' operations (@e cont will be NULL in this case).
93    */
94   GNUNET_IDENTITY_Callback cb;
95
96   /**
97    * Closure for @e cont or @e cb.
98    */
99   void *cls;
100
101 };
102
103
104 /**
105  * Handle for the service.
106  */
107 struct GNUNET_IDENTITY_Handle
108 {
109   /**
110    * Configuration to use.
111    */
112   const struct GNUNET_CONFIGURATION_Handle *cfg;
113
114   /**
115    * Connection to service.
116    */
117   struct GNUNET_MQ_Handle *mq;
118
119   /**
120    * Hash map from the hash of the public key to the
121    * respective `GNUNET_IDENTITY_Ego` handle.
122    */
123   struct GNUNET_CONTAINER_MultiHashMap *egos;
124
125   /**
126    * Function to call when we receive updates.
127    */
128   GNUNET_IDENTITY_Callback cb;
129
130   /**
131    * Closure for @e cb.
132    */
133   void *cb_cls;
134
135   /**
136    * Head of active operations.
137    */
138   struct GNUNET_IDENTITY_Operation *op_head;
139
140   /**
141    * Tail of active operations.
142    */
143   struct GNUNET_IDENTITY_Operation *op_tail;
144
145   /**
146    * Task doing exponential back-off trying to reconnect.
147    */
148   struct GNUNET_SCHEDULER_Task *reconnect_task;
149
150   /**
151    * Time for next connect retry.
152    */
153   struct GNUNET_TIME_Relative reconnect_delay;
154
155   /**
156    * Are we polling for incoming messages right now?
157    */
158   int in_receive;
159
160 };
161
162
163 /**
164  * Obtain the ego representing 'anonymous' users.
165  *
166  * @return handle for the anonymous user, must not be freed
167  */
168 const struct GNUNET_IDENTITY_Ego *
169 GNUNET_IDENTITY_ego_get_anonymous ()
170 {
171   static struct GNUNET_IDENTITY_Ego anon;
172   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
173
174   if (NULL != anon.pk)
175     return &anon;
176   anon.pk = (struct GNUNET_CRYPTO_EcdsaPrivateKey *) GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
177   GNUNET_CRYPTO_ecdsa_key_get_public (anon.pk,
178                                       &pub);
179   GNUNET_CRYPTO_hash (&pub,
180                       sizeof (pub),
181                       &anon.id);
182   return &anon;
183 }
184
185
186 /**
187  * Try again to connect to the identity service.
188  *
189  * @param cls handle to the identity service.
190  */
191 static void
192 reconnect (void *cls);
193
194
195 /**
196  * Free ego from hash map.
197  *
198  * @param cls identity service handle
199  * @param key unused
200  * @param value ego to free
201  * @return #GNUNET_OK (continue to iterate)
202  */
203 static int
204 free_ego (void *cls,
205           const struct GNUNET_HashCode *key,
206           void *value)
207 {
208   struct GNUNET_IDENTITY_Handle *h = cls;
209   struct GNUNET_IDENTITY_Ego *ego = value;
210
211   if (NULL != h->cb)
212     h->cb (h->cb_cls,
213            ego,
214            &ego->ctx,
215            NULL);
216   GNUNET_free (ego->pk);
217   GNUNET_free (ego->name);
218   GNUNET_assert (GNUNET_YES ==
219                  GNUNET_CONTAINER_multihashmap_remove (h->egos,
220                                                        key,
221                                                        value));
222   GNUNET_free (ego);
223   return GNUNET_OK;
224 }
225
226
227 /**
228  * Reschedule a connect attempt to the service.
229  *
230  * @param h transport service to reconnect
231  */
232 static void
233 reschedule_connect (struct GNUNET_IDENTITY_Handle *h)
234 {
235   struct GNUNET_IDENTITY_Operation *op;
236
237   GNUNET_assert (NULL == h->reconnect_task);
238
239   if (NULL != h->mq)
240   {
241     GNUNET_MQ_destroy (h->mq);
242     h->mq = NULL;
243   }
244   while (NULL != (op = h->op_head))
245   {
246     GNUNET_CONTAINER_DLL_remove (h->op_head,
247                                  h->op_tail,
248                                  op);
249     if (NULL != op->cont)
250       op->cont (op->cls,
251                 "Error in communication with the identity service");
252     else if (NULL != op->cb)
253       op->cb (op->cls,
254               NULL,
255               NULL,
256               NULL);
257     GNUNET_free (op);
258   }
259   GNUNET_CONTAINER_multihashmap_iterate (h->egos,
260                                          &free_ego,
261                                          h);
262   LOG (GNUNET_ERROR_TYPE_DEBUG,
263        "Scheduling task to reconnect to identity service in %s.\n",
264        GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay,
265                                                GNUNET_YES));
266   h->reconnect_task =
267       GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
268                                     &reconnect,
269                                     h);
270   h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
271 }
272
273
274 /**
275  * Generic error handler, called with the appropriate error code and
276  * the same closure specified at the creation of the message queue.
277  * Not every message queue implementation supports an error handler.
278  *
279  * @param cls closure with the `struct GNUNET_IDENTITY_Handle *`
280  * @param error error code
281  */
282 static void
283 mq_error_handler (void *cls,
284                   enum GNUNET_MQ_Error error)
285 {
286   struct GNUNET_IDENTITY_Handle *h = cls;
287
288   reschedule_connect (h);
289 }
290
291
292 /**
293  * We received a result code from the service.  Check the message
294  * is well-formed.
295  *
296  * @param cls closure
297  * @param rcm result message received
298  * @return #GNUNET_OK if the message is well-formed
299  */
300 static int
301 check_identity_result_code (void *cls,
302                             const struct ResultCodeMessage *rcm)
303 {
304   uint16_t size = ntohs (rcm->header.size) - sizeof (*rcm);
305   const char *str = (const char *) &rcm[1];
306
307   if (0 == size)
308     return GNUNET_OK;
309   if ('\0' != str[size - 1])
310   {
311     GNUNET_break (0);
312     return GNUNET_SYSERR;
313   }
314   return GNUNET_OK;
315 }
316
317
318 /**
319  * We received a result code from the service.
320  *
321  * @param cls closure
322  * @param rcm result message received
323  */
324 static void
325 handle_identity_result_code (void *cls,
326                              const struct ResultCodeMessage *rcm)
327 {
328   struct GNUNET_IDENTITY_Handle *h = cls;
329   struct GNUNET_IDENTITY_Operation *op;
330   uint16_t size = ntohs (rcm->header.size) - sizeof (*rcm);
331   const char *str = (0 == size) ? NULL : (const char *) &rcm[1];
332
333   op = h->op_head;
334   if (NULL == op)
335   {
336     GNUNET_break (0);
337     reschedule_connect (h);
338     return;
339   }
340   GNUNET_CONTAINER_DLL_remove (h->op_head,
341                                h->op_tail,
342                                op);
343   if (NULL != op->cont)
344     op->cont (op->cls,
345               str);
346   else if (NULL != op->cb)
347     op->cb (op->cls, NULL, NULL, NULL);
348   GNUNET_free (op);
349 }
350
351
352 /**
353  * Check validity of identity update message.
354  *
355  * @param cls closure
356  * @param um message received
357  * @return #GNUNET_OK if the message is well-formed
358  */
359 static int
360 check_identity_update (void *cls,
361                         const struct UpdateMessage *um)
362 {
363   uint16_t size = ntohs (um->header.size);
364   uint16_t name_len = ntohs (um->name_len);
365   const char *str = (const char *) &um[1];
366
367   if ( (size != name_len + sizeof (struct UpdateMessage)) ||
368        ( (0 != name_len) &&
369          ('\0' != str[name_len - 1])) )
370   {
371     GNUNET_break (0);
372     return GNUNET_SYSERR;
373   }
374   return GNUNET_OK;
375 }
376
377
378 /**
379  * Handle identity update message.
380  *
381  * @param cls closure
382  * @param um message received
383  */
384 static void
385 handle_identity_update (void *cls,
386                         const struct UpdateMessage *um)
387 {
388   struct GNUNET_IDENTITY_Handle *h = cls;
389   uint16_t name_len = ntohs (um->name_len);
390   const char *str = (0 == name_len) ? NULL : (const char *) &um[1];
391   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
392   struct GNUNET_HashCode id;
393   struct GNUNET_IDENTITY_Ego *ego;
394
395   if (GNUNET_YES == ntohs (um->end_of_list))
396   {
397     /* end of initial list of data */
398     if (NULL != h->cb)
399       h->cb (h->cb_cls,
400              NULL,
401              NULL,
402              NULL);
403     return;
404   }
405   GNUNET_CRYPTO_ecdsa_key_get_public (&um->private_key,
406                                       &pub);
407   GNUNET_CRYPTO_hash (&pub,
408                       sizeof (pub),
409                       &id);
410   ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
411                                            &id);
412   if (NULL == ego)
413   {
414     /* ego was created */
415     if (NULL == str)
416     {
417       /* deletion of unknown ego? not allowed */
418       GNUNET_break (0);
419       reschedule_connect (h);
420       return;
421     }
422     ego = GNUNET_new (struct GNUNET_IDENTITY_Ego);
423     ego->pk = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
424     *ego->pk = um->private_key;
425     ego->name = GNUNET_strdup (str);
426     ego->id = id;
427     GNUNET_assert (GNUNET_YES ==
428                    GNUNET_CONTAINER_multihashmap_put (h->egos,
429                                                       &ego->id,
430                                                       ego,
431                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
432   }
433   if (NULL == str)
434   {
435     /* ego was deleted */
436     GNUNET_assert (GNUNET_YES ==
437                    GNUNET_CONTAINER_multihashmap_remove (h->egos,
438                                                          &ego->id,
439                                                          ego));
440   }
441   else
442   {
443     /* ego changed name */
444     GNUNET_free (ego->name);
445     ego->name = GNUNET_strdup (str);
446   }
447   /* inform application about change */
448   if (NULL != h->cb)
449     h->cb (h->cb_cls,
450            ego,
451            &ego->ctx,
452            str);
453   /* complete deletion */
454   if (NULL == str)
455   {
456     GNUNET_free (ego->pk);
457     GNUNET_free (ego->name);
458     GNUNET_free (ego);
459   }
460 }
461
462
463 /**
464  * Function called when we receive a set default message from the
465  * service.
466  *
467  * @param cls closure
468  * @param sdm message received
469  * @return #GNUNET_OK if the message is well-formed
470  */
471 static int
472 check_identity_set_default (void *cls,
473                             const struct SetDefaultMessage *sdm)
474 {
475   uint16_t size = ntohs (sdm->header.size) - sizeof (*sdm);
476   uint16_t name_len = ntohs (sdm->name_len);
477   const char *str = (const char *) &sdm[1];
478
479   if ( (size != name_len) ||
480        ( (0 != name_len) &&
481          ('\0' != str[name_len - 1]) ) )
482   {
483     GNUNET_break (0);
484     return GNUNET_SYSERR;
485   }
486   GNUNET_break (0 == ntohs (sdm->reserved));
487   return GNUNET_OK;
488 }
489
490
491 /**
492  * Type of a function to call when we receive a message
493  * from the service.
494  *
495  * @param cls closure
496  * @param sdm message received
497  */
498 static void
499 handle_identity_set_default (void *cls,
500                              const struct SetDefaultMessage *sdm)
501 {
502   struct GNUNET_IDENTITY_Handle *h = cls;
503   struct GNUNET_IDENTITY_Operation *op;
504   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
505   struct GNUNET_HashCode id;
506   struct GNUNET_IDENTITY_Ego *ego;
507
508   GNUNET_CRYPTO_ecdsa_key_get_public (&sdm->private_key,
509                                       &pub);
510   GNUNET_CRYPTO_hash (&pub,
511                       sizeof (pub),
512                       &id);
513   ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
514                                            &id);
515   if (NULL == ego)
516   {
517     GNUNET_break (0);
518     reschedule_connect (h);
519     return;
520   }
521   op = h->op_head;
522   if (NULL == op)
523   {
524     GNUNET_break (0);
525     reschedule_connect (h);
526     return;
527   }
528   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529               "Received SET_DEFAULT message from identity service\n");
530   GNUNET_CONTAINER_DLL_remove (h->op_head,
531                                h->op_tail,
532                                op);
533   if (NULL != op->cb)
534     op->cb (op->cls,
535             ego,
536             &ego->ctx,
537             ego->name);
538   GNUNET_free (op);
539 }
540
541
542 /**
543  * Try again to connect to the identity service.
544  *
545  * @param cls handle to the identity service.
546  */
547 static void
548 reconnect (void *cls)
549 {
550   struct GNUNET_IDENTITY_Handle *h = cls;
551   struct GNUNET_MQ_MessageHandler handlers[] = {
552     GNUNET_MQ_hd_var_size (identity_result_code,
553                            GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE,
554                            struct ResultCodeMessage,
555                            h),
556     GNUNET_MQ_hd_var_size (identity_update,
557                            GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE,
558                            struct UpdateMessage,
559                            h),
560     GNUNET_MQ_hd_var_size (identity_set_default,
561                            GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT,
562                            struct SetDefaultMessage,
563                            h),
564     GNUNET_MQ_handler_end ()
565   };
566   struct GNUNET_MQ_Envelope *env;
567   struct GNUNET_MessageHeader *msg;
568
569   h->reconnect_task = NULL;
570   LOG (GNUNET_ERROR_TYPE_DEBUG,
571        "Connecting to identity service.\n");
572   GNUNET_assert (NULL == h->mq);
573   h->mq = GNUNET_CLIENT_connect (h->cfg,
574                                  "identity",
575                                  handlers,
576                                  &mq_error_handler,
577                                  h);
578   if (NULL == h->mq)
579     return;
580   env = GNUNET_MQ_msg (msg,
581                        GNUNET_MESSAGE_TYPE_IDENTITY_START);
582   GNUNET_MQ_send (h->mq,
583                   env);
584 }
585
586
587 /**
588  * Connect to the identity service.
589  *
590  * @param cfg the configuration to use
591  * @param cb function to call on all identity events, can be NULL
592  * @param cb_cls closure for @a cb
593  * @return handle to use
594  */
595 struct GNUNET_IDENTITY_Handle *
596 GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
597                          GNUNET_IDENTITY_Callback cb,
598                          void *cb_cls)
599 {
600   struct GNUNET_IDENTITY_Handle *h;
601
602   h = GNUNET_new (struct GNUNET_IDENTITY_Handle);
603   h->cfg = cfg;
604   h->cb = cb;
605   h->cb_cls = cb_cls;
606   h->egos = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_YES);
607   reconnect (h);
608   if (NULL == h->mq)
609   {
610     GNUNET_free (h);
611     return NULL;
612   }
613   return h;
614 }
615
616
617 /**
618  * Obtain the ECC key associated with a ego.
619  *
620  * @param ego the ego
621  * @return associated ECC key, valid as long as the ego is valid
622  */
623 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
624 GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego)
625 {
626   return ego->pk;
627 }
628
629
630 /**
631  * Get the identifier (public key) of an ego.
632  *
633  * @param ego identity handle with the private key
634  * @param pk set to ego's public key
635  */
636 void
637 GNUNET_IDENTITY_ego_get_public_key (const struct GNUNET_IDENTITY_Ego *ego,
638                                     struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
639 {
640   GNUNET_CRYPTO_ecdsa_key_get_public (ego->pk,
641                                       pk);
642 }
643
644
645 /**
646  * Obtain the identity that is currently preferred/default
647  * for a service.
648  *
649  * @param h identity service to query
650  * @param service_name for which service is an identity wanted
651  * @param cb function to call with the result (will only be called once)
652  * @param cb_cls closure for @a cb
653  * @return handle to abort the operation
654  */
655 struct GNUNET_IDENTITY_Operation *
656 GNUNET_IDENTITY_get (struct GNUNET_IDENTITY_Handle *h,
657                      const char *service_name,
658                      GNUNET_IDENTITY_Callback cb,
659                      void *cb_cls)
660 {
661   struct GNUNET_IDENTITY_Operation *op;
662   struct GNUNET_MQ_Envelope *env;
663   struct GetDefaultMessage *gdm;
664   size_t slen;
665
666   if (NULL == h->mq)
667     return NULL;
668   slen = strlen (service_name) + 1;
669   if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct GetDefaultMessage))
670   {
671     GNUNET_break (0);
672     return NULL;
673   }
674   op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
675   op->h = h;
676   op->cb = cb;
677   op->cls = cb_cls;
678   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
679                                     h->op_tail,
680                                     op);
681   env = GNUNET_MQ_msg_extra (gdm,
682                              slen,
683                              GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT);
684   gdm->name_len = htons (slen);
685   gdm->reserved = htons (0);
686   GNUNET_memcpy (&gdm[1],
687           service_name,
688           slen);
689   GNUNET_MQ_send (h->mq,
690                   env);
691   return op;
692 }
693
694
695 /**
696  * Set the preferred/default identity for a service.
697  *
698  * @param h identity service to inform
699  * @param service_name for which service is an identity set
700  * @param ego new default identity to be set for this service
701  * @param cont function to call once the operation finished
702  * @param cont_cls closure for @a cont
703  * @return handle to abort the operation
704  */
705 struct GNUNET_IDENTITY_Operation *
706 GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *h,
707                      const char *service_name,
708                      struct GNUNET_IDENTITY_Ego *ego,
709                      GNUNET_IDENTITY_Continuation cont,
710                      void *cont_cls)
711 {
712   struct GNUNET_IDENTITY_Operation *op;
713   struct GNUNET_MQ_Envelope *env;
714   struct SetDefaultMessage *sdm;
715   size_t slen;
716
717   if (NULL == h->mq)
718     return NULL;
719   slen = strlen (service_name) + 1;
720   if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct SetDefaultMessage))
721   {
722     GNUNET_break (0);
723     return NULL;
724   }
725   op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
726   op->h = h;
727   op->cont = cont;
728   op->cls = cont_cls;
729   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
730                                     h->op_tail,
731                                     op);
732   env = GNUNET_MQ_msg_extra (sdm,
733                              slen,
734                              GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT);
735   sdm->name_len = htons (slen);
736   sdm->reserved = htons (0);
737   sdm->private_key = *ego->pk;
738   GNUNET_memcpy (&sdm[1],
739           service_name,
740           slen);
741   GNUNET_MQ_send (h->mq,
742                   env);
743   return op;
744 }
745
746
747 /**
748  * Create a new identity with the given name.
749  *
750  * @param h identity service to use
751  * @param name desired name
752  * @param cont function to call with the result (will only be called once)
753  * @param cont_cls closure for @a cont
754  * @return handle to abort the operation
755  */
756 struct GNUNET_IDENTITY_Operation *
757 GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *h,
758                         const char *name,
759                         GNUNET_IDENTITY_Continuation cont,
760                         void *cont_cls)
761 {
762   struct GNUNET_IDENTITY_Operation *op;
763   struct GNUNET_MQ_Envelope *env;
764   struct CreateRequestMessage *crm;
765   struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
766   size_t slen;
767
768   if (NULL == h->mq)
769     return NULL;
770   slen = strlen (name) + 1;
771   if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct CreateRequestMessage))
772   {
773     GNUNET_break (0);
774     return NULL;
775   }
776   op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
777   op->h = h;
778   op->cont = cont;
779   op->cls = cont_cls;
780   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
781                                     h->op_tail,
782                                     op);
783   env = GNUNET_MQ_msg_extra (crm,
784                              slen,
785                              GNUNET_MESSAGE_TYPE_IDENTITY_CREATE);
786   crm->name_len = htons (slen);
787   crm->reserved = htons (0);
788   pk = GNUNET_CRYPTO_ecdsa_key_create ();
789   crm->private_key = *pk;
790   GNUNET_free (pk);
791   GNUNET_memcpy (&crm[1],
792           name,
793           slen);
794   GNUNET_MQ_send (h->mq,
795                   env);
796   return op;
797 }
798
799
800 /**
801  * Renames an existing identity.
802  *
803  * @param h identity service to use
804  * @param old_name old name
805  * @param new_name desired new name
806  * @param cb function to call with the result (will only be called once)
807  * @param cb_cls closure for @a cb
808  * @return handle to abort the operation
809  */
810 struct GNUNET_IDENTITY_Operation *
811 GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *h,
812                         const char *old_name,
813                         const char *new_name,
814                         GNUNET_IDENTITY_Continuation cb,
815                         void *cb_cls)
816 {
817   struct GNUNET_IDENTITY_Operation *op;
818   struct GNUNET_MQ_Envelope *env;
819   struct RenameMessage *grm;
820   size_t slen_old;
821   size_t slen_new;
822   char *dst;
823
824   if (NULL == h->mq)
825     return NULL;
826   slen_old = strlen (old_name) + 1;
827   slen_new = strlen (new_name) + 1;
828   if ( (slen_old >= GNUNET_MAX_MESSAGE_SIZE) ||
829        (slen_new >= GNUNET_MAX_MESSAGE_SIZE) ||
830        (slen_old + slen_new >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct RenameMessage)) )
831   {
832     GNUNET_break (0);
833     return NULL;
834   }
835   op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
836   op->h = h;
837   op->cont = cb;
838   op->cls = cb_cls;
839   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
840                                     h->op_tail,
841                                     op);
842   env = GNUNET_MQ_msg_extra (grm,
843                              slen_old + slen_new,
844                              GNUNET_MESSAGE_TYPE_IDENTITY_RENAME);
845   grm->old_name_len = htons (slen_old);
846   grm->new_name_len = htons (slen_new);
847   dst = (char *) &grm[1];
848   GNUNET_memcpy (dst,
849           old_name,
850           slen_old);
851   GNUNET_memcpy (&dst[slen_old],
852           new_name,
853           slen_new);
854   GNUNET_MQ_send (h->mq,
855                   env);
856   return op;
857 }
858
859
860 /**
861  * Delete an existing identity.
862  *
863  * @param h identity service to use
864  * @param name name of the identity to delete
865  * @param cb function to call with the result (will only be called once)
866  * @param cb_cls closure for @a cb
867  * @return handle to abort the operation
868  */
869 struct GNUNET_IDENTITY_Operation *
870 GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *h,
871                         const char *name,
872                         GNUNET_IDENTITY_Continuation cb,
873                         void *cb_cls)
874 {
875   struct GNUNET_IDENTITY_Operation *op;
876   struct GNUNET_MQ_Envelope *env;
877   struct DeleteMessage *gdm;
878   size_t slen;
879
880   if (NULL == h->mq)
881     return NULL;
882   slen = strlen (name) + 1;
883   if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct DeleteMessage))
884   {
885     GNUNET_break (0);
886     return NULL;
887   }
888   op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
889   op->h = h;
890   op->cont = cb;
891   op->cls = cb_cls;
892   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
893                                     h->op_tail,
894                                     op);
895   env = GNUNET_MQ_msg_extra (gdm,
896                              slen,
897                              GNUNET_MESSAGE_TYPE_IDENTITY_DELETE);
898   gdm->name_len = htons (slen);
899   gdm->reserved = htons (0);
900   GNUNET_memcpy (&gdm[1],
901           name,
902           slen);
903   GNUNET_MQ_send (h->mq,
904                   env);
905   return op;
906 }
907
908
909 /**
910  * Cancel an identity operation. Note that the operation MAY still
911  * be executed; this merely cancels the continuation; if the request
912  * was already transmitted, the service may still choose to complete
913  * the operation.
914  *
915  * @param op operation to cancel
916  */
917 void
918 GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op)
919 {
920   op->cont = NULL;
921   op->cb = NULL;
922 }
923
924
925 /**
926  * Disconnect from identity service
927  *
928  * @param h handle to destroy
929  */
930 void
931 GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
932 {
933   struct GNUNET_IDENTITY_Operation *op;
934
935   GNUNET_assert (NULL != h);
936   if (h->reconnect_task != NULL)
937   {
938     GNUNET_SCHEDULER_cancel (h->reconnect_task);
939     h->reconnect_task = NULL;
940   }
941   if (NULL != h->egos)
942   {
943     GNUNET_CONTAINER_multihashmap_iterate (h->egos,
944                                            &free_ego,
945                                            h);
946     GNUNET_CONTAINER_multihashmap_destroy (h->egos);
947     h->egos = NULL;
948   }
949   while (NULL != (op = h->op_head))
950   {
951     GNUNET_break (NULL == op->cont);
952     GNUNET_CONTAINER_DLL_remove (h->op_head,
953                                  h->op_tail,
954                                  op);
955     GNUNET_free (op);
956   }
957   if (NULL != h->mq)
958   {
959     GNUNET_MQ_destroy (h->mq);
960     h->mq = NULL;
961   }
962   GNUNET_free (h);
963 }
964
965 /* end of identity_api.c */