changing time measurement from milliseconds to microseconds
[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_CRYPTO_ecc_key_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     GNUNET_CRYPTO_ecc_key_get_public (&sdm->private_key,
402                                       &pub);
403     GNUNET_CRYPTO_hash (&pub, sizeof (pub), &id);
404     if (0 == name_len)
405       str = NULL;
406     else
407       str = (const char *) &sdm[1];
408     ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
409                                              &id);
410     if (NULL == ego)
411     {
412       GNUNET_break (0);
413       reschedule_connect (h);
414       return;
415     }
416     op = h->op_head;
417     GNUNET_CONTAINER_DLL_remove (h->op_head,
418                                  h->op_tail,
419                                  op);
420     if (NULL != op->cb)
421       op->cb (op->cls,
422               ego,
423               &ego->ctx,
424               ego->name);
425     GNUNET_free (op);
426     break;
427   default:
428     GNUNET_break (0);
429     reschedule_connect (h);
430     return;
431   }
432   GNUNET_CLIENT_receive (h->client, &message_handler, h,
433                          GNUNET_TIME_UNIT_FOREVER_REL);
434 }
435
436
437 /**
438  * Schedule transmission of the next message from our queue.
439  *
440  * @param h identity handle
441  */
442 static void
443 transmit_next (struct GNUNET_IDENTITY_Handle *h);
444
445
446 /**
447  * Transmit next message to service.
448  *
449  * @param cls the 'struct GNUNET_IDENTITY_Handle'.
450  * @param size number of bytes available in buf
451  * @param buf where to copy the message
452  * @return number of bytes copied to buf
453  */
454 static size_t
455 send_next_message (void *cls, 
456                    size_t size, 
457                    void *buf)
458 {
459   struct GNUNET_IDENTITY_Handle *h = cls;
460   struct GNUNET_IDENTITY_Operation *op = h->op_head;
461   size_t ret;
462   
463   h->th = NULL;
464   if (NULL == op)
465     return 0;
466   ret = ntohs (op->msg->size);
467   if (ret > size)
468   {
469     reschedule_connect (h);
470     return 0;
471   }  
472   LOG (GNUNET_ERROR_TYPE_DEBUG,
473        "Sending message of type %d to identity service\n",
474        ntohs (op->msg->type));
475   memcpy (buf, op->msg, ret);
476   if ( (NULL == op->cont) &&
477        (NULL == op->cb) )
478   {
479     GNUNET_CONTAINER_DLL_remove (h->op_head,
480                                  h->op_tail,
481                                  op);
482     GNUNET_free (op);
483     transmit_next (h);
484   }
485   if (GNUNET_NO == h->in_receive)
486   {
487     h->in_receive = GNUNET_YES;
488     GNUNET_CLIENT_receive (h->client,
489                            &message_handler, h,
490                            GNUNET_TIME_UNIT_FOREVER_REL);
491   }
492   return ret;
493 }
494
495
496 /**
497  * Schedule transmission of the next message from our queue.
498  *
499  * @param h identity handle
500  */
501 static void
502 transmit_next (struct GNUNET_IDENTITY_Handle *h)
503 {
504   struct GNUNET_IDENTITY_Operation *op = h->op_head;
505
506   GNUNET_assert (NULL == h->th);
507   if (NULL == op)
508     return;
509   if (NULL == h->client)
510     return;
511   h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
512                                                ntohs (op->msg->size),
513                                                GNUNET_TIME_UNIT_FOREVER_REL,
514                                                GNUNET_NO,
515                                                &send_next_message,
516                                                h);
517 }
518
519
520 /**
521  * Try again to connect to network size estimation service.
522  *
523  * @param cls the handle to the transport service
524  * @param tc scheduler context
525  */
526 static void
527 reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
528 {
529   struct GNUNET_IDENTITY_Handle *h = cls;
530   struct GNUNET_IDENTITY_Operation *op;
531   struct GNUNET_MessageHeader msg;
532
533   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
534   LOG (GNUNET_ERROR_TYPE_DEBUG,
535        "Connecting to identity service.\n");
536   GNUNET_assert (NULL == h->client);
537   h->client = GNUNET_CLIENT_connect ("identity", h->cfg);
538   GNUNET_assert (NULL != h->client);
539   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) + 
540                       sizeof (struct GNUNET_MessageHeader));
541   op->h = h;
542   op->msg = (const struct GNUNET_MessageHeader *) &op[1];
543   msg.size = htons (sizeof (msg));
544   msg.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_START);
545   memcpy (&op[1], &msg, sizeof (msg));
546   GNUNET_CONTAINER_DLL_insert (h->op_head,
547                                h->op_tail,
548                                op);
549   transmit_next (h);
550   GNUNET_assert (NULL != h->th);
551 }
552
553
554 /**
555  * Connect to the identity service.
556  *
557  * @param cfg the configuration to use
558  * @param cb function to call on all identity events, can be NULL
559  * @param cb_cls closure for 'cb'
560  * @return handle to use
561  */
562 struct GNUNET_IDENTITY_Handle *
563 GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
564                          GNUNET_IDENTITY_Callback cb,
565                          void *cb_cls)
566 {
567   struct GNUNET_IDENTITY_Handle *h;
568
569   h = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Handle));
570   h->cfg = cfg;
571   h->cb = cb;
572   h->cb_cls = cb_cls;
573   h->egos = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_YES);
574   h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
575   h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, h);
576   return h;
577 }
578
579
580 /**
581  * Obtain the ECC key associated with a ego.
582  *
583  * @param ego the ego
584  * @return associated ECC key, valid as long as the ego is valid
585  */
586 const struct GNUNET_CRYPTO_EccPrivateKey *
587 GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego)
588 {
589   return ego->pk;
590 }
591
592
593 /**
594  * Get the identifier (public key) of an ego.
595  *
596  * @param ego identity handle with the private key
597  * @param pk set to ego's public key
598  */
599 void
600 GNUNET_IDENTITY_ego_get_public_key (const struct GNUNET_IDENTITY_Ego *ego,
601                                     struct GNUNET_CRYPTO_EccPublicKey *pk)
602 {
603   GNUNET_CRYPTO_ecc_key_get_public (ego->pk,
604                                     pk);
605 }
606
607
608 /**
609  * Obtain the identity that is currently preferred/default
610  * for a service.
611  *
612  * @param id identity service to query
613  * @param service_name for which service is an identity wanted
614  * @param cb function to call with the result (will only be called once)
615  * @param cb_cls closure for cb
616  * @return handle to abort the operation
617  */
618 struct GNUNET_IDENTITY_Operation *
619 GNUNET_IDENTITY_get (struct GNUNET_IDENTITY_Handle *id,
620                      const char *service_name,
621                      GNUNET_IDENTITY_Callback cb,
622                      void *cb_cls)
623 {
624   struct GNUNET_IDENTITY_Operation *op;
625   struct GNUNET_IDENTITY_GetDefaultMessage *gdm;
626   size_t slen;
627
628   slen = strlen (service_name) + 1; 
629   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_GetDefaultMessage))
630   {
631     GNUNET_break (0);
632     return NULL;
633   }
634   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
635                       sizeof (struct GNUNET_IDENTITY_GetDefaultMessage) +
636                       slen);  
637   op->h = id;
638   op->cb = cb;
639   op->cls = cb_cls;
640   gdm = (struct GNUNET_IDENTITY_GetDefaultMessage *) &op[1];
641   gdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT);
642   gdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_GetDefaultMessage) +
643                             slen);
644   gdm->name_len = htons (slen);
645   gdm->reserved = htons (0);
646   memcpy (&gdm[1], service_name, slen);
647   op->msg = &gdm->header;
648   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
649                                     id->op_tail,
650                                     op);
651   if (NULL == id->th)
652     transmit_next (id);
653   return op;
654 }
655
656
657 /**
658  * Set the preferred/default identity for a service.
659  *
660  * @param id identity service to inform
661  * @param service_name for which service is an identity set
662  * @param ego new default identity to be set for this service
663  * @param cont function to call once the operation finished
664  * @param cont_cls closure for cont
665  * @return handle to abort the operation
666  */
667 struct GNUNET_IDENTITY_Operation *
668 GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *id,
669                      const char *service_name,
670                      struct GNUNET_IDENTITY_Ego *ego,
671                      GNUNET_IDENTITY_Continuation cont,
672                      void *cont_cls)
673 {
674   struct GNUNET_IDENTITY_Operation *op;
675   struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
676   size_t slen;
677
678   slen = strlen (service_name) + 1;
679   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_SetDefaultMessage))
680   {
681     GNUNET_break (0);
682     return NULL;
683   }
684   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
685                       sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) +
686                       slen);  
687   op->h = id;
688   op->cont = cont;
689   op->cls = cont_cls;
690   sdm = (struct GNUNET_IDENTITY_SetDefaultMessage *) &op[1];
691   sdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT);
692   sdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) +
693                             slen);
694   sdm->name_len = htons (slen);
695   sdm->reserved = htons (0);
696   sdm->private_key = *ego->pk;
697   memcpy (&sdm[1], service_name, slen);
698   op->msg = &sdm->header;
699   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
700                                     id->op_tail,
701                                     op);
702   if (NULL == id->th)
703     transmit_next (id);
704   return op;
705 }
706
707
708 /** 
709  * Create a new identity with the given name.
710  *
711  * @param id identity service to use
712  * @param name desired name
713  * @param cont function to call with the result (will only be called once)
714  * @param cont_cls closure for cont
715  * @return handle to abort the operation
716  */
717 struct GNUNET_IDENTITY_Operation *
718 GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *id,
719                         const char *name,
720                         GNUNET_IDENTITY_Continuation cont,
721                         void *cont_cls)
722 {
723   struct GNUNET_IDENTITY_Operation *op;
724   struct GNUNET_IDENTITY_CreateRequestMessage *crm;
725   struct GNUNET_CRYPTO_EccPrivateKey *pk;
726   size_t slen;
727
728   slen = strlen (name) + 1;
729   pk = GNUNET_CRYPTO_ecc_key_create ();
730
731   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_CreateRequestMessage))
732   {
733     GNUNET_break (0);
734     GNUNET_CRYPTO_ecc_key_free (pk);
735     return NULL;
736   }
737   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
738                       sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) +
739                       slen);  
740   op->h = id;
741   op->cont = cont;
742   op->cls = cont_cls;
743   crm = (struct GNUNET_IDENTITY_CreateRequestMessage *) &op[1];
744   crm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_CREATE);
745   crm->header.size = htons (sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) +
746                             slen);
747   crm->name_len = htons (slen);
748   crm->reserved = htons (0);
749   crm->private_key = *pk;
750   memcpy (&crm[1], name, slen);
751   op->msg = &crm->header;
752   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
753                                     id->op_tail,
754                                     op);
755   if (NULL == id->th)
756     transmit_next (id);
757   GNUNET_CRYPTO_ecc_key_free (pk);
758   return op;
759 }
760
761
762 /** 
763  * Renames an existing identity.
764  *
765  * @param id identity service to use
766  * @param old_name old name
767  * @param new_name desired new name
768  * @param cb function to call with the result (will only be called once)
769  * @param cb_cls closure for cb
770  * @return handle to abort the operation
771  */
772 struct GNUNET_IDENTITY_Operation *
773 GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *id,
774                         const char *old_name,
775                         const char *new_name,
776                         GNUNET_IDENTITY_Continuation cb,
777                         void *cb_cls)
778 {
779   struct GNUNET_IDENTITY_Operation *op;
780   struct GNUNET_IDENTITY_RenameMessage *grm;
781   size_t slen_old;
782   size_t slen_new;
783   char *dst;
784
785   slen_old = strlen (old_name) + 1;
786   slen_new = strlen (new_name) + 1;
787   if ( (slen_old >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
788        (slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
789        (slen_old + slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_RenameMessage)) )
790   {
791     GNUNET_break (0);
792     return NULL;
793   }
794   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
795                       sizeof (struct GNUNET_IDENTITY_RenameMessage) +
796                       slen_old + slen_new);
797   op->h = id;
798   op->cont = cb;
799   op->cls = cb_cls;
800   grm = (struct GNUNET_IDENTITY_RenameMessage *) &op[1];
801   grm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_RENAME);
802   grm->header.size = htons (sizeof (struct GNUNET_IDENTITY_RenameMessage) +
803                             slen_old + slen_new);
804   grm->old_name_len = htons (slen_old);
805   grm->new_name_len = htons (slen_new);
806   dst = (char *) &grm[1];
807   memcpy (dst, old_name, slen_old);
808   memcpy (&dst[slen_old], new_name, slen_new);
809   op->msg = &grm->header;
810   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
811                                     id->op_tail,
812                                     op);
813   if (NULL == id->th)
814     transmit_next (id);
815   return op;
816 }
817
818
819 /** 
820  * Delete an existing identity.
821  *
822  * @param id identity service to use
823  * @param name name of the identity to delete
824  * @param cb function to call with the result (will only be called once)
825  * @param cb_cls closure for cb
826  * @return handle to abort the operation
827  */
828 struct GNUNET_IDENTITY_Operation *
829 GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *id,
830                         const char *name,
831                         GNUNET_IDENTITY_Continuation cb,
832                         void *cb_cls)
833 {
834   struct GNUNET_IDENTITY_Operation *op;
835   struct GNUNET_IDENTITY_DeleteMessage *gdm;
836   size_t slen;
837
838   slen = strlen (name) + 1;
839   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_DeleteMessage))
840   {
841     GNUNET_break (0);
842     return NULL;
843   }
844   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
845                       sizeof (struct GNUNET_IDENTITY_DeleteMessage) +
846                       slen);  
847   op->h = id;
848   op->cont = cb;
849   op->cls = cb_cls;
850   gdm = (struct GNUNET_IDENTITY_DeleteMessage *) &op[1];
851   gdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_DELETE);
852   gdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_DeleteMessage) +
853                             slen);
854   gdm->name_len = htons (slen);
855   gdm->reserved = htons (0);
856   memcpy (&gdm[1], name, slen);
857   op->msg = &gdm->header;
858   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
859                                     id->op_tail,
860                                     op);
861   if (NULL == id->th)
862     transmit_next (id);
863   return op;
864 }
865
866
867 /**
868  * Cancel an identity operation. Note that the operation MAY still
869  * be executed; this merely cancels the continuation; if the request
870  * was already transmitted, the service may still choose to complete
871  * the operation.
872  *
873  * @param op operation to cancel
874  */
875 void
876 GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op)
877 {
878   struct GNUNET_IDENTITY_Handle *h = op->h;
879
880   if ( (h->op_head != op) ||
881        (NULL == h->client) )
882   {
883     /* request not active, can simply remove */
884     GNUNET_CONTAINER_DLL_remove (h->op_head,
885                                  h->op_tail,
886                                  op);
887     GNUNET_free (op);
888     return;
889   }
890   if (NULL != h->th)
891   {
892     /* request active but not yet with service, can still abort */
893     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
894     h->th = NULL;
895     GNUNET_CONTAINER_DLL_remove (h->op_head,
896                                  h->op_tail,
897                                  op);
898     GNUNET_free (op);
899     transmit_next (h);
900     return;
901   }
902   /* request active with service, simply ensure continuations are not called */
903   op->cont = NULL;
904   op->cb = NULL;
905 }
906
907
908 /**
909  * Free ego from hash map.
910  *
911  * @param cls identity service handle
912  * @param key unused
913  * @param value ego to free
914  * @return GNUNET_OK (continue to iterate)
915  */
916 static int
917 free_ego (void *cls,
918           const struct GNUNET_HashCode *key,
919           void *value)
920 {
921   struct GNUNET_IDENTITY_Handle *h = cls;
922   struct GNUNET_IDENTITY_Ego *ego = value;
923
924   h->cb (h->cb_cls,
925          ego,
926          &ego->ctx,
927          NULL);
928   GNUNET_CRYPTO_ecc_key_free (ego->pk);
929   GNUNET_free (ego->name);
930   GNUNET_free (ego);
931   return GNUNET_OK;
932 }
933
934
935 /**
936  * Disconnect from identity service
937  *
938  * @param h handle to destroy
939  */
940 void
941 GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
942 {
943   GNUNET_assert (NULL != h);
944   GNUNET_assert (h->op_head == h->op_tail);
945   if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
946   {
947     GNUNET_SCHEDULER_cancel (h->reconnect_task);
948     h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
949   }
950   if (NULL != h->th)
951   {
952     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
953     h->th = NULL;
954   }
955   if (NULL != h->egos)
956   {
957     GNUNET_CONTAINER_multihashmap_iterate (h->egos,
958                                            &free_ego,
959                                            h);
960     GNUNET_CONTAINER_multihashmap_destroy (h->egos);
961     h->egos = NULL;
962   }
963   if (NULL != h->client)
964   {
965     GNUNET_CLIENT_disconnect (h->client);
966     h->client = NULL;
967   }
968   GNUNET_free (h);
969 }
970
971 /* end of identity_api.c */