-bugfixes, tests
[oweals/gnunet.git] / src / gns / gnunet-service-gns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011 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 License 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 License for more details.
14
15      You should have received a copy of the GNU General Public License
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  *
23  * TODO:
24  *    - Write xquery and block plugin
25  *    - The smaller FIXME issues all around
26  *
27  * @file gns/gnunet-service-gns.c
28  * @brief GNUnet GNS service
29  * @author Martin Schanzenbach
30  */
31 #include "platform.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_transport_service.h"
34 #include "gnunet_dns_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "gnunet_dht_service.h"
37 #include "gnunet_namestore_service.h"
38 #include "gnunet_gns_service.h"
39 #include "block_gns.h"
40 #include "gns.h"
41
42 #define DHT_OPERATION_TIMEOUT  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
43 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
44 #define DHT_GNS_REPLICATION_LEVEL 5
45 #define MAX_DNS_LABEL_LENGTH 63
46
47 /* FIXME move to proper header in include */
48 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP 23
49 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT 24
50 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN 25
51 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT 26
52 #define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH 27
53 #define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT 28
54
55
56 struct AuthorityChain
57 {
58   struct AuthorityChain *prev;
59
60   struct AuthorityChain *next;
61
62   GNUNET_HashCode zone;
63
64   /* (local) name of the authority */
65   char* name;
66
67   /* was the ns entry fresh */
68   int fresh;
69 };
70
71 /* handle to a resolution process */
72 struct GNUNET_GNS_ResolverHandle;
73
74 /**
75  * processor for a resultion result
76  *
77  * @param cls the closure
78  * @param rh the resolution handle
79  * @param rd_count number of results
80  * @pram rd resukt data
81  */
82 typedef void (*ResolutionResultProcessor) (void *cls,
83                                   struct GNUNET_GNS_ResolverHandle *rh,
84                                   uint32_t rd_count,
85                                   const struct GNUNET_NAMESTORE_RecordData *rd);
86
87 /**
88  * Resoltion status indicator
89  * EXISTS: the name to lookup exists
90  * EXPIRED: the name in the record expired
91  */
92 enum ResolutionStatus
93 {
94   EXISTS = 1,
95   EXPIRED = 2
96 };
97
98 /**
99  * Handle to a currenty pending resolution
100  */
101 struct GNUNET_GNS_ResolverHandle
102 {
103   /* The name to resolve */
104   char *name;
105
106   /* has this query been answered? how many matches */
107   int answered;
108
109   /* the authoritative zone to query */
110   GNUNET_HashCode authority;
111
112   /* the name of the authoritative zone to query */
113   char *authority_name;
114
115   /**
116    * we have an authority in namestore that
117    * may be able to resolve
118    */
119   int authority_found;
120
121   /* a handle for dht lookups. should be NULL if no lookups are in progress */
122   struct GNUNET_DHT_GetHandle *get_handle;
123
124   /* timeout task for dht lookups */
125   GNUNET_SCHEDULER_TaskIdentifier dht_timeout_task;
126
127   /* called when resolution phase finishes */
128   ResolutionResultProcessor proc;
129   
130   /* closure passed to proc */
131   void* proc_cls;
132
133   /* DLL to store the authority chain */
134   struct AuthorityChain *authority_chain_head;
135
136   /* DLL to store the authority chain */
137   struct AuthorityChain *authority_chain_tail;
138   
139   /* status of the resolution result */
140   enum ResolutionStatus status;
141
142 };
143
144 /**
145  * Handle to a record lookup
146  */
147 struct RecordLookupHandle
148 {
149   /* the record type to look up */
150   enum GNUNET_GNS_RecordType record_type;
151
152   /* the name to look up */
153   char *name;
154
155   /* Method to call on record resolution result */
156   ResolutionResultProcessor proc;
157
158   /* closure to pass to proc */
159   void* proc_cls;
160
161 };
162
163 /**
164  * Handle to a shorten operation from api
165  */
166 struct ClientShortenHandle
167 {
168   /* the requesting client that */
169   struct GNUNET_SERVER_Client *client;
170
171   /* request id */
172   uint64_t unique_id;
173
174   /* request type */
175   enum GNUNET_GNS_RecordType type;
176
177   /* name to shorten */
178   char* name;
179
180 };
181
182
183 /**
184  * Handle to a get auhtority operation from api
185  */
186 struct ClientGetAuthHandle
187 {
188   /* the requesting client that */
189   struct GNUNET_SERVER_Client *client;
190
191   /* request id */
192   uint64_t unique_id;
193
194   /* name to lookup authority */
195   char* name;
196
197 };
198
199
200 /**
201  * Handle to a lookup operation from api
202  */
203 struct ClientLookupHandle
204 {
205   /* the requesting client that */
206   struct GNUNET_SERVER_Client *client;
207
208   /* request id */
209   uint64_t unique_id;
210
211   /* request type */
212   enum GNUNET_GNS_RecordType type;
213
214   /* the name to look up */
215   char* name; //Needed?
216 };
217
218 /**
219  * Handle to a DNS intercepted
220  * reslution request
221  */
222 struct InterceptLookupHandle
223 {
224   /* the request handle to reply to */
225   struct GNUNET_DNS_RequestHandle *request_handle;
226   
227   /* the dns parser packet received */
228   struct GNUNET_DNSPARSER_Packet *packet;
229   
230   /* the query parsed from the packet */
231   struct GNUNET_DNSPARSER_Query *query;
232 };
233
234
235 /**
236  * Our handle to the DNS handler library
237  */
238 struct GNUNET_DNS_Handle *dns_handle;
239
240 /**
241  * Our handle to the DHT
242  */
243 struct GNUNET_DHT_Handle *dht_handle;
244
245 /**
246  * Our zone's private key
247  */
248 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
249
250 /**
251  * Our handle to the namestore service
252  * FIXME maybe need a second handle for iteration
253  */
254 struct GNUNET_NAMESTORE_Handle *namestore_handle;
255
256 /**
257  * Handle to iterate over our authoritative zone in namestore
258  */
259 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
260
261 /**
262  * The configuration the GNS service is running with
263  */
264 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
265
266 /**
267  * Our notification context.
268  */
269 static struct GNUNET_SERVER_NotificationContext *nc;
270
271 /**
272  * Our zone hash
273  */
274 GNUNET_HashCode zone_hash;
275
276 /**
277  * Our tld. Maybe get from config file
278  */
279 const char* gnunet_tld = ".gnunet";
280
281 /**
282  * Useful for zone update for DHT put
283  */
284 static int num_public_records =  3600;
285
286 /* dht update interval FIXME define? */
287 static struct GNUNET_TIME_Relative dht_update_interval;
288
289 /* zone update task */
290 GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
291
292 /**
293  * Helper function to free resolver handle
294  *
295  * @rh the handle to free
296  */
297 static void
298 free_resolver_handle(struct GNUNET_GNS_ResolverHandle* rh)
299 {
300   struct AuthorityChain *ac;
301   struct AuthorityChain *ac_next;
302
303   if (NULL == rh)
304     return;
305
306   GNUNET_free_non_null (rh->name);
307   GNUNET_free_non_null (rh->authority_name);
308
309   ac = rh->authority_chain_head;
310
311   while (NULL != ac)
312   {
313     ac_next = ac->next;
314     GNUNET_free_non_null (ac->name);
315     GNUNET_free(ac);
316     ac = ac_next;
317   }
318   GNUNET_free(rh);
319 }
320
321
322 /**
323  * Reply to dns request with the result from our lookup.
324  *
325  * @param cls the closure to the request (an InterceptLookupHandle)
326  * @param rh the request handle of the lookup
327  * @param rd_count the number of records to return
328  * @param rd the record data
329  */
330 static void
331 reply_to_dns(void* cls, struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count,
332              const struct GNUNET_NAMESTORE_RecordData *rd)
333 {
334   int i;
335   size_t len;
336   int ret;
337   char *buf;
338   struct InterceptLookupHandle* ilh = (struct InterceptLookupHandle*)cls;
339   struct GNUNET_DNSPARSER_Packet *packet = ilh->packet;
340   struct GNUNET_DNSPARSER_Record answer_records[rh->answered];
341   struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)];
342   packet->answers = answer_records;
343   packet->additional_records = additional_records;
344   
345   /**
346    * Put records in the DNS packet and modify it
347    * to a response
348    */
349   len = sizeof(struct GNUNET_DNSPARSER_Record*);
350   for (i=0; i < rd_count; i++)
351   {
352     
353     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
354                "Adding type %d to DNS response\n", rd[i].record_type);
355     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", rh->name);
356     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "QName: %s\n", ilh->query->name);
357     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count);
358     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size);
359     
360     if (rd[i].record_type == ilh->query->type)
361     {
362       answer_records[i].name = ilh->query->name;
363       answer_records[i].type = rd[i].record_type;
364       answer_records[i].data.raw.data_len = rd[i].data_size;
365       answer_records[i].data.raw.data = (char*)rd[i].data;
366       answer_records[i].expiration_time = rd[i].expiration;
367       answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
368     }
369     else
370     {
371       additional_records[i].name = ilh->query->name;
372       additional_records[i].type = rd[i].record_type;
373       additional_records[i].data.raw.data_len = rd[i].data_size;
374       additional_records[i].data.raw.data = (char*)rd[i].data;
375       additional_records[i].expiration_time = rd[i].expiration;
376       additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
377     }
378   }
379   
380   packet->num_answers = rh->answered;
381   packet->num_additional_records = rd_count-(rh->answered);
382   
383   if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash))
384     packet->flags.authoritative_answer = 1;
385   else
386     packet->flags.authoritative_answer = 0;
387
388   if (rd == NULL)
389     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
390   else
391     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
392   
393   packet->flags.query_or_response = 1;
394
395   
396   /**
397    * Reply to DNS
398    */
399   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
400              "Building DNS response\n");
401   ret = GNUNET_DNSPARSER_pack (packet,
402                                1024, /* FIXME magic from dns redirector */
403                                &buf,
404                                &len);
405   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
406              "Built DNS response! (ret=%d,len=%d)\n", ret, len);
407   if (ret == GNUNET_OK)
408   {
409     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
410                "Answering DNS request\n");
411     GNUNET_DNS_request_answer(ilh->request_handle,
412                               len,
413                               buf);
414
415     GNUNET_free(buf);
416     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n");
417   }
418   else
419   {
420     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
421                "Error building DNS response! (ret=%d)", ret);
422   }
423   
424   packet->num_answers = 0;
425   packet->answers = NULL;
426   packet->num_additional_records = 0;
427   packet->additional_records = NULL;
428   GNUNET_DNSPARSER_free_packet(packet);
429   //FIXME free more!
430   GNUNET_free((struct RecordLookupHandle*)rh->proc_cls);
431   free_resolver_handle(rh);
432   GNUNET_free(ilh);
433 }
434
435
436 /**
437  * Task run during shutdown.
438  *
439  * @param cls unused
440  * @param tc unused
441  */
442 static void
443 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
444 {
445
446   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
447              "Shutting down!");
448   /* Kill zone task for it may make the scheduler hang */
449   if (zone_update_taskid)
450     GNUNET_SCHEDULER_cancel(zone_update_taskid);
451   
452   GNUNET_SERVER_notification_context_destroy (nc);
453   
454   if (dns_handle)
455     GNUNET_DNS_disconnect(dns_handle);
456   
457   GNUNET_NAMESTORE_disconnect(namestore_handle, 1);
458   GNUNET_DHT_disconnect(dht_handle);
459 }
460
461
462 /**
463  * Callback when record data is put into namestore
464  *
465  * @param cls the closure
466  * @param success GNUNET_OK on success
467  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
468  */
469 void
470 on_namestore_record_put_result(void *cls,
471                                int32_t success,
472                                const char *emsg)
473 {
474   if (GNUNET_NO == success)
475   {
476     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
477     return;
478   }
479   else if (GNUNET_YES == success)
480   {
481     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
482                "records successfully put in namestore\n");
483     return;
484   }
485
486   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
487              "Error putting records into namestore: %s\n", emsg);
488 }
489
490
491 /**
492  * Handle timeout for DHT requests
493  *
494  * @param cls the request handle as closure
495  * @param tc the task context
496  */
497 static void
498 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
499 {
500   struct GNUNET_GNS_ResolverHandle *rh = cls;
501
502   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
503              "dht lookup for query %s timed out.\n",
504              rh->name);
505
506   GNUNET_DHT_get_stop (rh->get_handle);
507   rh->proc(rh->proc_cls, rh, 0, NULL);
508 }
509
510
511 /**
512  * Function called when we get a result from the dht
513  * for our record query
514  *
515  * @param cls the request handle
516  * @param exp lifetime
517  * @param key the key the record was stored under
518  * @param get_path get path
519  * @param get_path_length get path length
520  * @param put_path put path
521  * @param put_path_length put path length
522  * @param type the block type
523  * @param size the size of the record
524  * @param data the record data
525  */
526 static void
527 process_record_dht_result(void* cls,
528                  struct GNUNET_TIME_Absolute exp,
529                  const GNUNET_HashCode * key,
530                  const struct GNUNET_PeerIdentity *get_path,
531                  unsigned int get_path_length,
532                  const struct GNUNET_PeerIdentity *put_path,
533                  unsigned int put_path_length,
534                  enum GNUNET_BLOCK_Type type,
535                  size_t size, const void *data)
536 {
537   struct GNUNET_GNS_ResolverHandle *rh;
538   struct RecordLookupHandle *rlh;
539   struct GNSNameRecordBlock *nrb;
540   uint32_t num_records;
541   char* name = NULL;
542   char* rd_data = (char*)data;
543   int i;
544   int rd_size;
545   
546   GNUNET_HashCode zone, name_hash;
547   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
548   
549   if (data == NULL)
550     return;
551
552   //FIXME maybe check expiration here, check block type
553   
554   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
555   rlh = (struct RecordLookupHandle *) rh->proc_cls;
556   nrb = (struct GNSNameRecordBlock*)data;
557   
558   /* stop lookup and timeout task */
559   GNUNET_DHT_get_stop (rh->get_handle);
560   GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
561   
562   rh->get_handle = NULL;
563   name = (char*)&nrb[1];
564   num_records = ntohl(nrb->rd_count);
565   {
566     struct GNUNET_NAMESTORE_RecordData rd[num_records];
567
568     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
569     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
570   
571     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
572                                                                rd_data,
573                                                                num_records,
574                                                                rd))
575     {
576       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
577       return;
578     }
579
580     for (i=0; i<num_records; i++)
581     {
582       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
583                "Got name: %s (wanted %s)\n", name, rh->name);
584       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
585                "Got type: %d\n",
586                rd[i].record_type);
587       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
588                "Got data length: %d\n", rd[i].data_size);
589       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
590                "Got flag %d\n", rd[i].flags);
591     
592      if ((strcmp(name, rh->name) == 0) &&
593          (rd[i].record_type == rlh->record_type))
594       {
595         rh->answered++;
596       }
597
598     }
599
600     GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
601     GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
602   
603     /**
604      * FIXME check pubkey against existing key in namestore?
605      * https://gnunet.org/bugs/view.php?id=2179
606      */
607
608     /* Save to namestore */
609     GNUNET_NAMESTORE_record_put (namestore_handle,
610                                  &nrb->public_key,
611                                  name,
612                                  exp,
613                                  num_records,
614                                  rd,
615                                  &nrb->signature,
616                                  &on_namestore_record_put_result, //cont
617                                  NULL); //cls
618   
619     if (rh->answered)
620       rh->proc(rh->proc_cls, rh, num_records, rd);
621     else
622       rh->proc(rh->proc_cls, rh, 0, NULL);
623   }
624
625 }
626
627
628 /**
629  * Start DHT lookup for a (name -> query->record_type) record in
630  * rh->authority's zone
631  *
632  * @param rh the pending gns query context
633  */
634 static void
635 resolve_record_dht(struct GNUNET_GNS_ResolverHandle *rh)
636 {
637   uint32_t xquery;
638   GNUNET_HashCode name_hash;
639   GNUNET_HashCode lookup_key;
640   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
641   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
642
643   GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash);
644   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
645   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
646   
647   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
648              "starting dht lookup for %s with key: %s\n",
649              rh->name, (char*)&lookup_key_string);
650
651   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
652                                                       &dht_lookup_timeout, rh);
653
654   xquery = htonl(rlh->record_type);
655   rh->get_handle = GNUNET_DHT_get_start(dht_handle, 
656                        DHT_OPERATION_TIMEOUT,
657                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
658                        &lookup_key,
659                        DHT_GNS_REPLICATION_LEVEL,
660                        GNUNET_DHT_RO_NONE,
661                        &xquery, 
662                        sizeof(xquery),
663                        &process_record_dht_result,
664                        rh);
665
666 }
667
668
669 /**
670  * Namestore calls this function if we have record for this name.
671  * (or with rd_count=0 to indicate no matches)
672  *
673  * @param cls the pending query
674  * @param key the key of the zone we did the lookup
675  * @param expiration expiration date of the namestore entry
676  * @param name the name for which we need an authority
677  * @param rd_count the number of records with 'name'
678  * @param rd the record data
679  * @param signature the signature of the authority for the record data
680  */
681 static void
682 process_record_lookup_ns(void* cls,
683                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
684                   struct GNUNET_TIME_Absolute expiration,
685                   const char *name, unsigned int rd_count,
686                   const struct GNUNET_NAMESTORE_RecordData *rd,
687                   const struct GNUNET_CRYPTO_RsaSignature *signature)
688 {
689   struct GNUNET_GNS_ResolverHandle *rh;
690   struct RecordLookupHandle *rlh;
691   struct GNUNET_TIME_Relative remaining_time;
692   GNUNET_HashCode zone;
693
694   rh = (struct GNUNET_GNS_ResolverHandle *) cls;
695   rlh = (struct RecordLookupHandle *)rh->proc_cls;
696   GNUNET_CRYPTO_hash(key,
697                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
698                      &zone);
699   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
700
701   rh->status = 0;
702   
703   if (name != NULL)
704   {
705     rh->status |= EXISTS;
706   }
707   
708   if (remaining_time.rel_value == 0)
709   {
710     rh->status |= EXPIRED;
711   }
712   
713   if (rd_count == 0)
714   {
715     /**
716      * Lookup terminated and no results
717      */
718     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
719                "Namestore lookup for %s terminated without results\n", name);
720
721     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
722                "Record %s unknown in namestore\n",
723                rh->name);
724     /**
725      * Our zone and no result? Cannot resolve TT
726      */
727     rh->proc(rh->proc_cls, rh, 0, NULL);
728     return;
729
730   }
731   else
732   {
733     
734     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
735                "Processing additional result %s from namestore\n", name);
736     int i;
737     for (i=0; i<rd_count;i++)
738     {
739       
740       if (rd[i].record_type != rlh->record_type)
741         continue;
742       
743       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
744           == 0)
745       {
746         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n");
747         continue;
748       }
749       
750       rh->answered++;
751       
752     }
753     
754     /**
755      * no answers found
756      */
757     if (rh->answered == 0)
758     {
759       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
760                  "No answers found. This is odd!\n");
761       rh->proc(rh->proc_cls, rh, 0, NULL);
762       return;
763     }
764     
765     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
766                rh->answered);
767
768     rh->proc(rh->proc_cls, rh, rd_count, rd);
769   }
770 }
771
772
773 /**
774  * The final phase of resolution.
775  * rh->name is a name that is canonical and we do not have a delegation.
776  * Query namestore for this record
777  *
778  * @param rh the pending lookup
779  */
780 static void
781 resolve_record_ns(struct GNUNET_GNS_ResolverHandle *rh)
782 {
783   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
784   
785   /**
786    * Try to resolve this record in our namestore.
787    * The name to resolve is now in rh->authority_name
788    * since we tried to resolve it to an authority
789    * and failed.
790    **/
791   GNUNET_NAMESTORE_lookup_record(namestore_handle,
792                                  &rh->authority,
793                                  rh->name,
794                                  rlh->record_type,
795                                  &process_record_lookup_ns,
796                                  rh);
797 }
798
799
800 /**
801  * Handle timeout for DHT requests
802  *
803  * @param cls the request handle as closure
804  * @param tc the task context
805  */
806 static void
807 dht_authority_lookup_timeout(void *cls,
808                              const struct GNUNET_SCHEDULER_TaskContext *tc)
809 {
810   struct GNUNET_GNS_ResolverHandle *rh = cls;
811
812   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
813              "dht lookup for query %s timed out.\n",
814              rh->name);
815
816   GNUNET_DHT_get_stop (rh->get_handle);
817   if (strcmp(rh->name, "") == 0)
818   {
819     /*
820      * promote authority back to name and try to resolve record
821      */
822     strcpy(rh->name, rh->authority_name);
823   }
824   rh->proc(rh->proc_cls, rh, 0, NULL);
825 }
826
827 /* Prototype */
828 static void resolve_delegation_dht(struct GNUNET_GNS_ResolverHandle *rh);
829
830 /**
831  * Function called when we get a result from the dht
832  * for our query. Recursively tries to resolve authorities
833  * for name in DHT.
834  *
835  * @param cls the request handle
836  * @param exp lifetime
837  * @param key the key the record was stored under
838  * @param get_path get path
839  * @param get_path_length get path length
840  * @param put_path put path
841  * @param put_path_length put path length
842  * @param type the block type
843  * @param size the size of the record
844  * @param data the record data
845  */
846 static void
847 process_delegation_result_dht(void* cls,
848                  struct GNUNET_TIME_Absolute exp,
849                  const GNUNET_HashCode * key,
850                  const struct GNUNET_PeerIdentity *get_path,
851                  unsigned int get_path_length,
852                  const struct GNUNET_PeerIdentity *put_path,
853                  unsigned int put_path_length,
854                  enum GNUNET_BLOCK_Type type,
855                  size_t size, const void *data)
856 {
857   struct GNUNET_GNS_ResolverHandle *rh;
858   struct GNSNameRecordBlock *nrb;
859   uint32_t num_records;
860   char* name = NULL;
861   char* rd_data = (char*) data;
862   int i;
863   int rd_size;
864   GNUNET_HashCode zone, name_hash;
865   
866   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
867
868   if (data == NULL)
869     return;
870   
871   //FIXME check expiration?
872   
873   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
874   nrb = (struct GNSNameRecordBlock*)data;
875   
876   /* stop dht lookup and timeout task */
877   GNUNET_DHT_get_stop (rh->get_handle);
878   GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
879
880   rh->get_handle = NULL;
881   num_records = ntohl(nrb->rd_count);
882   name = (char*)&nrb[1];
883   {
884     struct GNUNET_NAMESTORE_RecordData rd[num_records];
885     
886     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
887     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
888   
889     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
890                                                                rd_data,
891                                                                num_records,
892                                                                rd))
893     {
894       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
895       return;
896     }
897
898     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
899                "Got name: %s (wanted %s)\n", name, rh->authority_name);
900     for (i=0; i<num_records; i++)
901     {
902     
903       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
904                 "Got name: %s (wanted %s)\n", name, rh->authority_name);
905       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
906                  "Got type: %d (wanted %d)\n",
907                  rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
908       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
909                  "Got data length: %d\n", rd[i].data_size);
910       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
911                  "Got flag %d\n", rd[i].flags);
912
913       if ((strcmp(name, rh->authority_name) == 0) &&
914           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
915       {
916         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
917         rh->answered = 1;
918         memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
919         struct AuthorityChain *auth =
920           GNUNET_malloc(sizeof(struct AuthorityChain));
921         auth->zone = rh->authority;
922         auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
923         memset(auth->name, 0, strlen(rh->authority_name)+1);
924         strcpy(auth->name, rh->authority_name);
925         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
926                                      rh->authority_chain_tail,
927                                      auth);
928       }
929
930     }
931
932
933     GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
934     GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
935
936     /* Save to namestore */
937     if (0 != GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone))
938     {
939       GNUNET_NAMESTORE_record_put (namestore_handle,
940                                  &nrb->public_key,
941                                  name,
942                                  exp,
943                                  num_records,
944                                  rd,
945                                  &nrb->signature,
946                                  &on_namestore_record_put_result, //cont
947                                  NULL); //cls
948     }
949   }
950   
951   if (rh->answered)
952   {
953     rh->answered = 0;
954     /**
955      * delegate
956      * FIXME in this case. should we ask namestore again?
957      */
958     if (strcmp(rh->name, "") == 0)
959       rh->proc(rh->proc_cls, rh, 0, NULL);
960     else
961       resolve_delegation_dht(rh);
962     return;
963   }
964
965   /**
966    * should never get here unless false dht key/put
967    * block plugin should handle this
968    **/
969   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup error!\n");
970   GNUNET_break(0);
971 }
972
973
974 /**
975  * Process DHT lookup result for record.
976  *
977  * @param cls the closure
978  * @param rh resolver handle
979  * @param rd_count number of results (always 0)
980  * @param rd record data (always NULL)
981  */
982 static void
983 process_record_result_dht(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
984                        unsigned int rd_count,
985                        const struct GNUNET_NAMESTORE_RecordData *rd)
986 {
987   struct RecordLookupHandle* rlh;
988   rlh = (struct RecordLookupHandle*)cls;
989   if (rd_count == 0)
990   {
991     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
992                "No records for %s found in DHT. Aborting\n",
993                rh->name);
994     /* give up, cannot resolve */
995     rlh->proc(rlh->proc_cls, rh, 0, NULL);
996     return;
997   }
998
999   /* results found yay */
1000   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1001              "Record resolved from namestore!");
1002   rlh->proc(rlh->proc_cls, rh, rd_count, rd);
1003
1004 }
1005
1006
1007 /**
1008  * Process namestore lookup result for record.
1009  *
1010  * @param cls the closure
1011  * @param rh resolver handle
1012  * @param rd_count number of results (always 0)
1013  * @param rd record data (always NULL)
1014  */
1015 static void
1016 process_record_result_ns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1017                        unsigned int rd_count,
1018                        const struct GNUNET_NAMESTORE_RecordData *rd)
1019 {
1020   struct RecordLookupHandle* rlh;
1021   rlh = (struct RecordLookupHandle*) cls;
1022   if (rd_count == 0)
1023   {
1024     /* ns entry expired. try dht */
1025     if (rh->status & (EXPIRED | !EXISTS))
1026     {
1027       rh->proc = &process_record_result_dht;
1028       resolve_record_dht(rh);
1029       return;
1030     }
1031     /* give up, cannot resolve */
1032     rlh->proc(rlh->proc_cls, rh, 0, NULL);
1033     return;
1034   }
1035
1036   /* results found yay */
1037   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1038              "Record resolved from namestore!");
1039   rlh->proc(rlh->proc_cls, rh, rd_count, rd);
1040
1041 }
1042
1043
1044 /**
1045  * Determine if this name is canonical.
1046  * i.e.
1047  * a.b.gnunet  = not canonical
1048  * a           = canonical
1049  *
1050  * @param name the name to test
1051  * @return 1 if canonical
1052  */
1053 static int
1054 is_canonical(char* name)
1055 {
1056   uint32_t len = strlen(name);
1057   int i;
1058
1059   for (i=0; i<len; i++)
1060   {
1061     if (*(name+i) == '.')
1062       return 0;
1063   }
1064   return 1;
1065 }
1066
1067 /**
1068  * Move one level up in the domain hierarchy and return the
1069  * passed top level domain.
1070  *
1071  * @param name the domain
1072  * @param dest the destination where the tld will be put
1073  */
1074 void
1075 pop_tld(char* name, char* dest)
1076 {
1077   uint32_t len;
1078
1079   if (is_canonical(name))
1080   {
1081     strcpy(dest, name);
1082     strcpy(name, "");
1083     return;
1084   }
1085
1086   for (len = strlen(name); len > 0; len--)
1087   {
1088     if (*(name+len) == '.')
1089       break;
1090   }
1091   
1092   //Was canonical?
1093   if (len == 0)
1094     return;
1095
1096   name[len] = '\0';
1097
1098   strcpy(dest, (name+len+1));
1099 }
1100
1101 /**
1102  * DHT resolution for delegation finished. Processing result.
1103  *
1104  * @param cls the closure
1105  * @param rh resolver handle
1106  * @param rd_count number of results (always 0)
1107  * @param rd record data (always NULL)
1108  */
1109 static void
1110 process_delegation_dht(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1111                           unsigned int rd_count,
1112                           const struct GNUNET_NAMESTORE_RecordData *rd)
1113 {
1114   struct RecordLookupHandle* rlh;
1115   rlh = (struct RecordLookupHandle*) cls;
1116   
1117   if (strcmp(rh->name, "") == 0)
1118   {
1119     /* We resolved full name for delegation. resolving record */
1120     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1121       "Resolved full name for delegation via DHT. resolving record '' in ns\n");
1122     rh->proc = &process_record_result_ns;
1123     resolve_record_ns(rh);
1124     return;
1125   }
1126
1127   /**
1128    * we still have some left
1129    **/
1130   if (is_canonical(rh->name))
1131   {
1132     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1133                "Resolving canonical record %s in ns\n", rh->name);
1134     rh->proc = &process_record_result_ns;
1135     resolve_record_ns(rh);
1136     return;
1137   }
1138   /* give up, cannot resolve */
1139   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1140              "Cannot fully resolve delegation for %s via DHT!\n",
1141              rh->name);
1142   rlh->proc(rlh->proc_cls, rh, 0, NULL);
1143 }
1144
1145
1146 /**
1147  * Start DHT lookup for a name -> PKEY (compare NS) record in
1148  * rh->authority's zone
1149  *
1150  * @param rh the pending gns query
1151  * @param name the name of the PKEY record
1152  */
1153 static void
1154 resolve_delegation_dht(struct GNUNET_GNS_ResolverHandle *rh)
1155 {
1156   uint32_t xquery;
1157   GNUNET_HashCode name_hash;
1158   GNUNET_HashCode lookup_key;
1159
1160   GNUNET_CRYPTO_hash(rh->authority_name,
1161                      strlen(rh->authority_name),
1162                      &name_hash);
1163   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1164
1165   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1166                                                   &dht_authority_lookup_timeout,
1167                                                        rh);
1168
1169   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1170   
1171   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1172                        DHT_OPERATION_TIMEOUT,
1173                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1174                        &lookup_key,
1175                        DHT_GNS_REPLICATION_LEVEL,
1176                        GNUNET_DHT_RO_NONE,
1177                        &xquery,
1178                        sizeof(xquery),
1179                        &process_delegation_result_dht,
1180                        rh);
1181
1182 }
1183
1184
1185 /**
1186  * Namestore resolution for delegation finished. Processing result.
1187  *
1188  * @param cls the closure
1189  * @param rh resolver handle
1190  * @param rd_count number of results (always 0)
1191  * @param rd record data (always NULL)
1192  */
1193 static void
1194 process_delegation_ns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1195                           unsigned int rd_count,
1196                           const struct GNUNET_NAMESTORE_RecordData *rd)
1197 {
1198   struct RecordLookupHandle* rlh;
1199   rlh = (struct RecordLookupHandle*) cls;
1200   
1201   if (strcmp(rh->name, "") == 0)
1202   {
1203     /* We resolved full name for delegation. resolving record */
1204     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1205                "Resolved full name for delegation. resolving record ''\n");
1206     rh->proc = &process_record_result_ns;
1207     resolve_record_ns(rh);
1208     return;
1209   }
1210
1211   /**
1212    * we still have some left
1213    * check if ns entry is fresh
1214    **/
1215   if (rh->status & (EXISTS | !EXPIRED))
1216   {
1217     if (is_canonical(rh->name))
1218     {
1219       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1220                  "Resolving canonical record %s\n", rh->name);
1221       rh->proc = &process_record_result_ns;
1222       resolve_record_ns(rh);
1223     }
1224     else
1225     {
1226       /* give up, cannot resolve */
1227       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1228                  "Cannot fully resolve delegation for %s!\n",
1229                  rh->name);
1230       rlh->proc(rlh->proc_cls, rh, 0, NULL);
1231     }
1232     return;
1233   }
1234   
1235   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1236              "Trying to resolve delegation for %s via DHT\n",
1237              rh->name);
1238   rh->proc = &process_delegation_dht;
1239   resolve_delegation_dht(rh);
1240 }
1241
1242 //Prototype
1243 static void resolve_delegation_ns(struct GNUNET_GNS_ResolverHandle *rh);
1244
1245 /**
1246  * This is a callback function that should give us only PKEY
1247  * records. Used to query the namestore for the authority (PKEY)
1248  * for 'name'. It will recursively try to resolve the
1249  * authority for a given name from the namestore.
1250  *
1251  * @param cls the pending query
1252  * @param key the key of the zone we did the lookup
1253  * @param expiration expiration date of the record data set in the namestore
1254  * @param name the name for which we need an authority
1255  * @param rd_count the number of records with 'name'
1256  * @param rd the record data
1257  * @param signature the signature of the authority for the record data
1258  */
1259 static void
1260 process_delegation_result_ns(void* cls,
1261                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1262                    struct GNUNET_TIME_Absolute expiration,
1263                    const char *name,
1264                    unsigned int rd_count,
1265                    const struct GNUNET_NAMESTORE_RecordData *rd,
1266                    const struct GNUNET_CRYPTO_RsaSignature *signature)
1267 {
1268   struct GNUNET_GNS_ResolverHandle *rh;
1269   struct GNUNET_TIME_Relative remaining_time;
1270   GNUNET_HashCode zone;
1271   char* new_name;
1272   
1273   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1274              rd_count);
1275
1276   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
1277   GNUNET_CRYPTO_hash(key,
1278                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1279                      &zone);
1280   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1281   
1282   rh->status = 0;
1283   
1284   if (name != NULL)
1285   {
1286     rh->status |= EXISTS;
1287   }
1288   
1289   if (remaining_time.rel_value == 0)
1290   {
1291     rh->status |= EXPIRED;
1292   }
1293   
1294   /**
1295    * No authority found in namestore.
1296    */
1297   if (rd_count == 0)
1298   {
1299     /**
1300      * We did not find an authority in the namestore
1301      */
1302     
1303     /**
1304      * No PKEY in zone.
1305      * Promote this authority back to a name maybe it is
1306      * our record.
1307      */
1308     if (strcmp(rh->name, "") == 0)
1309     {
1310       /* simply promote back */
1311       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1312                  "Promoting %s back to name\n", rh->authority_name);
1313       strcpy(rh->name, rh->authority_name);
1314     }
1315     else
1316     {
1317       /* add back to existing name */
1318       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1319                  "Adding %s back to %s\n",
1320                  rh->authority_name, rh->name);
1321       new_name = GNUNET_malloc(strlen(rh->name)
1322                                + strlen(rh->authority_name) + 2);
1323       memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1324       strcpy(new_name, rh->name);
1325       strcpy(new_name+strlen(new_name)+1, ".");
1326       strcpy(new_name+strlen(new_name)+2, rh->authority_name);
1327       GNUNET_free(rh->name);
1328       rh->name = new_name;
1329     }
1330     rh->proc(rh->proc_cls, rh, 0, NULL);
1331     return;
1332   }
1333
1334   //Note only 1 pkey should have been returned.. anything else would be strange
1335   /**
1336    * We found an authority that may be able to help us
1337    * move on with query
1338    */
1339   int i;
1340   for (i=0; i<rd_count;i++)
1341   {
1342   
1343     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1344       continue;
1345     
1346     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1347          == 0)
1348     {
1349       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1350       if (remaining_time.rel_value == 0)
1351       {
1352         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1353                    "This dht entry is expired.\n");
1354         rh->authority_chain_head->fresh = 0;
1355         rh->proc(rh->proc_cls, rh, 0, NULL);
1356         return;
1357       }
1358
1359       continue;
1360     }
1361
1362     /**
1363      * Resolve rest of query with new authority
1364      */
1365     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1366     memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1367     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1368     auth->zone = rh->authority;
1369     auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1370     memset(auth->name, 0, strlen(rh->authority_name)+1);
1371     strcpy(auth->name, rh->authority_name);
1372     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1373                                  rh->authority_chain_tail,
1374                                  auth);
1375     
1376     /**
1377      * We are done with PKEY resolution if name is empty
1378      * else resolve again with new authority
1379      */
1380     if (strcmp(rh->name, "") == 0)
1381       rh->proc(rh->proc_cls, rh, 0, NULL);
1382     else
1383       resolve_delegation_ns(rh);
1384     return;
1385   }
1386     
1387   /**
1388    * no answers found
1389    */
1390   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1391              "Authority lookup successful but no PKEY... never get here\n");
1392   rh->proc(rh->proc_cls, rh, 0, NULL);
1393 }
1394
1395
1396 /**
1397  * Resolve the delegation chain for the request in our namestore
1398  *
1399  * @param rh the resolver handle
1400  */
1401 static void
1402 resolve_delegation_ns(struct GNUNET_GNS_ResolverHandle *rh)
1403 {
1404   
1405   pop_tld(rh->name, rh->authority_name);
1406   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1407                                  &rh->authority,
1408                                  rh->authority_name,
1409                                  GNUNET_GNS_RECORD_PKEY,
1410                                  &process_delegation_result_ns,
1411                                  rh);
1412
1413 }
1414
1415 /**
1416  * Entry point for name resolution
1417  * Setup a new query and try to resolve
1418  *
1419  * @param request the request handle of the DNS request from a client
1420  * @param p the DNS query packet we received
1421  * @param q the DNS query we received parsed from p
1422  */
1423 static void
1424 start_resolution_for_dns(struct GNUNET_DNS_RequestHandle *request,
1425                           struct GNUNET_DNSPARSER_Packet *p,
1426                           struct GNUNET_DNSPARSER_Query *q)
1427 {
1428   struct GNUNET_GNS_ResolverHandle *rh;
1429   struct RecordLookupHandle* rlh;
1430   struct InterceptLookupHandle* ilh;
1431   
1432   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1433               "Starting resolution for %s (type=%d)!\n",
1434               q->name, q->type);
1435   
1436   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
1437   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1438   ilh = GNUNET_malloc(sizeof(struct InterceptLookupHandle));
1439   ilh->packet = p;
1440   ilh->query = q;
1441   ilh->request_handle = request;
1442   
1443   rh->authority = zone_hash;
1444
1445   rlh->record_type = q->type;
1446   rlh->name = q->name;
1447   rlh->proc = &reply_to_dns;
1448   rlh->proc_cls = ilh;
1449
1450   rh->proc_cls = rlh;
1451   
1452   rh->name = GNUNET_malloc(strlen(q->name)
1453                               - strlen(gnunet_tld) + 1);
1454   memset(rh->name, 0,
1455          strlen(q->name)-strlen(gnunet_tld) + 1);
1456   memcpy(rh->name, q->name,
1457          strlen(q->name)-strlen(gnunet_tld));
1458
1459   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1460   
1461   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1462   rh->authority_chain_head->prev = NULL;
1463   rh->authority_chain_head->next = NULL;
1464   rh->authority_chain_tail = rh->authority_chain_head;
1465   rh->authority_chain_head->zone = zone_hash;
1466
1467   /* Start resolution in our zone */
1468   rh->proc = &process_delegation_ns;
1469   resolve_delegation_ns(rh);
1470 }
1471
1472
1473
1474 /**
1475  * The DNS request handler
1476  * Called for every incoming DNS request.
1477  *
1478  * @param cls closure
1479  * @param rh request handle to user for reply
1480  * @param request_length number of bytes in request
1481  * @param request udp payload of the DNS request
1482  */
1483 static void
1484 handle_dns_request(void *cls,
1485                    struct GNUNET_DNS_RequestHandle *rh,
1486                    size_t request_length,
1487                    const char *request)
1488 {
1489   struct GNUNET_DNSPARSER_Packet *p;
1490   int i;
1491   char *tldoffset;
1492
1493   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n");
1494   p = GNUNET_DNSPARSER_parse (request, request_length);
1495   
1496   if (NULL == p)
1497   {
1498     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1499                 "Received malformed DNS packet, leaving it untouched\n");
1500     GNUNET_DNS_request_forward (rh);
1501     GNUNET_DNSPARSER_free_packet (p);
1502     return;
1503   }
1504   
1505   /**
1506    * Check tld and decide if we or
1507    * legacy dns is responsible
1508    *
1509    * FIXME now in theory there could be more than 1 query in the request
1510    * but if this is case we get into trouble:
1511    * either we query the GNS or the DNS. We cannot do both!
1512    * So I suggest to either only allow a single query per request or
1513    * only allow GNS or DNS requests.
1514    * The way it is implemented here now is buggy and will lead to erratic
1515    * behaviour (if multiple queries are present).
1516    */
1517   if (p->num_queries == 0)
1518   {
1519     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1520                 "No Queries in DNS packet... forwarding\n");
1521     GNUNET_DNS_request_forward (rh);
1522     GNUNET_DNSPARSER_free_packet(p);
1523     return;
1524   }
1525
1526   if (p->num_queries > 1)
1527   {
1528     /* Note: We could also look for .gnunet */
1529     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1530                 ">1 queriy in DNS packet... odd. We only process #1\n");
1531   }
1532
1533   
1534   /**
1535    * Check for .gnunet
1536    */
1537   tldoffset = p->queries[0].name + strlen(p->queries[0].name) - 1;
1538   
1539   for (i=0; i<strlen(p->queries[0].name); i++)
1540   {
1541     if (*(tldoffset-i) == '.')
1542       break;
1543   }
1544   
1545   if ((i==strlen(gnunet_tld)-1) && (0 == strcmp(tldoffset-i, gnunet_tld)))
1546   {
1547     start_resolution_for_dns(rh, p, p->queries);
1548   }
1549   else
1550   {
1551     /**
1552      * This request does not concern us. Forward to real DNS.
1553      */
1554     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1555                "Request for %s is forwarded to DNS\n", p->queries[0].name);
1556     GNUNET_DNS_request_forward (rh);
1557     GNUNET_DNSPARSER_free_packet (p);
1558   }
1559
1560 }
1561
1562 /**
1563  * Method called periodicattluy that triggers
1564  * iteration over root zone
1565  *
1566  * @param cls closure
1567  * @param tc task context
1568  */
1569 static void
1570 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1571 {
1572   GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
1573 }
1574
1575 /**
1576  * Continuation for DHT put
1577  *
1578  * @param cls closure
1579  * @param tc task context
1580  */
1581 static void
1582 record_dht_put(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1583 {
1584   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n");
1585 }
1586
1587 /* prototype */
1588 static void
1589 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1590
1591 /**
1592  * Function used to put all records successively into the DHT.
1593  *
1594  * @param cls the closure (NULL)
1595  * @param key the public key of the authority (ours)
1596  * @param expiration lifetime of the namestore entry
1597  * @param name the name of the records
1598  * @param rd_count the number of records in data
1599  * @param rd the record data
1600  * @param signature the signature for the record data
1601  */
1602 static void
1603 put_gns_record(void *cls,
1604                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1605                 struct GNUNET_TIME_Absolute expiration,
1606                 const char *name,
1607                 unsigned int rd_count,
1608                 const struct GNUNET_NAMESTORE_RecordData *rd,
1609                 const struct GNUNET_CRYPTO_RsaSignature *signature)
1610 {
1611   
1612   struct GNSNameRecordBlock *nrb;
1613   GNUNET_HashCode name_hash;
1614   GNUNET_HashCode xor_hash;
1615   struct GNUNET_CRYPTO_HashAsciiEncoded xor_hash_string;
1616   uint32_t rd_payload_length;
1617   char* nrb_data = NULL;
1618
1619   /* we're done */
1620   if (NULL == name)
1621   {
1622     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Zone iteration finished\n");
1623     GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1624     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start,
1625                                                    NULL);
1626     return;
1627   }
1628   
1629   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1630              "Putting records for %s into the DHT\n", name);
1631   
1632   rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1633   
1634   nrb = GNUNET_malloc(rd_payload_length + strlen(name) + 1 
1635                       + sizeof(struct GNSNameRecordBlock));
1636   
1637   if (signature != NULL)
1638     nrb->signature = *signature;
1639   
1640   nrb->public_key = *key;
1641
1642   nrb->rd_count = htonl(rd_count);
1643   
1644   memset(&nrb[1], 0, strlen(name) + 1);
1645   memcpy(&nrb[1], name, strlen(name));
1646
1647   nrb_data = (char*)&nrb[1];
1648   nrb_data += strlen(name) + 1;
1649
1650   rd_payload_length += sizeof(struct GNSNameRecordBlock) +
1651     strlen(name) + 1;
1652
1653   if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count,
1654                                                 rd,
1655                                                 rd_payload_length,
1656                                                 nrb_data))
1657   {
1658     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n");
1659     GNUNET_free(nrb);
1660     return;
1661     //FIXME what to do
1662   }
1663
1664
1665   /*
1666    * calculate DHT key: H(name) xor H(pubkey)
1667    */
1668   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1669   GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
1670   GNUNET_CRYPTO_hash_to_enc (&xor_hash, &xor_hash_string);
1671   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1672              "putting records for %s under key: %s with size %d\n",
1673              name, (char*)&xor_hash_string, rd_payload_length);
1674
1675   GNUNET_DHT_put (dht_handle, &xor_hash,
1676                   DHT_GNS_REPLICATION_LEVEL,
1677                   GNUNET_DHT_RO_NONE,
1678                   GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1679                   rd_payload_length,
1680                   (char*)nrb,
1681                   expiration,
1682                   DHT_OPERATION_TIMEOUT,
1683                   &record_dht_put,
1684                   NULL); //cls for cont
1685   
1686   num_public_records++;
1687
1688   /**
1689    * Reschedule periodic put
1690    */
1691   zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1692                                 &update_zone_dht_next,
1693                                 NULL);
1694
1695   GNUNET_free(nrb);
1696
1697 }
1698
1699 /**
1700  * Periodically iterate over our zone and store everything in dht
1701  *
1702  * @param cls NULL
1703  * @param tc task context
1704  */
1705 static void
1706 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1707 {
1708   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting DHT zone update!\n");
1709   if (0 == num_public_records)
1710   {
1711     dht_update_interval = GNUNET_TIME_relative_multiply(
1712                                                       GNUNET_TIME_UNIT_SECONDS,
1713                                                       1);
1714   }
1715   else
1716   {
1717     dht_update_interval = GNUNET_TIME_relative_multiply(
1718                                                       GNUNET_TIME_UNIT_SECONDS,
1719                                                      (3600/num_public_records));
1720   }
1721   num_public_records = 0; //start counting again
1722   namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
1723                                                           &zone_hash,
1724                                                           GNUNET_NAMESTORE_RF_AUTHORITY,
1725                                                           GNUNET_NAMESTORE_RF_PRIVATE,
1726                                                           &put_gns_record,
1727                                                           NULL);
1728 }
1729
1730 //Prototype
1731 static void send_shorten_response(const char* name,
1732                                   struct ClientShortenHandle *csh);
1733 static void
1734 process_shorten_pseu_lookup_ns(void *cls,
1735                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1736                  struct GNUNET_TIME_Absolute expire,
1737                  const char *name,
1738                  unsigned int rd_len,
1739                  const struct GNUNET_NAMESTORE_RecordData *rd,
1740                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1741 {
1742   struct GNUNET_GNS_ResolverHandle *rh = 
1743     (struct GNUNET_GNS_ResolverHandle *)cls;
1744   struct GNUNET_TIME_Relative remaining_time;
1745
1746   GNUNET_TIME_absolute_get_remaining (expire);
1747   rh->status = 0;
1748   
1749   if (name != NULL)
1750   {
1751     rh->status |= EXISTS;
1752   }
1753   
1754   if (remaining_time.rel_value == 0)
1755   {
1756     rh->status |= EXPIRED;
1757   }
1758
1759   rh->proc(rh->proc_cls, rh, rd_len, rd);
1760 }
1761
1762
1763 /**
1764  * Start DHT lookup for a PSEUdonym record in
1765  * rh->authority's zone
1766  *
1767  * @param rh the pending gns query
1768  */
1769 static void
1770 resolve_pseu_dht(struct GNUNET_GNS_ResolverHandle *rh)
1771 {
1772   uint32_t xquery;
1773   GNUNET_HashCode name_hash;
1774   GNUNET_HashCode lookup_key;
1775
1776   //Empty string
1777   GNUNET_CRYPTO_hash("",
1778                      1,
1779                      &name_hash);
1780
1781   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1782
1783   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1784                                                   &dht_lookup_timeout,
1785                                                   rh);
1786
1787   xquery = htonl(GNUNET_GNS_RECORD_PSEU);
1788   
1789   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1790                        DHT_OPERATION_TIMEOUT,
1791                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1792                        &lookup_key,
1793                        DHT_GNS_REPLICATION_LEVEL,
1794                        GNUNET_DHT_RO_NONE,
1795                        &xquery,
1796                        sizeof(xquery),
1797                        &process_delegation_result_dht,
1798                        rh);
1799
1800 }
1801
1802 //Prototype
1803 static void
1804 handle_shorten_pseu_ns_result(void* cls,
1805                               struct GNUNET_GNS_ResolverHandle *rh,
1806                               uint32_t rd_count,
1807                               const struct GNUNET_NAMESTORE_RecordData *rd);
1808
1809 static void
1810 handle_shorten_zone_to_name(void *cls,
1811                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1812                  struct GNUNET_TIME_Absolute expire,
1813                  const char *name,
1814                  unsigned int rd_len,
1815                  const struct GNUNET_NAMESTORE_RecordData *rd,
1816                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1817 {
1818   struct GNUNET_GNS_ResolverHandle *rh = 
1819     (struct GNUNET_GNS_ResolverHandle *)cls;
1820   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) rh->proc_cls;
1821
1822   char* result;
1823   size_t answer_len;
1824   
1825   /* we found a match in our own zone */
1826   if (rd_len != 0)
1827   {
1828     answer_len = strlen(rh->name) + strlen(name) + strlen(gnunet_tld) + 2;
1829     result = GNUNET_malloc(answer_len);
1830     memset(result, 0, answer_len);
1831     strcpy(result, rh->name);
1832     strcpy(result+strlen(rh->name), ".");
1833     strcpy(result+strlen(rh->name)+1, name);
1834     strcpy(result+strlen(rh->name)+strlen(name), gnunet_tld);
1835     
1836     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1837                "Sending shorten result %s\n", result);
1838
1839     send_shorten_response(result, csh);
1840     free_resolver_handle(rh);
1841     GNUNET_free(result);
1842   }
1843   else
1844   {
1845     /**
1846      * Nothing in our zone
1847      * check PSEU for this authority in namestore
1848      */
1849     rh->proc = &handle_shorten_pseu_ns_result;
1850     GNUNET_NAMESTORE_lookup_record(namestore_handle,
1851                                    &rh->authority_chain_head->zone,
1852                                    "",
1853                                    GNUNET_GNS_RECORD_PSEU,
1854                                    &process_shorten_pseu_lookup_ns,
1855                                    rh);
1856   }
1857 }
1858
1859 /**
1860  * Process result from namestore delegation lookup
1861  * for shorten operation
1862  *
1863  * @param cls the client shorten handle
1864  * @param rh the resolver handle
1865  * @param rd_count number of results (0)
1866  * @param rd data (NULL)
1867  */
1868 void
1869 handle_shorten_pseu_dht_result(void* cls,
1870                       struct GNUNET_GNS_ResolverHandle *rh,
1871                       uint32_t rd_len,
1872                       const struct GNUNET_NAMESTORE_RecordData *rd)
1873 {
1874   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1875   struct AuthorityChain *auth_chain;
1876   char* pseu;
1877   char* result;
1878   char* new_name;
1879   size_t answer_len;
1880   int i;
1881   
1882   /**
1883    * PSEU found
1884    */
1885   if (rd_len != 0)
1886   {
1887     for (i=0; i < rd_len; i++)
1888     {
1889       if (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)
1890       {
1891         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1892                    "Found PSEU %s\n", (char*) rd[i].data);
1893         break;
1894       }
1895     }
1896
1897     pseu = (char*) rd[i].data;
1898     answer_len = strlen(rh->name) + strlen(pseu) + strlen(gnunet_tld) + 2;
1899     result = GNUNET_malloc(answer_len);
1900     memset(result, 0, answer_len);
1901     strcpy(result, rh->name);
1902     strcpy(result+strlen(rh->name), ".");
1903     strcpy(result+strlen(rh->name)+1, pseu);
1904     strcpy(result+strlen(rh->name)+strlen(pseu), gnunet_tld);
1905     
1906     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1907                "Sending pseudonym shorten result %s\n", result);
1908     
1909     send_shorten_response(result, csh);
1910     free_resolver_handle(rh);
1911     GNUNET_free(result);
1912     return;
1913   }
1914   
1915   /**
1916    * No PSEU found.
1917    * continue with next authority
1918    * backtrack
1919    */
1920   auth_chain = rh->authority_chain_head;
1921
1922   if ((auth_chain->next->next == NULL) &&
1923       GNUNET_CRYPTO_hash_cmp(&auth_chain->next->zone, &zone_hash) == 0)
1924   {
1925     /**
1926      * Our zone is next
1927      */
1928     answer_len = strlen(rh->name) + strlen(auth_chain->name)
1929       + strlen(gnunet_tld) + 2;
1930
1931     result = GNUNET_malloc(answer_len);
1932     memset(result, 0, answer_len);
1933     strcpy(result, rh->name);
1934     strcpy(result+strlen(rh->name), ".");
1935     strcpy(result+strlen(rh->name)+1, auth_chain->name);
1936     strcpy(result+strlen(rh->name)+strlen(auth_chain->name)+1, gnunet_tld);
1937     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1938                "Sending non pseudonym shorten result %s\n", result);
1939     
1940     send_shorten_response(result, csh);
1941     free_resolver_handle(rh);
1942     GNUNET_free(result);
1943     return;
1944   }
1945
1946   /**
1947    * Continue with next authority
1948    */
1949   new_name = GNUNET_malloc(strlen(rh->name)+
1950                            strlen(auth_chain->name) + 2);
1951   memset(new_name, 0, strlen(rh->name)+
1952                       strlen(auth_chain->name) + 2);
1953   strcpy(new_name, rh->name);
1954   strcpy(new_name+strlen(rh->name)+1, ".");
1955   strcpy(new_name+strlen(rh->name)+2, auth_chain->name);
1956   GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1957                               rh->authority_chain_tail,
1958                               auth_chain);
1959   GNUNET_free(rh->name);
1960   rh->name = new_name;
1961   GNUNET_free(auth_chain->name);
1962   GNUNET_free(auth_chain);
1963   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1964                                  &zone_hash,
1965                                  &rh->authority_chain_head->zone,
1966                                  &handle_shorten_zone_to_name,
1967                                  rh);
1968
1969 }
1970
1971
1972
1973 /**
1974  * Process result from namestore PSEU lookup
1975  * for shorten operation
1976  * FIXME do we need to check for own zone here?
1977  *
1978  * @param cls the client shorten handle
1979  * @param rh the resolver handle
1980  * @param rd_count number of results (0 if none found)
1981  * @param rd data (NULL if none found)
1982  */
1983 static void
1984 handle_shorten_pseu_ns_result(void* cls,
1985                       struct GNUNET_GNS_ResolverHandle *rh,
1986                       uint32_t rd_len,
1987                       const struct GNUNET_NAMESTORE_RecordData *rd)
1988 {
1989   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1990   struct AuthorityChain *auth_chain;
1991   char* pseu;
1992   char* result;
1993   char* new_name;
1994   size_t answer_len;
1995   int i;
1996   
1997   /**
1998    * PSEU found
1999    */
2000   if (rd_len != 0)
2001   {
2002     for (i=0; i < rd_len; i++)
2003     {
2004       if (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)
2005       {
2006         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2007                    "Found PSEU %s\n", (char*) rd[i].data);
2008         break;
2009       }
2010     }
2011     
2012     pseu = (char*) rd[i].data;
2013     answer_len = strlen(rh->name) + strlen(pseu) + strlen(gnunet_tld) + 2;
2014     result = GNUNET_malloc(answer_len);
2015     memset(result, 0, answer_len);
2016     strcpy(result, rh->name);
2017     strcpy(result+strlen(rh->name), ".");
2018     strcpy(result+strlen(rh->name)+1, pseu);
2019     strcpy(result+strlen(rh->name)+strlen(pseu)+1, gnunet_tld);
2020     
2021     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2022                "Sending shorten result %s\n", result);
2023     
2024     send_shorten_response(result, csh);
2025     free_resolver_handle(rh);
2026     GNUNET_free(result);
2027     return;
2028   }
2029   
2030   /**
2031    * No PSEU found. Ask DHT if expired.
2032    * Else contunue with next authority
2033    */
2034   if (rh->status & (EXISTS | !EXPIRED))
2035   {
2036     /**
2037      * backtrack
2038      */
2039     auth_chain = rh->authority_chain_head;
2040     new_name = GNUNET_malloc(strlen(rh->name)+
2041                              strlen(auth_chain->name) + 2);
2042     memset(new_name, 0, strlen(rh->name)+
2043                         strlen(auth_chain->name) + 2);
2044     strcpy(new_name, rh->name);
2045     strcpy(new_name+strlen(rh->name)+1, ".");
2046     strcpy(new_name+strlen(rh->name)+2, auth_chain->name);
2047     
2048     GNUNET_free(rh->name);
2049     rh->name = new_name;
2050     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2051                                 rh->authority_chain_tail,
2052                                 auth_chain);
2053
2054     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2055                                    &zone_hash,
2056                                    &rh->authority_chain_head->zone,
2057                                    &handle_shorten_zone_to_name,
2058                                    rh);
2059     return;
2060   }
2061
2062   /**
2063    * Ask DHT
2064    */
2065   rh->authority = rh->authority_chain_head->zone;
2066   rh->proc = &handle_shorten_pseu_dht_result;
2067   resolve_pseu_dht(rh);
2068
2069 }
2070
2071
2072
2073 /**
2074  * Process result from namestore delegation lookup
2075  * for shorten operation
2076  *
2077  * @param cls the client shorten handle
2078  * @param rh the resolver handle
2079  * @param rd_count number of results (0)
2080  * @param rd data (NULL)
2081  */
2082 void
2083 handle_shorten_delegation_result(void* cls,
2084                       struct GNUNET_GNS_ResolverHandle *rh,
2085                       uint32_t rd_count,
2086                       const struct GNUNET_NAMESTORE_RecordData *rd)
2087 {
2088   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
2089   struct AuthorityChain *auth_chain;
2090   char* result;
2091   size_t answer_len;
2092   
2093   /**
2094    * At this point rh->name contains the part of the name
2095    * that we do not have a PKEY in our namestore to resolve.
2096    * The authority chain in the resolver handle is now
2097    * useful to backtrack if needed
2098    */
2099   
2100   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2101              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2102
2103   if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
2104                              &zone_hash) == 0)
2105   {
2106     /**
2107      * This is our zone append .gnunet unless name is empty
2108      * (it shouldn't be, usually FIXME what happens if we
2109      * shorten to our zone to a "" record??)
2110      **/
2111     
2112     answer_len = strlen(rh->name) + strlen(gnunet_tld) + 2;
2113     result = GNUNET_malloc(answer_len);
2114     memset(result, 0, answer_len);
2115     strcpy(result, rh->name);
2116     strcpy(result+strlen(rh->name), ".");
2117     strcpy(result+strlen(rh->name)+1, gnunet_tld);
2118
2119     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2120                "Our zone: Sending name as shorten result %s\n", rh->name);
2121     
2122     send_shorten_response(result, csh); //FIXME +.gnunet!
2123     free_resolver_handle(rh);
2124     GNUNET_free(result);
2125     return;
2126   }
2127   
2128   auth_chain = rh->authority_chain_head;
2129   /* backtrack authorities for pseu */
2130   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2131                                  &zone_hash, //ours
2132                                  &auth_chain->zone,
2133                                  &handle_shorten_zone_to_name,
2134                                  rh);
2135
2136 }
2137
2138 typedef void (*ShortenResponseProc) (void* cls, const char* name);
2139
2140 /**
2141  * Shorten a given name
2142  *
2143  * @param name the name to shorten
2144  * @param csh the shorten handle of the request
2145  */
2146 static void
2147 shorten_name(char* name, struct ClientShortenHandle* csh)
2148 {
2149
2150   struct GNUNET_GNS_ResolverHandle *rh;
2151   
2152   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2153               "Starting resolution for %s (type=%d)!\n",
2154               name, GNUNET_GNS_RECORD_PKEY);
2155   
2156   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
2157   rh->authority = zone_hash;
2158   
2159   rh->name = GNUNET_malloc(strlen(name)
2160                               - strlen(gnunet_tld) + 1);
2161   memset(rh->name, 0,
2162          strlen(name)-strlen(gnunet_tld) + 1);
2163   memcpy(rh->name, name,
2164          strlen(name)-strlen(gnunet_tld));
2165
2166   csh->name = GNUNET_malloc(strlen(name)
2167                             - strlen(gnunet_tld) + 1);
2168   memset(csh->name, 0,
2169          strlen(name)-strlen(gnunet_tld) + 1);
2170   memcpy(csh->name, name,
2171          strlen(name)-strlen(gnunet_tld));
2172
2173   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
2174
2175   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2176   rh->authority_chain_tail = rh->authority_chain_head;
2177   rh->authority_chain_head->zone = zone_hash;
2178   rh->proc = &handle_shorten_delegation_result;
2179   rh->proc_cls = (void*)csh;
2180
2181   /* Start delegation resolution in our namestore */
2182   resolve_delegation_ns(rh);
2183
2184 }
2185
2186 /**
2187  * Send shorten response back to client
2188  * 
2189  * @param name the shortened name result or NULL if cannot be shortened
2190  * @param csh the handle to the shorten request
2191  */
2192 static void
2193 send_shorten_response(const char* name, struct ClientShortenHandle *csh)
2194 {
2195   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
2196               "SHORTEN_RESULT", name);
2197   struct GNUNET_GNS_ClientShortenResultMessage *rmsg;
2198   
2199   if (name == NULL)
2200   {
2201     name = "";
2202   }
2203
2204   rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientShortenResultMessage)
2205                        + strlen(name) + 1);
2206   
2207   rmsg->id = csh->unique_id;
2208   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT);
2209   rmsg->header.size = 
2210     htons(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) +
2211           strlen(name) + 1);
2212
2213   strcpy((char*)&rmsg[1], name);
2214
2215   GNUNET_SERVER_notification_context_unicast (nc, csh->client,
2216                               (const struct GNUNET_MessageHeader *) rmsg,
2217                               GNUNET_NO);
2218   GNUNET_SERVER_receive_done (csh->client, GNUNET_OK);
2219   
2220   GNUNET_free(rmsg);
2221   GNUNET_free(csh->name);
2222   GNUNET_free(csh);
2223
2224 }
2225
2226 /**
2227  * Handle a shorten message from the api
2228  *
2229  * @param cls the closure
2230  * @param client the client
2231  * @param message the message
2232  */
2233 static void handle_shorten(void *cls,
2234                            struct GNUNET_SERVER_Client * client,
2235                            const struct GNUNET_MessageHeader * message)
2236 {
2237   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "SHORTEN");
2238
2239   size_t msg_size = 0;
2240   struct ClientShortenHandle *csh;
2241
2242   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientShortenMessage))
2243   {
2244     GNUNET_break_op (0);
2245     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2246     return;
2247   }
2248
2249   GNUNET_SERVER_notification_context_add (nc, client);
2250
2251   struct GNUNET_GNS_ClientShortenMessage *sh_msg =
2252     (struct GNUNET_GNS_ClientShortenMessage *) message;
2253   
2254   msg_size = ntohs(message->size);
2255
2256   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2257   {
2258     GNUNET_break_op (0);
2259     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2260     return;
2261   }
2262
2263   csh = GNUNET_malloc(sizeof(struct ClientShortenHandle));
2264   csh->client = client;
2265   csh->unique_id = sh_msg->id;
2266   
2267   shorten_name((char*)&sh_msg[1], csh);
2268
2269 }
2270
2271
2272 /**
2273  * Send get authority response back to client
2274  * 
2275  * @param name the shortened name result or NULL if cannot be shortened
2276  * @param cah the handle to the get authority request
2277  */
2278 static void
2279 send_get_auth_response(const char* name, struct ClientGetAuthHandle *cah)
2280 {
2281   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
2282               "GET_AUTH_RESULT", name);
2283   struct GNUNET_GNS_ClientGetAuthResultMessage *rmsg;
2284   
2285   if (name == NULL)
2286   {
2287     name = "";
2288   }
2289
2290   rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage)
2291                        + strlen(name) + 1);
2292   
2293   rmsg->id = cah->unique_id;
2294   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT);
2295   rmsg->header.size = 
2296     htons(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage) +
2297           strlen(name) + 1);
2298
2299   strcpy((char*)&rmsg[1], name);
2300
2301   GNUNET_SERVER_notification_context_unicast (nc, cah->client,
2302                               (const struct GNUNET_MessageHeader *) rmsg,
2303                               GNUNET_NO);
2304   GNUNET_SERVER_receive_done (cah->client, GNUNET_OK);
2305   
2306   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up handles...\n");
2307
2308   GNUNET_free(rmsg);
2309   GNUNET_free(cah->name);
2310   GNUNET_free(cah);
2311
2312   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done.\n");
2313
2314 }
2315
2316 /**
2317  * Process result from namestore delegation lookup
2318  * for get authority operation
2319  *
2320  * @param cls the client get auth handle
2321  * @param rh the resolver handle
2322  * @param rd_count number of results (0)
2323  * @param rd data (NULL)
2324  */
2325 void
2326 handle_get_auth_delegation_result(void* cls,
2327                       struct GNUNET_GNS_ResolverHandle *rh,
2328                       uint32_t rd_count,
2329                       const struct GNUNET_NAMESTORE_RecordData *rd)
2330 {
2331   struct ClientGetAuthHandle* cah = (struct ClientGetAuthHandle*) cls;
2332   struct AuthorityChain *auth_chain;
2333   char* result;
2334   size_t answer_len;
2335   
2336   /**
2337    * At this point rh->name contains the part of the name
2338    * that we do not have a PKEY in our namestore to resolve.
2339    * The authority chain in the resolver handle is now
2340    * useful to backtrack if needed
2341    */
2342   
2343   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2344              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2345
2346   if (is_canonical(rh->name))
2347   {
2348     /**
2349      * We successfully resolved the authority in the ns
2350      * FIXME for our purposes this is fine
2351      * but maybe we want to have an api that also looks
2352      * into the dht (i.e. option in message)
2353      **/
2354     if (strlen(rh->name) > strlen(cah->name))
2355     {
2356       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2357                  "Record name longer than original lookup name... odd!\n");
2358       //FIXME to sth here
2359     }
2360
2361
2362     answer_len = strlen(cah->name) - strlen(rh->name) + strlen(gnunet_tld) + 1;
2363     result = GNUNET_malloc(answer_len);
2364     memset(result, 0, answer_len);
2365     strcpy(result, cah->name + strlen(rh->name) + 1);
2366     strcpy(result+strlen(result), gnunet_tld);
2367
2368     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2369                "Got authority result %s\n", result);
2370     
2371     send_get_auth_response(result, cah);
2372     free_resolver_handle(rh);
2373     GNUNET_free(result);
2374     return;
2375   }
2376   
2377   auth_chain = rh->authority_chain_head;
2378   /* backtrack authorities for pseu */
2379   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2380                                  &zone_hash, //ours
2381                                  &auth_chain->zone,
2382                                  &handle_shorten_zone_to_name,
2383                                  rh);
2384
2385 }
2386
2387
2388 /**
2389  * Get authority for a given name
2390  *
2391  * @param name the name to shorten
2392  * @param csh the shorten handle of the request
2393  */
2394 static void
2395 get_authority(char* name, struct ClientGetAuthHandle* cah)
2396 {
2397
2398   struct GNUNET_GNS_ResolverHandle *rh;
2399   
2400   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2401               "Starting authority resolution for %s (type=%d)!\n",
2402               name, GNUNET_GNS_RECORD_PKEY);
2403   
2404   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
2405   rh->authority = zone_hash;
2406   
2407   rh->name = GNUNET_malloc(strlen(name)
2408                               - strlen(gnunet_tld) + 1);
2409   memset(rh->name, 0,
2410          strlen(name)-strlen(gnunet_tld) + 1);
2411   memcpy(rh->name, name,
2412          strlen(name)-strlen(gnunet_tld));
2413
2414   cah->name = GNUNET_malloc(strlen(name)
2415                             - strlen(gnunet_tld) + 1);
2416   memset(cah->name, 0,
2417          strlen(name)-strlen(gnunet_tld) + 1);
2418   memcpy(cah->name, name,
2419          strlen(name)-strlen(gnunet_tld));
2420
2421   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
2422
2423   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2424   rh->authority_chain_tail = rh->authority_chain_head;
2425   rh->authority_chain_head->zone = zone_hash;
2426   rh->proc = &handle_get_auth_delegation_result;
2427   rh->proc_cls = (void*)cah;
2428
2429   /* Start delegation resolution in our namestore */
2430   resolve_delegation_ns(rh);
2431
2432 }
2433
2434
2435 /**
2436  * Handle a get authority message from the api
2437  *
2438  * @param cls the closure
2439  * @param client the client
2440  * @param message the message
2441  */
2442 static void handle_get_authority(void *cls,
2443                            struct GNUNET_SERVER_Client * client,
2444                            const struct GNUNET_MessageHeader * message)
2445 {
2446   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "GET_AUTH");
2447
2448   size_t msg_size = 0;
2449   struct ClientGetAuthHandle *cah;
2450
2451   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientGetAuthMessage))
2452   {
2453     GNUNET_break_op (0);
2454     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2455     return;
2456   }
2457
2458   GNUNET_SERVER_notification_context_add (nc, client);
2459
2460   struct GNUNET_GNS_ClientGetAuthMessage *sh_msg =
2461     (struct GNUNET_GNS_ClientGetAuthMessage *) message;
2462   
2463   msg_size = ntohs(message->size);
2464
2465   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2466   {
2467     GNUNET_break_op (0);
2468     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2469     return;
2470   }
2471
2472   cah = GNUNET_malloc(sizeof(struct ClientGetAuthHandle));
2473   cah->client = client;
2474   cah->unique_id = sh_msg->id;
2475   
2476   get_authority((char*)&sh_msg[1], cah);
2477
2478 }
2479
2480
2481 /**
2482  * Reply to client with the result from our lookup.
2483  *
2484  * @param cls the closure (our client lookup handle)
2485  * @param rh the request handle of the lookup
2486  * @param rd_count the number of records
2487  * @param rd the record data
2488  */
2489 static void
2490 reply_to_client(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
2491                 uint32_t rd_count,
2492                 const struct GNUNET_NAMESTORE_RecordData *rd)
2493 {
2494   struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls;
2495   struct GNUNET_GNS_ClientLookupResultMessage *rmsg;
2496   size_t len;
2497   
2498   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %d results\n",
2499               "LOOKUP_RESULT", rd_count);
2500   
2501   len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
2502   rmsg = GNUNET_malloc(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
2503   
2504   rmsg->id = clh->unique_id;
2505   rmsg->rd_count = htonl(rd_count);
2506   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
2507   rmsg->header.size = 
2508     htons(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
2509
2510   GNUNET_NAMESTORE_records_serialize (rd_count, rd, len, (char*)&rmsg[1]);
2511   
2512   GNUNET_SERVER_notification_context_unicast (nc, clh->client,
2513                                 (const struct GNUNET_MessageHeader *) rmsg,
2514                                 GNUNET_NO);
2515   GNUNET_SERVER_receive_done (clh->client, GNUNET_OK);
2516   
2517   GNUNET_free(rh->proc_cls);
2518   free_resolver_handle(rh);
2519   GNUNET_free(rmsg);
2520   GNUNET_free(clh->name);
2521   GNUNET_free(clh);
2522
2523 }
2524
2525 /**
2526  * Lookup a given name
2527  *
2528  * @param name the name to looku[
2529  * @param clh the client lookup handle
2530  */
2531 static void
2532 lookup_name(char* name, struct ClientLookupHandle* clh)
2533 {
2534
2535   struct GNUNET_GNS_ResolverHandle *rh;
2536   struct RecordLookupHandle* rlh;
2537   
2538   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2539               "Starting resolution for %s (type=%d)!\n",
2540               name, clh->type);
2541   
2542   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
2543   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
2544   
2545   rh->authority = zone_hash;
2546
2547   rlh->record_type = clh->type;
2548   rlh->name = clh->name;
2549   rlh->proc = &reply_to_client;
2550   rlh->proc_cls = clh;
2551
2552   rh->proc_cls = rlh;
2553   
2554   rh->name = GNUNET_malloc(strlen(name)
2555                               - strlen(gnunet_tld) + 1);
2556   memset(rh->name, 0,
2557          strlen(name)-strlen(gnunet_tld) + 1);
2558   memcpy(rh->name, name,
2559          strlen(name)-strlen(gnunet_tld));
2560
2561   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
2562   
2563   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2564   rh->authority_chain_head->prev = NULL;
2565   rh->authority_chain_head->next = NULL;
2566   rh->authority_chain_tail = rh->authority_chain_head;
2567   rh->authority_chain_head->zone = zone_hash;
2568
2569   /* Start resolution in our zone */
2570   rh->proc = &process_delegation_ns;
2571   resolve_delegation_ns(rh);
2572 }
2573
2574
2575 /**
2576  * Handle lookup requests from client
2577  *
2578  * @param cls the closure
2579  * @param client the client
2580  * @param message the message
2581  */
2582 static void
2583 handle_lookup(void *cls,
2584               struct GNUNET_SERVER_Client * client,
2585               const struct GNUNET_MessageHeader * message)
2586 {
2587   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "LOOKUP");
2588
2589   size_t msg_size = 0;
2590   struct ClientLookupHandle *clh;
2591
2592   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientLookupMessage))
2593   {
2594     GNUNET_break_op (0);
2595     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2596     return;
2597   }
2598
2599   GNUNET_SERVER_notification_context_add (nc, client);
2600
2601   struct GNUNET_GNS_ClientLookupMessage *sh_msg =
2602     (struct GNUNET_GNS_ClientLookupMessage *) message;
2603   
2604   msg_size = ntohs(message->size);
2605
2606   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2607   {
2608     GNUNET_break_op (0);
2609     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2610     return;
2611   }
2612
2613   clh = GNUNET_malloc(sizeof(struct ClientLookupHandle));
2614   clh->client = client;
2615   clh->name = GNUNET_malloc(strlen((char*)&sh_msg[1]) + 1);
2616   strcpy(clh->name, (char*)&sh_msg[1]);
2617   clh->unique_id = sh_msg->id;
2618   clh->type = ntohl(sh_msg->type);
2619   
2620   lookup_name((char*)&sh_msg[1], clh);
2621 }
2622
2623
2624
2625 /**
2626  * Process GNS requests.
2627  *
2628  * @param cls closure)
2629  * @param server the initialized server
2630  * @param c configuration to use
2631  */
2632 static void
2633 run (void *cls, struct GNUNET_SERVER_Handle *server,
2634      const struct GNUNET_CONFIGURATION_Handle *c)
2635 {
2636   
2637   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n");
2638
2639   char* keyfile;
2640   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
2641
2642   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2643     {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0},
2644     {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0},
2645     {&handle_get_authority, NULL, GNUNET_MESSAGE_TYPE_GNS_GET_AUTH, 0}
2646   };
2647
2648   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "gns",
2649                                              "ZONEKEY", &keyfile))
2650   {
2651     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2652                 "No private key for root zone specified%s!\n", keyfile);
2653     GNUNET_SCHEDULER_shutdown(0);
2654     return;
2655   }
2656
2657   zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2658   GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
2659
2660   GNUNET_CRYPTO_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2661                      &zone_hash);
2662   GNUNET_free(keyfile);
2663   
2664
2665   dns_handle = NULL;
2666   if (GNUNET_YES ==
2667       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
2668                                             "HIJACK_DNS"))
2669   {
2670     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2671                "DNS hijacking enabled... connecting to service.\n");
2672     /**
2673      * Do gnunet dns init here
2674      */
2675     dns_handle = GNUNET_DNS_connect(c,
2676                                     GNUNET_DNS_FLAG_PRE_RESOLUTION,
2677                                     &handle_dns_request, /* rh */
2678                                     NULL); /* Closure */
2679     if (NULL == dns_handle)
2680     {
2681       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2682                "Failed to connect to the dnsservice!\n");
2683     }
2684   }
2685
2686   
2687
2688   /**
2689    * handle to our local namestore
2690    */
2691   namestore_handle = GNUNET_NAMESTORE_connect(c);
2692
2693   if (NULL == namestore_handle)
2694   {
2695     //FIXME do error handling;
2696     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2697                "Failed to connect to the namestore!\n");
2698     GNUNET_SCHEDULER_shutdown(0);
2699     return;
2700   }
2701   
2702   /**
2703    * handle to the dht
2704    */
2705   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
2706
2707   if (NULL == dht_handle)
2708   {
2709     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
2710   }
2711
2712   //put_some_records(); //FIXME for testing
2713   
2714   /**
2715    * Schedule periodic put
2716    * for our records
2717    * We have roughly an hour for all records;
2718    */
2719   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
2720                                                       1);
2721   //zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
2722
2723   GNUNET_SERVER_add_handlers (server, handlers);
2724   
2725   //FIXME
2726   //GNUNET_SERVER_disconnect_notify (server,
2727   //                                 &client_disconnect_notification,
2728   //                                 NULL);
2729
2730   nc = GNUNET_SERVER_notification_context_create (server, 1);
2731
2732   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
2733                                 NULL);
2734 }
2735
2736
2737 /**
2738  * The main function for the GNS service.
2739  *
2740  * @param argc number of arguments from the command line
2741  * @param argv command line arguments
2742  * @return 0 ok, 1 on error
2743  */
2744 int
2745 main (int argc, char *const *argv)
2746 {
2747   int ret;
2748
2749   ret =
2750       (GNUNET_OK ==
2751        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
2752                            NULL)) ? 0 : 1;
2753   return ret;
2754 }
2755
2756 /* end of gnunet-service-gns.c */