removing GNUNET_CRYPTO_ecc_key_free, use GNUNET_free directly instead
[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 name associated with this ego.
52    */
53   char *name;
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  * Obtain the ego representing 'anonymous' users.
180  */
181 const struct GNUNET_IDENTITY_Ego *
182 GNUNET_IDENTITY_ego_get_anonymous ()
183 {
184   static struct GNUNET_IDENTITY_Ego anon;
185   struct GNUNET_CRYPTO_EccPublicKey pub;
186
187   if (NULL != anon.pk)
188     return &anon;
189   anon.pk = (struct GNUNET_CRYPTO_EccPrivateKey *) GNUNET_CRYPTO_ecc_key_get_anonymous ();
190   GNUNET_CRYPTO_ecc_key_get_public (anon.pk,
191                                     &pub);
192   GNUNET_CRYPTO_hash (&pub, sizeof (pub), &anon.id);
193   return &anon;
194 }
195
196
197 /**
198  * Try again to connect to network size estimation service.
199  *
200  * @param cls the handle to the transport service
201  * @param tc scheduler context
202  */
203 static void
204 reconnect (void *cls,
205            const struct GNUNET_SCHEDULER_TaskContext *tc);
206
207
208 /**
209  * Reschedule a connect attempt to the service.
210  *
211  * @param h transport service to reconnect
212  */
213 static void
214 reschedule_connect (struct GNUNET_IDENTITY_Handle *h)
215 {
216   GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
217
218   if (NULL != h->th)
219   {
220     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
221     h->th = NULL;
222   }
223   if (NULL != h->client)
224   {
225     GNUNET_CLIENT_disconnect (h->client);
226     h->client = NULL;
227   }
228   h->in_receive = GNUNET_NO;
229   LOG (GNUNET_ERROR_TYPE_DEBUG,
230        "Scheduling task to reconnect to identity service in %s.\n",
231        GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
232   h->reconnect_task =
233       GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
234   h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
235 }
236
237
238 /**
239  * Type of a function to call when we receive a message
240  * from the service.
241  *
242  * @param cls closure
243  * @param msg message received, NULL on timeout or fatal error
244  */
245 static void
246 message_handler (void *cls, 
247                  const struct GNUNET_MessageHeader *msg)
248 {
249   struct GNUNET_IDENTITY_Handle *h = cls;
250   struct GNUNET_IDENTITY_Operation *op;
251   struct GNUNET_IDENTITY_Ego *ego;
252   const struct GNUNET_IDENTITY_ResultCodeMessage *rcm;
253   const struct GNUNET_IDENTITY_UpdateMessage *um;
254   const struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
255   struct GNUNET_CRYPTO_EccPublicKey pub;
256   struct GNUNET_HashCode id;
257   const char *str;
258   uint16_t size;
259   uint16_t name_len;
260
261   if (NULL == msg)
262   {
263     reschedule_connect (h);
264     return;
265   }
266   LOG (GNUNET_ERROR_TYPE_DEBUG,
267        "Received message of type %d from identity service\n",
268        ntohs (msg->type));
269   size = ntohs (msg->size);
270   switch (ntohs (msg->type))
271   {
272   case GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE:
273     if (size < sizeof (struct GNUNET_IDENTITY_ResultCodeMessage))
274     {
275       GNUNET_break (0);
276       reschedule_connect (h);
277       return;
278     }
279     rcm = (const struct GNUNET_IDENTITY_ResultCodeMessage *) msg;
280     str = (const char *) &rcm[1];
281     if ( (size > sizeof (struct GNUNET_IDENTITY_ResultCodeMessage)) &&
282          ('\0' != str[size - sizeof (struct GNUNET_IDENTITY_ResultCodeMessage) - 1]) )
283     {
284       GNUNET_break (0);
285       reschedule_connect (h);
286       return;
287     }
288     if (size == sizeof (struct GNUNET_IDENTITY_ResultCodeMessage))
289       str = NULL;
290
291     op = h->op_head;
292     GNUNET_CONTAINER_DLL_remove (h->op_head,
293                                  h->op_tail,
294                                  op);
295     if (NULL != op->cont)
296       op->cont (op->cls,
297                 str);
298     else if (NULL != op->cb)
299       op->cb (op->cls, NULL, NULL, NULL);
300     GNUNET_free (op);
301     break;
302   case GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE:
303     if (size < sizeof (struct GNUNET_IDENTITY_UpdateMessage))
304     {
305       GNUNET_break (0);
306       reschedule_connect (h);
307       return;
308     }
309     um = (const struct GNUNET_IDENTITY_UpdateMessage *) msg;
310     name_len = ntohs (um->name_len);
311     
312     str = (const char *) &um[1];
313     if ( (size != name_len + sizeof (struct GNUNET_IDENTITY_UpdateMessage)) ||
314          ( (0 != name_len) &&
315            ('\0' != str[name_len - 1])) )
316     {
317       GNUNET_break (0);
318       reschedule_connect (h);
319       return;
320     }
321     if (GNUNET_YES == ntohs (um->end_of_list))
322     {
323       /* end of initial list of data */
324       if (NULL != h->cb)
325         h->cb (h->cb_cls, NULL, NULL, NULL);
326       break;
327     }
328     GNUNET_CRYPTO_ecc_key_get_public (&um->private_key,
329                                       &pub);
330     GNUNET_CRYPTO_hash (&pub, sizeof (pub), &id);
331     if (0 == name_len)
332       str = NULL;
333     else
334       str = (const char *) &um[1];
335     ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
336                                              &id);
337     if (NULL == ego)
338     {
339       /* ego was created */
340       if (NULL == str)
341       {
342         /* deletion of unknown ego? not allowed */
343         GNUNET_break (0);
344         reschedule_connect (h);
345         return;
346       }
347       ego = GNUNET_new (struct GNUNET_IDENTITY_Ego);
348       ego->pk = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
349       *ego->pk = um->private_key;
350       ego->name = GNUNET_strdup (str);
351       ego->id = id;
352       GNUNET_assert (GNUNET_YES ==
353                      GNUNET_CONTAINER_multihashmap_put (h->egos,
354                                                         &ego->id,
355                                                         ego,
356                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
357     }
358     /* inform application about change */
359     if (NULL != h->cb)
360       h->cb (h->cb_cls,
361              ego,
362              &ego->ctx,
363              str);
364     if (NULL == str)
365     {
366       /* ego was deleted */
367       GNUNET_assert (GNUNET_YES ==
368                      GNUNET_CONTAINER_multihashmap_remove (h->egos,
369                                                            &ego->id,
370                                                            ego));
371       GNUNET_free (ego->pk);
372       GNUNET_free (ego->name);
373       GNUNET_free (ego);
374     }
375     else
376       {
377       /* ego changed name */
378       GNUNET_free (ego->name);
379       ego->name = GNUNET_strdup (str);
380     }    
381     break;
382   case GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT:
383     if (size < sizeof (struct GNUNET_IDENTITY_SetDefaultMessage))
384     {
385       GNUNET_break (0);
386       reschedule_connect (h);
387       return;
388     }
389     sdm = (const struct GNUNET_IDENTITY_SetDefaultMessage *) msg;
390     GNUNET_break (0 == ntohs (sdm->reserved));
391     name_len = ntohs (sdm->name_len);
392     str = (const char *) &sdm[1];
393     if ( (size != name_len + sizeof (struct GNUNET_IDENTITY_SetDefaultMessage)) ||
394          ( (0 != name_len) &&
395            ('\0' != str[name_len - 1]) ) )
396     {
397       GNUNET_break (0);
398       reschedule_connect (h);
399       return;
400     }
401     /* Note: we know which service this should be for, so we're not
402        really using 'str' henceforth */
403     GNUNET_CRYPTO_ecc_key_get_public (&sdm->private_key,
404                                       &pub);
405     GNUNET_CRYPTO_hash (&pub, sizeof (pub), &id);
406     ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
407                                              &id);
408     if (NULL == ego)
409     {
410       GNUNET_break (0);
411       reschedule_connect (h);
412       return;
413     }
414     op = h->op_head;
415     GNUNET_CONTAINER_DLL_remove (h->op_head,
416                                  h->op_tail,
417                                  op);
418     GNUNET_free (ego->name);
419     if (NULL != op->cb)
420       op->cb (op->cls,
421               ego,
422               &ego->ctx,
423               ego->name);
424     GNUNET_free (op);
425     break;
426   default:
427     GNUNET_break (0);
428     reschedule_connect (h);
429     return;
430   }
431   GNUNET_CLIENT_receive (h->client, &message_handler, h,
432                          GNUNET_TIME_UNIT_FOREVER_REL);
433 }
434
435
436 /**
437  * Schedule transmission of the next message from our queue.
438  *
439  * @param h identity handle
440  */
441 static void
442 transmit_next (struct GNUNET_IDENTITY_Handle *h);
443
444
445 /**
446  * Transmit next message to service.
447  *
448  * @param cls the 'struct GNUNET_IDENTITY_Handle'.
449  * @param size number of bytes available in buf
450  * @param buf where to copy the message
451  * @return number of bytes copied to buf
452  */
453 static size_t
454 send_next_message (void *cls, 
455                    size_t size, 
456                    void *buf)
457 {
458   struct GNUNET_IDENTITY_Handle *h = cls;
459   struct GNUNET_IDENTITY_Operation *op = h->op_head;
460   size_t ret;
461   
462   h->th = NULL;
463   if (NULL == op)
464     return 0;
465   ret = ntohs (op->msg->size);
466   if (ret > size)
467   {
468     reschedule_connect (h);
469     return 0;
470   }  
471   LOG (GNUNET_ERROR_TYPE_DEBUG,
472        "Sending message of type %d to identity service\n",
473        ntohs (op->msg->type));
474   memcpy (buf, op->msg, ret);
475   if ( (NULL == op->cont) &&
476        (NULL == op->cb) )
477   {
478     GNUNET_CONTAINER_DLL_remove (h->op_head,
479                                  h->op_tail,
480                                  op);
481     GNUNET_free (op);
482     transmit_next (h);
483   }
484   if (GNUNET_NO == h->in_receive)
485   {
486     h->in_receive = GNUNET_YES;
487     GNUNET_CLIENT_receive (h->client,
488                            &message_handler, h,
489                            GNUNET_TIME_UNIT_FOREVER_REL);
490   }
491   return ret;
492 }
493
494
495 /**
496  * Schedule transmission of the next message from our queue.
497  *
498  * @param h identity handle
499  */
500 static void
501 transmit_next (struct GNUNET_IDENTITY_Handle *h)
502 {
503   struct GNUNET_IDENTITY_Operation *op = h->op_head;
504
505   GNUNET_assert (NULL == h->th);
506   if (NULL == op)
507     return;
508   if (NULL == h->client)
509     return;
510   h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
511                                                ntohs (op->msg->size),
512                                                GNUNET_TIME_UNIT_FOREVER_REL,
513                                                GNUNET_NO,
514                                                &send_next_message,
515                                                h);
516 }
517
518
519 /**
520  * Try again to connect to network size estimation service.
521  *
522  * @param cls the handle to the transport service
523  * @param tc scheduler context
524  */
525 static void
526 reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
527 {
528   struct GNUNET_IDENTITY_Handle *h = cls;
529   struct GNUNET_IDENTITY_Operation *op;
530   struct GNUNET_MessageHeader msg;
531
532   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
533   LOG (GNUNET_ERROR_TYPE_DEBUG,
534        "Connecting to identity service.\n");
535   GNUNET_assert (NULL == h->client);
536   h->client = GNUNET_CLIENT_connect ("identity", h->cfg);
537   GNUNET_assert (NULL != h->client);
538   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) + 
539                       sizeof (struct GNUNET_MessageHeader));
540   op->h = h;
541   op->msg = (const struct GNUNET_MessageHeader *) &op[1];
542   msg.size = htons (sizeof (msg));
543   msg.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_START);
544   memcpy (&op[1], &msg, sizeof (msg));
545   GNUNET_CONTAINER_DLL_insert (h->op_head,
546                                h->op_tail,
547                                op);
548   transmit_next (h);
549   GNUNET_assert (NULL != h->th);
550 }
551
552
553 /**
554  * Connect to the identity service.
555  *
556  * @param cfg the configuration to use
557  * @param cb function to call on all identity events, can be NULL
558  * @param cb_cls closure for 'cb'
559  * @return handle to use
560  */
561 struct GNUNET_IDENTITY_Handle *
562 GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
563                          GNUNET_IDENTITY_Callback cb,
564                          void *cb_cls)
565 {
566   struct GNUNET_IDENTITY_Handle *h;
567
568   h = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Handle));
569   h->cfg = cfg;
570   h->cb = cb;
571   h->cb_cls = cb_cls;
572   h->egos = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_YES);
573   h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
574   h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, h);
575   return h;
576 }
577
578
579 /**
580  * Obtain the ECC key associated with a ego.
581  *
582  * @param ego the ego
583  * @return associated ECC key, valid as long as the ego is valid
584  */
585 const struct GNUNET_CRYPTO_EccPrivateKey *
586 GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego)
587 {
588   return ego->pk;
589 }
590
591
592 /**
593  * Get the identifier (public key) of an ego.
594  *
595  * @param ego identity handle with the private key
596  * @param pk set to ego's public key
597  */
598 void
599 GNUNET_IDENTITY_ego_get_public_key (const struct GNUNET_IDENTITY_Ego *ego,
600                                     struct GNUNET_CRYPTO_EccPublicKey *pk)
601 {
602   GNUNET_CRYPTO_ecc_key_get_public (ego->pk,
603                                     pk);
604 }
605
606
607 /**
608  * Obtain the identity that is currently preferred/default
609  * for a service.
610  *
611  * @param id identity service to query
612  * @param service_name for which service is an identity wanted
613  * @param cb function to call with the result (will only be called once)
614  * @param cb_cls closure for cb
615  * @return handle to abort the operation
616  */
617 struct GNUNET_IDENTITY_Operation *
618 GNUNET_IDENTITY_get (struct GNUNET_IDENTITY_Handle *id,
619                      const char *service_name,
620                      GNUNET_IDENTITY_Callback cb,
621                      void *cb_cls)
622 {
623   struct GNUNET_IDENTITY_Operation *op;
624   struct GNUNET_IDENTITY_GetDefaultMessage *gdm;
625   size_t slen;
626
627   slen = strlen (service_name) + 1; 
628   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_GetDefaultMessage))
629   {
630     GNUNET_break (0);
631     return NULL;
632   }
633   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
634                       sizeof (struct GNUNET_IDENTITY_GetDefaultMessage) +
635                       slen);  
636   op->h = id;
637   op->cb = cb;
638   op->cls = cb_cls;
639   gdm = (struct GNUNET_IDENTITY_GetDefaultMessage *) &op[1];
640   gdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT);
641   gdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_GetDefaultMessage) +
642                             slen);
643   gdm->name_len = htons (slen);
644   gdm->reserved = htons (0);
645   memcpy (&gdm[1], service_name, slen);
646   op->msg = &gdm->header;
647   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
648                                     id->op_tail,
649                                     op);
650   if (NULL == id->th)
651     transmit_next (id);
652   return op;
653 }
654
655
656 /**
657  * Set the preferred/default identity for a service.
658  *
659  * @param id identity service to inform
660  * @param service_name for which service is an identity set
661  * @param ego new default identity to be set for this service
662  * @param cont function to call once the operation finished
663  * @param cont_cls closure for cont
664  * @return handle to abort the operation
665  */
666 struct GNUNET_IDENTITY_Operation *
667 GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *id,
668                      const char *service_name,
669                      struct GNUNET_IDENTITY_Ego *ego,
670                      GNUNET_IDENTITY_Continuation cont,
671                      void *cont_cls)
672 {
673   struct GNUNET_IDENTITY_Operation *op;
674   struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
675   size_t slen;
676
677   slen = strlen (service_name) + 1;
678   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_SetDefaultMessage))
679   {
680     GNUNET_break (0);
681     return NULL;
682   }
683   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
684                       sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) +
685                       slen);  
686   op->h = id;
687   op->cont = cont;
688   op->cls = cont_cls;
689   sdm = (struct GNUNET_IDENTITY_SetDefaultMessage *) &op[1];
690   sdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT);
691   sdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) +
692                             slen);
693   sdm->name_len = htons (slen);
694   sdm->reserved = htons (0);
695   sdm->private_key = *ego->pk;
696   memcpy (&sdm[1], service_name, slen);
697   op->msg = &sdm->header;
698   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
699                                     id->op_tail,
700                                     op);
701   if (NULL == id->th)
702     transmit_next (id);
703   return op;
704 }
705
706
707 /** 
708  * Create a new identity with the given name.
709  *
710  * @param id identity service to use
711  * @param name desired name
712  * @param cont function to call with the result (will only be called once)
713  * @param cont_cls closure for cont
714  * @return handle to abort the operation
715  */
716 struct GNUNET_IDENTITY_Operation *
717 GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *id,
718                         const char *name,
719                         GNUNET_IDENTITY_Continuation cont,
720                         void *cont_cls)
721 {
722   struct GNUNET_IDENTITY_Operation *op;
723   struct GNUNET_IDENTITY_CreateRequestMessage *crm;
724   struct GNUNET_CRYPTO_EccPrivateKey *pk;
725   size_t slen;
726
727   slen = strlen (name) + 1;
728   pk = GNUNET_CRYPTO_ecc_key_create ();
729
730   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_CreateRequestMessage))
731   {
732     GNUNET_break (0);
733     GNUNET_free (pk);
734     return NULL;
735   }
736   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
737                       sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) +
738                       slen);  
739   op->h = id;
740   op->cont = cont;
741   op->cls = cont_cls;
742   crm = (struct GNUNET_IDENTITY_CreateRequestMessage *) &op[1];
743   crm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_CREATE);
744   crm->header.size = htons (sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) +
745                             slen);
746   crm->name_len = htons (slen);
747   crm->reserved = htons (0);
748   crm->private_key = *pk;
749   memcpy (&crm[1], name, slen);
750   op->msg = &crm->header;
751   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
752                                     id->op_tail,
753                                     op);
754   if (NULL == id->th)
755     transmit_next (id);
756   GNUNET_free (pk);
757   return op;
758 }
759
760
761 /** 
762  * Renames an existing identity.
763  *
764  * @param id identity service to use
765  * @param old_name old name
766  * @param new_name desired new name
767  * @param cb function to call with the result (will only be called once)
768  * @param cb_cls closure for cb
769  * @return handle to abort the operation
770  */
771 struct GNUNET_IDENTITY_Operation *
772 GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *id,
773                         const char *old_name,
774                         const char *new_name,
775                         GNUNET_IDENTITY_Continuation cb,
776                         void *cb_cls)
777 {
778   struct GNUNET_IDENTITY_Operation *op;
779   struct GNUNET_IDENTITY_RenameMessage *grm;
780   size_t slen_old;
781   size_t slen_new;
782   char *dst;
783
784   slen_old = strlen (old_name) + 1;
785   slen_new = strlen (new_name) + 1;
786   if ( (slen_old >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
787        (slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
788        (slen_old + slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_RenameMessage)) )
789   {
790     GNUNET_break (0);
791     return NULL;
792   }
793   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
794                       sizeof (struct GNUNET_IDENTITY_RenameMessage) +
795                       slen_old + slen_new);
796   op->h = id;
797   op->cont = cb;
798   op->cls = cb_cls;
799   grm = (struct GNUNET_IDENTITY_RenameMessage *) &op[1];
800   grm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_RENAME);
801   grm->header.size = htons (sizeof (struct GNUNET_IDENTITY_RenameMessage) +
802                             slen_old + slen_new);
803   grm->old_name_len = htons (slen_old);
804   grm->new_name_len = htons (slen_new);
805   dst = (char *) &grm[1];
806   memcpy (dst, old_name, slen_old);
807   memcpy (&dst[slen_old], new_name, slen_new);
808   op->msg = &grm->header;
809   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
810                                     id->op_tail,
811                                     op);
812   if (NULL == id->th)
813     transmit_next (id);
814   return op;
815 }
816
817
818 /** 
819  * Delete an existing identity.
820  *
821  * @param id identity service to use
822  * @param name name of the identity to delete
823  * @param cb function to call with the result (will only be called once)
824  * @param cb_cls closure for cb
825  * @return handle to abort the operation
826  */
827 struct GNUNET_IDENTITY_Operation *
828 GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *id,
829                         const char *name,
830                         GNUNET_IDENTITY_Continuation cb,
831                         void *cb_cls)
832 {
833   struct GNUNET_IDENTITY_Operation *op;
834   struct GNUNET_IDENTITY_DeleteMessage *gdm;
835   size_t slen;
836
837   slen = strlen (name) + 1;
838   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_DeleteMessage))
839   {
840     GNUNET_break (0);
841     return NULL;
842   }
843   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
844                       sizeof (struct GNUNET_IDENTITY_DeleteMessage) +
845                       slen);  
846   op->h = id;
847   op->cont = cb;
848   op->cls = cb_cls;
849   gdm = (struct GNUNET_IDENTITY_DeleteMessage *) &op[1];
850   gdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_DELETE);
851   gdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_DeleteMessage) +
852                             slen);
853   gdm->name_len = htons (slen);
854   gdm->reserved = htons (0);
855   memcpy (&gdm[1], name, slen);
856   op->msg = &gdm->header;
857   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
858                                     id->op_tail,
859                                     op);
860   if (NULL == id->th)
861     transmit_next (id);
862   return op;
863 }
864
865
866 /**
867  * Cancel an identity operation. Note that the operation MAY still
868  * be executed; this merely cancels the continuation; if the request
869  * was already transmitted, the service may still choose to complete
870  * the operation.
871  *
872  * @param op operation to cancel
873  */
874 void
875 GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op)
876 {
877   struct GNUNET_IDENTITY_Handle *h = op->h;
878
879   if ( (h->op_head != op) ||
880        (NULL == h->client) )
881   {
882     /* request not active, can simply remove */
883     GNUNET_CONTAINER_DLL_remove (h->op_head,
884                                  h->op_tail,
885                                  op);
886     GNUNET_free (op);
887     return;
888   }
889   if (NULL != h->th)
890   {
891     /* request active but not yet with service, can still abort */
892     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
893     h->th = NULL;
894     GNUNET_CONTAINER_DLL_remove (h->op_head,
895                                  h->op_tail,
896                                  op);
897     GNUNET_free (op);
898     transmit_next (h);
899     return;
900   }
901   /* request active with service, simply ensure continuations are not called */
902   op->cont = NULL;
903   op->cb = NULL;
904 }
905
906
907 /**
908  * Free ego from hash map.
909  *
910  * @param cls identity service handle
911  * @param key unused
912  * @param value ego to free
913  * @return GNUNET_OK (continue to iterate)
914  */
915 static int
916 free_ego (void *cls,
917           const struct GNUNET_HashCode *key,
918           void *value)
919 {
920   struct GNUNET_IDENTITY_Handle *h = cls;
921   struct GNUNET_IDENTITY_Ego *ego = value;
922
923   h->cb (h->cb_cls,
924          ego,
925          &ego->ctx,
926          NULL);
927   GNUNET_free (ego->pk);
928   GNUNET_free (ego->name);
929   GNUNET_free (ego);
930   return GNUNET_OK;
931 }
932
933
934 /**
935  * Disconnect from identity service
936  *
937  * @param h handle to destroy
938  */
939 void
940 GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
941 {
942   GNUNET_assert (NULL != h);
943   GNUNET_assert (h->op_head == h->op_tail);
944   if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
945   {
946     GNUNET_SCHEDULER_cancel (h->reconnect_task);
947     h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
948   }
949   if (NULL != h->th)
950   {
951     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
952     h->th = NULL;
953   }
954   if (NULL != h->egos)
955   {
956     GNUNET_CONTAINER_multihashmap_iterate (h->egos,
957                                            &free_ego,
958                                            h);
959     GNUNET_CONTAINER_multihashmap_destroy (h->egos);
960     h->egos = NULL;
961   }
962   if (NULL != h->client)
963   {
964     GNUNET_CLIENT_disconnect (h->client);
965     h->client = NULL;
966   }
967   GNUNET_free (h);
968 }
969
970 /* end of identity_api.c */