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