-fix typos
[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   if (NULL == h->client)
508     return;
509   h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
510                                                ntohs (op->msg->size),
511                                                GNUNET_TIME_UNIT_FOREVER_REL,
512                                                GNUNET_NO,
513                                                &send_next_message,
514                                                h);
515 }
516
517
518 /**
519  * Try again to connect to network size estimation service.
520  *
521  * @param cls the handle to the transport service
522  * @param tc scheduler context
523  */
524 static void
525 reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
526 {
527   struct GNUNET_IDENTITY_Handle *h = cls;
528   struct GNUNET_IDENTITY_Operation *op;
529   struct GNUNET_MessageHeader msg;
530
531   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
532   LOG (GNUNET_ERROR_TYPE_DEBUG,
533        "Connecting to identity service.\n");
534   GNUNET_assert (NULL == h->client);
535   h->client = GNUNET_CLIENT_connect ("identity", h->cfg);
536   GNUNET_assert (NULL != h->client);
537   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) + 
538                       sizeof (struct GNUNET_MessageHeader));
539   op->h = h;
540   op->msg = (const struct GNUNET_MessageHeader *) &op[1];
541   msg.size = htons (sizeof (msg));
542   msg.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_START);
543   memcpy (&op[1], &msg, sizeof (msg));
544   GNUNET_CONTAINER_DLL_insert (h->op_head,
545                                h->op_tail,
546                                op);
547   transmit_next (h);
548   GNUNET_assert (NULL != h->th);
549 }
550
551
552 /**
553  * Connect to the identity service.
554  *
555  * @param cfg the configuration to use
556  * @param cb function to call on all identity events, can be NULL
557  * @param cb_cls closure for 'cb'
558  * @return handle to use
559  */
560 struct GNUNET_IDENTITY_Handle *
561 GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
562                          GNUNET_IDENTITY_Callback cb,
563                          void *cb_cls)
564 {
565   struct GNUNET_IDENTITY_Handle *h;
566
567   h = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Handle));
568   h->cfg = cfg;
569   h->cb = cb;
570   h->cb_cls = cb_cls;
571   h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
572   h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, h);
573   return h;
574 }
575
576
577 /**
578  * Obtain the ECC key associated with a ego.
579  *
580  * @param ego the ego
581  * @return associated ECC key, valid as long as the ego is valid
582  */
583 const struct GNUNET_CRYPTO_EccPrivateKey *
584 GNUNET_IDENTITY_ego_get_key (struct GNUNET_IDENTITY_Ego *ego)
585 {
586   return ego->pk;
587 }
588
589
590 /**
591  * Obtain the identity that is currently preferred/default
592  * for a service.
593  *
594  * @param id identity service to query
595  * @param service_name for which service is an identity wanted
596  * @param cb function to call with the result (will only be called once)
597  * @param cb_cls closure for cb
598  * @return handle to abort the operation
599  */
600 struct GNUNET_IDENTITY_Operation *
601 GNUNET_IDENTITY_get (struct GNUNET_IDENTITY_Handle *id,
602                      const char *service_name,
603                      GNUNET_IDENTITY_Callback cb,
604                      void *cb_cls)
605 {
606   struct GNUNET_IDENTITY_Operation *op;
607   struct GNUNET_IDENTITY_GetDefaultMessage *gdm;
608   size_t slen;
609
610   slen = strlen (service_name) + 1; 
611   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_GetDefaultMessage))
612   {
613     GNUNET_break (0);
614     return NULL;
615   }
616   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
617                       sizeof (struct GNUNET_IDENTITY_GetDefaultMessage) +
618                       slen);  
619   op->h = id;
620   op->cb = cb;
621   op->cls = cb_cls;
622   gdm = (struct GNUNET_IDENTITY_GetDefaultMessage *) &op[1];
623   gdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT);
624   gdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_GetDefaultMessage) +
625                             slen);
626   gdm->name_len = htons (slen);
627   gdm->reserved = htons (0);
628   memcpy (&gdm[1], service_name, slen);
629   op->msg = &gdm->header;
630   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
631                                     id->op_tail,
632                                     op);
633   if (NULL == id->th)
634     transmit_next (id);
635   return op;
636 }
637
638
639 /**
640  * Set the preferred/default identity for a service.
641  *
642  * @param id identity service to inform
643  * @param service_name for which service is an identity set
644  * @param ego new default identity to be set for this service
645  * @param cont function to call once the operation finished
646  * @param cont_cls closure for cont
647  * @return handle to abort the operation
648  */
649 struct GNUNET_IDENTITY_Operation *
650 GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *id,
651                      const char *service_name,
652                      struct GNUNET_IDENTITY_Ego *ego,
653                      GNUNET_IDENTITY_Continuation cont,
654                      void *cont_cls)
655 {
656   struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
657   struct GNUNET_IDENTITY_Operation *op;
658   struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
659   char *str;
660   uint16_t enc_len;
661   size_t slen;
662
663   slen = strlen (service_name) + 1;
664   enc = GNUNET_CRYPTO_ecc_encode_key (ego->pk);
665   enc_len = ntohs (enc->size);
666
667   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) - enc_len)
668   {
669     GNUNET_break (0);
670     GNUNET_free (enc);
671     return NULL;
672   }
673   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
674                       sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) +
675                       enc_len + slen);  
676   op->h = id;
677   op->cont = cont;
678   op->cls = cont_cls;
679   sdm = (struct GNUNET_IDENTITY_SetDefaultMessage *) &op[1];
680   sdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT);
681   sdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) +
682                             slen + enc_len);
683   sdm->name_len = htons (slen);
684   sdm->pk_len = htons (enc_len);
685   str = (char *) &sdm[1];
686   memcpy (str, enc, enc_len);
687   memcpy (&str[enc_len], service_name, slen);
688   op->msg = &sdm->header;
689   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
690                                     id->op_tail,
691                                     op);
692   if (NULL == id->th)
693     transmit_next (id);
694   return op;
695 }
696
697
698 /** 
699  * Create a new identity with the given identifier.
700  *
701  * @param id identity service to use
702  * @param identifier desired identifier
703  * @param cb function to call with the result (will only be called once)
704  * @param cb_cls closure for cb
705  * @return handle to abort the operation
706  */
707 struct GNUNET_IDENTITY_Operation *
708 GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *id,
709                         const char *identifier,
710                         GNUNET_IDENTITY_Callback cb,
711                         void *cb_cls)
712 {
713   struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
714   struct GNUNET_IDENTITY_Operation *op;
715   struct GNUNET_IDENTITY_CreateRequestMessage *crm;
716   struct GNUNET_CRYPTO_EccPrivateKey *pk;
717   char *str;
718   uint16_t enc_len;
719   size_t slen;
720
721   slen = strlen (identifier) + 1;
722   pk = GNUNET_CRYPTO_ecc_key_create ();
723   enc = GNUNET_CRYPTO_ecc_encode_key (pk);
724   GNUNET_CRYPTO_ecc_key_free (pk);
725   enc_len = ntohs (enc->size);
726
727   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) - enc_len)
728   {
729     GNUNET_break (0);
730     GNUNET_free (enc);
731     return NULL;
732   }
733   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
734                       sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) +
735                       enc_len + slen);  
736   op->h = id;
737   op->cb = cb;
738   op->cls = cb_cls;
739   crm = (struct GNUNET_IDENTITY_CreateRequestMessage *) &op[1];
740   crm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_CREATE);
741   crm->header.size = htons (sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) +
742                             slen + enc_len);
743   crm->name_len = htons (slen);
744   crm->pk_len = htons (enc_len);
745   str = (char *) &crm[1];
746   memcpy (str, enc, enc_len);
747   memcpy (&str[enc_len], identifier, slen);
748   op->msg = &crm->header;
749   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
750                                     id->op_tail,
751                                     op);
752   if (NULL == id->th)
753     transmit_next (id);
754   return op;
755 }
756
757
758 /** 
759  * Renames an existing identity.
760  *
761  * @param id identity service to use
762  * @param old_identifier old identifier
763  * @param new_identifier desired new identifier
764  * @param cb function to call with the result (will only be called once)
765  * @param cb_cls closure for cb
766  * @return handle to abort the operation
767  */
768 struct GNUNET_IDENTITY_Operation *
769 GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *id,
770                         const char *old_identifier,
771                         const char *new_identifier,
772                         GNUNET_IDENTITY_Continuation cb,
773                         void *cb_cls)
774 {
775   struct GNUNET_IDENTITY_Operation *op;
776   struct GNUNET_IDENTITY_RenameMessage *grm;
777   size_t slen_old;
778   size_t slen_new;
779   char *dst;
780
781   slen_old = strlen (old_identifier) + 1;
782   slen_new = strlen (new_identifier) + 1;
783   if ( (slen_old >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
784        (slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
785        (slen_old + slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_RenameMessage)) )
786   {
787     GNUNET_break (0);
788     return NULL;
789   }
790   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
791                       sizeof (struct GNUNET_IDENTITY_RenameMessage) +
792                       slen_old + slen_new);
793   op->h = id;
794   op->cont = cb;
795   op->cls = cb_cls;
796   grm = (struct GNUNET_IDENTITY_RenameMessage *) &op[1];
797   grm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_RENAME);
798   grm->header.size = htons (sizeof (struct GNUNET_IDENTITY_RenameMessage) +
799                             slen_old + slen_new);
800   grm->old_name_len = htons (slen_old);
801   grm->new_name_len = htons (slen_new);
802   dst = (char *) &grm[1];
803   memcpy (dst, old_identifier, slen_old);
804   memcpy (&dst[slen_old], new_identifier, slen_new);
805   op->msg = &grm->header;
806   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
807                                     id->op_tail,
808                                     op);
809   if (NULL == id->th)
810     transmit_next (id);
811   return op;
812 }
813
814
815 /** 
816  * Delete an existing identity.
817  *
818  * @param id identity service to use
819  * @param identifier identifier of the identity to delete
820  * @param cb function to call with the result (will only be called once)
821  * @param cb_cls closure for cb
822  * @return handle to abort the operation
823  */
824 struct GNUNET_IDENTITY_Operation *
825 GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *id,
826                         const char *identifier,
827                         GNUNET_IDENTITY_Continuation cb,
828                         void *cb_cls)
829 {
830   struct GNUNET_IDENTITY_Operation *op;
831   struct GNUNET_IDENTITY_DeleteMessage *gdm;
832   size_t slen;
833
834   slen = strlen (identifier) + 1;
835   if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_DeleteMessage))
836   {
837     GNUNET_break (0);
838     return NULL;
839   }
840   op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
841                       sizeof (struct GNUNET_IDENTITY_DeleteMessage) +
842                       slen);  
843   op->h = id;
844   op->cont = cb;
845   op->cls = cb_cls;
846   gdm = (struct GNUNET_IDENTITY_DeleteMessage *) &op[1];
847   gdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_DELETE);
848   gdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_DeleteMessage) +
849                             slen);
850   gdm->name_len = htons (slen);
851   gdm->reserved = htons (0);
852   memcpy (&gdm[1], identifier, slen);
853   op->msg = &gdm->header;
854   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
855                                     id->op_tail,
856                                     op);
857   if (NULL == id->th)
858     transmit_next (id);
859   return op;
860 }
861
862
863 /**
864  * Cancel an identity operation. Note that the operation MAY still
865  * be executed; this merely cancels the continuation; if the request
866  * was already transmitted, the service may still choose to complete
867  * the operation.
868  *
869  * @param op operation to cancel
870  */
871 void
872 GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op)
873 {
874   struct GNUNET_IDENTITY_Handle *h = op->h;
875
876   if ( (h->op_head != op) ||
877        (NULL == h->client) )
878   {
879     /* request not active, can simply remove */
880     GNUNET_CONTAINER_DLL_remove (h->op_head,
881                                  h->op_tail,
882                                  op);
883     GNUNET_free (op);
884     return;
885   }
886   if (NULL != h->th)
887   {
888     /* request active but not yet with service, can still abort */
889     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
890     h->th = NULL;
891     GNUNET_CONTAINER_DLL_remove (h->op_head,
892                                  h->op_tail,
893                                  op);
894     GNUNET_free (op);
895     transmit_next (h);
896     return;
897   }
898   /* request active with service, simply ensure continuations are not called */
899   op->cont = NULL;
900   op->cb = NULL;
901 }
902
903
904 /**
905  * Disconnect from identity service
906  *
907  * @param h handle to destroy
908  */
909 void
910 GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
911 {
912   GNUNET_assert (NULL != h);
913   GNUNET_assert (h->op_head == h->op_tail);
914   if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
915   {
916     GNUNET_SCHEDULER_cancel (h->reconnect_task);
917     h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
918   }
919   if (NULL != h->th)
920   {
921     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
922     h->th = NULL;
923   }
924   if (NULL != h->client)
925   {
926     GNUNET_CLIENT_disconnect (h->client);
927     h->client = NULL;
928   }
929   GNUNET_free (h);
930 }
931
932 /* end of identity_api.c */