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