-add get_athority test, fixes
[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   if (data == NULL)
867     return;
868   
869   //FIXME check expiration?
870   
871   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
872   nrb = (struct GNSNameRecordBlock*)data;
873   
874   /* stop dht lookup and timeout task */
875   GNUNET_DHT_get_stop (rh->get_handle);
876   GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
877
878   rh->get_handle = NULL;
879   num_records = ntohl(nrb->rd_count);
880   name = (char*)&nrb[1];
881   {
882     struct GNUNET_NAMESTORE_RecordData rd[num_records];
883     
884     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
885     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
886   
887     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
888                                                                rd_data,
889                                                                num_records,
890                                                                rd))
891     {
892       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
893       return;
894     }
895
896     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
897                "Got name: %s (wanted %s)\n", name, rh->authority_name);
898     for (i=0; i<num_records; i++)
899     {
900     
901       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
902                 "Got name: %s (wanted %s)\n", name, rh->authority_name);
903       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
904                  "Got type: %d (wanted %d)\n",
905                  rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
906       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
907                  "Got data length: %d\n", rd[i].data_size);
908       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
909                  "Got flag %d\n", rd[i].flags);
910
911       if ((strcmp(name, rh->authority_name) == 0) &&
912           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
913       {
914         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
915         rh->answered = 1;
916         memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
917         struct AuthorityChain *auth =
918           GNUNET_malloc(sizeof(struct AuthorityChain));
919         auth->zone = rh->authority;
920         auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
921         memset(auth->name, 0, strlen(rh->authority_name)+1);
922         strcpy(auth->name, rh->authority_name);
923         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
924                                      rh->authority_chain_tail,
925                                      auth);
926       }
927
928     }
929
930
931     GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
932     GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
933
934     /* Save to namestore */
935     if (0 != GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone))
936     {
937       GNUNET_NAMESTORE_record_put (namestore_handle,
938                                  &nrb->public_key,
939                                  name,
940                                  exp,
941                                  num_records,
942                                  rd,
943                                  &nrb->signature,
944                                  &on_namestore_record_put_result, //cont
945                                  NULL); //cls
946     }
947   }
948   
949   if (rh->answered)
950   {
951     rh->answered = 0;
952     /**
953      * delegate
954      * FIXME in this case. should we ask namestore again?
955      */
956     if (strcmp(rh->name, "") == 0)
957       rh->proc(rh->proc_cls, rh, 0, NULL);
958     else
959       resolve_delegation_dht(rh);
960     return;
961   }
962
963   /**
964    * should never get here unless false dht key/put
965    * block plugin should handle this
966    **/
967   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup error!\n");
968   GNUNET_break(0);
969 }
970
971
972 /**
973  * Process DHT lookup result for record.
974  *
975  * @param cls the closure
976  * @param rh resolver handle
977  * @param rd_count number of results (always 0)
978  * @param rd record data (always NULL)
979  */
980 static void
981 process_record_result_dht(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
982                        unsigned int rd_count,
983                        const struct GNUNET_NAMESTORE_RecordData *rd)
984 {
985   struct RecordLookupHandle* rlh;
986   rlh = (struct RecordLookupHandle*)cls;
987   if (rd_count == 0)
988   {
989     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
990                "No records for %s found in DHT. Aborting\n",
991                rh->name);
992     /* give up, cannot resolve */
993     rlh->proc(rlh->proc_cls, rh, 0, NULL);
994     return;
995   }
996
997   /* results found yay */
998   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
999              "Record resolved from namestore!");
1000   rlh->proc(rlh->proc_cls, rh, rd_count, rd);
1001
1002 }
1003
1004
1005 /**
1006  * Process namestore lookup result for record.
1007  *
1008  * @param cls the closure
1009  * @param rh resolver handle
1010  * @param rd_count number of results (always 0)
1011  * @param rd record data (always NULL)
1012  */
1013 static void
1014 process_record_result_ns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1015                        unsigned int rd_count,
1016                        const struct GNUNET_NAMESTORE_RecordData *rd)
1017 {
1018   struct RecordLookupHandle* rlh;
1019   rlh = (struct RecordLookupHandle*) cls;
1020   if (rd_count == 0)
1021   {
1022     /* ns entry expired. try dht */
1023     if (rh->status & (EXPIRED | !EXISTS))
1024     {
1025       rh->proc = &process_record_result_dht;
1026       resolve_record_dht(rh);
1027       return;
1028     }
1029     /* give up, cannot resolve */
1030     rlh->proc(rlh->proc_cls, rh, 0, NULL);
1031     return;
1032   }
1033
1034   /* results found yay */
1035   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1036              "Record resolved from namestore!");
1037   rlh->proc(rlh->proc_cls, rh, rd_count, rd);
1038
1039 }
1040
1041
1042 /**
1043  * Determine if this name is canonical.
1044  * i.e.
1045  * a.b.gnunet  = not canonical
1046  * a           = canonical
1047  *
1048  * @param name the name to test
1049  * @return 1 if canonical
1050  */
1051 static int
1052 is_canonical(char* name)
1053 {
1054   uint32_t len = strlen(name);
1055   int i;
1056
1057   for (i=0; i<len; i++)
1058   {
1059     if (*(name+i) == '.')
1060       return 0;
1061   }
1062   return 1;
1063 }
1064
1065 /**
1066  * Move one level up in the domain hierarchy and return the
1067  * passed top level domain.
1068  *
1069  * @param name the domain
1070  * @param dest the destination where the tld will be put
1071  */
1072 void
1073 pop_tld(char* name, char* dest)
1074 {
1075   uint32_t len;
1076
1077   if (is_canonical(name))
1078   {
1079     strcpy(dest, name);
1080     strcpy(name, "");
1081     return;
1082   }
1083
1084   for (len = strlen(name); len > 0; len--)
1085   {
1086     if (*(name+len) == '.')
1087       break;
1088   }
1089   
1090   //Was canonical?
1091   if (len == 0)
1092     return;
1093
1094   name[len] = '\0';
1095
1096   strcpy(dest, (name+len+1));
1097 }
1098
1099 /**
1100  * DHT resolution for delegation finished. Processing result.
1101  *
1102  * @param cls the closure
1103  * @param rh resolver handle
1104  * @param rd_count number of results (always 0)
1105  * @param rd record data (always NULL)
1106  */
1107 static void
1108 process_delegation_dht(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1109                           unsigned int rd_count,
1110                           const struct GNUNET_NAMESTORE_RecordData *rd)
1111 {
1112   struct RecordLookupHandle* rlh;
1113   rlh = (struct RecordLookupHandle*) cls;
1114   
1115   if (strcmp(rh->name, "") == 0)
1116   {
1117     /* We resolved full name for delegation. resolving record */
1118     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1119       "Resolved full name for delegation via DHT. resolving record '' in ns\n");
1120     rh->proc = &process_record_result_ns;
1121     resolve_record_ns(rh);
1122     return;
1123   }
1124
1125   /**
1126    * we still have some left
1127    **/
1128   if (is_canonical(rh->name))
1129   {
1130     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1131                "Resolving canonical record %s in ns\n", rh->name);
1132     rh->proc = &process_record_result_ns;
1133     resolve_record_ns(rh);
1134     return;
1135   }
1136   /* give up, cannot resolve */
1137   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1138              "Cannot fully resolve delegation for %s via DHT!\n",
1139              rh->name);
1140   rlh->proc(rlh->proc_cls, rh, 0, NULL);
1141 }
1142
1143
1144 /**
1145  * Start DHT lookup for a name -> PKEY (compare NS) record in
1146  * rh->authority's zone
1147  *
1148  * @param rh the pending gns query
1149  * @param name the name of the PKEY record
1150  */
1151 static void
1152 resolve_delegation_dht(struct GNUNET_GNS_ResolverHandle *rh)
1153 {
1154   uint32_t xquery;
1155   GNUNET_HashCode name_hash;
1156   GNUNET_HashCode lookup_key;
1157
1158   GNUNET_CRYPTO_hash(rh->authority_name,
1159                      strlen(rh->authority_name),
1160                      &name_hash);
1161   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1162
1163   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1164                                                   &dht_authority_lookup_timeout,
1165                                                        rh);
1166
1167   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1168   
1169   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1170                        DHT_OPERATION_TIMEOUT,
1171                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1172                        &lookup_key,
1173                        DHT_GNS_REPLICATION_LEVEL,
1174                        GNUNET_DHT_RO_NONE,
1175                        &xquery,
1176                        sizeof(xquery),
1177                        &process_delegation_result_dht,
1178                        rh);
1179
1180 }
1181
1182
1183 /**
1184  * Namestore resolution for delegation finished. Processing result.
1185  *
1186  * @param cls the closure
1187  * @param rh resolver handle
1188  * @param rd_count number of results (always 0)
1189  * @param rd record data (always NULL)
1190  */
1191 static void
1192 process_delegation_ns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1193                           unsigned int rd_count,
1194                           const struct GNUNET_NAMESTORE_RecordData *rd)
1195 {
1196   struct RecordLookupHandle* rlh;
1197   rlh = (struct RecordLookupHandle*) cls;
1198   
1199   if (strcmp(rh->name, "") == 0)
1200   {
1201     /* We resolved full name for delegation. resolving record */
1202     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1203                "Resolved full name for delegation. resolving record ''\n");
1204     rh->proc = &process_record_result_ns;
1205     resolve_record_ns(rh);
1206     return;
1207   }
1208
1209   /**
1210    * we still have some left
1211    * check if ns entry is fresh
1212    **/
1213   if (rh->status & (EXISTS | !EXPIRED))
1214   {
1215     if (is_canonical(rh->name))
1216     {
1217       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1218                  "Resolving canonical record %s\n", rh->name);
1219       rh->proc = &process_record_result_ns;
1220       resolve_record_ns(rh);
1221     }
1222     else
1223     {
1224       /* give up, cannot resolve */
1225       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1226                  "Cannot fully resolve delegation for %s!\n",
1227                  rh->name);
1228       rlh->proc(rlh->proc_cls, rh, 0, NULL);
1229     }
1230     return;
1231   }
1232   
1233   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1234              "Trying to resolve delegation for %s via DHT\n",
1235              rh->name);
1236   rh->proc = &process_delegation_dht;
1237   resolve_delegation_dht(rh);
1238 }
1239
1240 //Prototype
1241 static void resolve_delegation_ns(struct GNUNET_GNS_ResolverHandle *rh);
1242
1243 /**
1244  * This is a callback function that should give us only PKEY
1245  * records. Used to query the namestore for the authority (PKEY)
1246  * for 'name'. It will recursively try to resolve the
1247  * authority for a given name from the namestore.
1248  *
1249  * @param cls the pending query
1250  * @param key the key of the zone we did the lookup
1251  * @param expiration expiration date of the record data set in the namestore
1252  * @param name the name for which we need an authority
1253  * @param rd_count the number of records with 'name'
1254  * @param rd the record data
1255  * @param signature the signature of the authority for the record data
1256  */
1257 static void
1258 process_delegation_result_ns(void* cls,
1259                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1260                    struct GNUNET_TIME_Absolute expiration,
1261                    const char *name,
1262                    unsigned int rd_count,
1263                    const struct GNUNET_NAMESTORE_RecordData *rd,
1264                    const struct GNUNET_CRYPTO_RsaSignature *signature)
1265 {
1266   struct GNUNET_GNS_ResolverHandle *rh;
1267   struct GNUNET_TIME_Relative remaining_time;
1268   GNUNET_HashCode zone;
1269   char* new_name;
1270   
1271   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1272              rd_count);
1273
1274   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
1275   GNUNET_CRYPTO_hash(key,
1276                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1277                      &zone);
1278   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1279   
1280   rh->status = 0;
1281   
1282   if (name != NULL)
1283   {
1284     rh->status |= EXISTS;
1285   }
1286   
1287   if (remaining_time.rel_value == 0)
1288   {
1289     rh->status |= EXPIRED;
1290   }
1291   
1292   /**
1293    * No authority found in namestore.
1294    */
1295   if (rd_count == 0)
1296   {
1297     /**
1298      * We did not find an authority in the namestore
1299      */
1300     
1301     /**
1302      * No PKEY in zone.
1303      * Promote this authority back to a name maybe it is
1304      * our record.
1305      */
1306     if (strcmp(rh->name, "") == 0)
1307     {
1308       /* simply promote back */
1309       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1310                  "Promoting %s back to name\n", rh->authority_name);
1311       strcpy(rh->name, rh->authority_name);
1312     }
1313     else
1314     {
1315       /* add back to existing name */
1316       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1317                  "Adding %s back to %s\n",
1318                  rh->authority_name, rh->name);
1319       new_name = GNUNET_malloc(strlen(rh->name)
1320                                + strlen(rh->authority_name) + 2);
1321       memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1322       strcpy(new_name, rh->name);
1323       strcpy(new_name+strlen(new_name)+1, ".");
1324       strcpy(new_name+strlen(new_name)+2, rh->authority_name);
1325       GNUNET_free(rh->name);
1326       rh->name = new_name;
1327     }
1328     rh->proc(rh->proc_cls, rh, 0, NULL);
1329     return;
1330   }
1331
1332   //Note only 1 pkey should have been returned.. anything else would be strange
1333   /**
1334    * We found an authority that may be able to help us
1335    * move on with query
1336    */
1337   int i;
1338   for (i=0; i<rd_count;i++)
1339   {
1340   
1341     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1342       continue;
1343     
1344     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1345          == 0)
1346     {
1347       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1348       if (remaining_time.rel_value == 0)
1349       {
1350         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1351                    "This dht entry is expired.\n");
1352         rh->authority_chain_head->fresh = 0;
1353         rh->proc(rh->proc_cls, rh, 0, NULL);
1354         return;
1355       }
1356
1357       continue;
1358     }
1359
1360     /**
1361      * Resolve rest of query with new authority
1362      */
1363     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1364     memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1365     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1366     auth->zone = rh->authority;
1367     auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1368     memset(auth->name, 0, strlen(rh->authority_name)+1);
1369     strcpy(auth->name, rh->authority_name);
1370     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1371                                  rh->authority_chain_tail,
1372                                  auth);
1373     
1374     /**
1375      * We are done with PKEY resolution if name is empty
1376      * else resolve again with new authority
1377      */
1378     if (strcmp(rh->name, "") == 0)
1379       rh->proc(rh->proc_cls, rh, 0, NULL);
1380     else
1381       resolve_delegation_ns(rh);
1382     return;
1383   }
1384     
1385   /**
1386    * no answers found
1387    */
1388   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1389              "Authority lookup successful but no PKEY... never get here\n");
1390   rh->proc(rh->proc_cls, rh, 0, NULL);
1391 }
1392
1393
1394 /**
1395  * Resolve the delegation chain for the request in our namestore
1396  *
1397  * @param rh the resolver handle
1398  */
1399 static void
1400 resolve_delegation_ns(struct GNUNET_GNS_ResolverHandle *rh)
1401 {
1402   
1403   pop_tld(rh->name, rh->authority_name);
1404   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1405                                  &rh->authority,
1406                                  rh->authority_name,
1407                                  GNUNET_GNS_RECORD_PKEY,
1408                                  &process_delegation_result_ns,
1409                                  rh);
1410
1411 }
1412
1413 /**
1414  * Entry point for name resolution
1415  * Setup a new query and try to resolve
1416  *
1417  * @param request the request handle of the DNS request from a client
1418  * @param p the DNS query packet we received
1419  * @param q the DNS query we received parsed from p
1420  */
1421 static void
1422 start_resolution_for_dns(struct GNUNET_DNS_RequestHandle *request,
1423                           struct GNUNET_DNSPARSER_Packet *p,
1424                           struct GNUNET_DNSPARSER_Query *q)
1425 {
1426   struct GNUNET_GNS_ResolverHandle *rh;
1427   struct RecordLookupHandle* rlh;
1428   struct InterceptLookupHandle* ilh;
1429   
1430   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1431               "Starting resolution for %s (type=%d)!\n",
1432               q->name, q->type);
1433   
1434   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
1435   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1436   ilh = GNUNET_malloc(sizeof(struct InterceptLookupHandle));
1437   ilh->packet = p;
1438   ilh->query = q;
1439   ilh->request_handle = request;
1440   
1441   rh->authority = zone_hash;
1442
1443   rlh->record_type = q->type;
1444   rlh->name = q->name;
1445   rlh->proc = &reply_to_dns;
1446   rlh->proc_cls = ilh;
1447
1448   rh->proc_cls = rlh;
1449   
1450   rh->name = GNUNET_malloc(strlen(q->name)
1451                               - strlen(gnunet_tld) + 1);
1452   memset(rh->name, 0,
1453          strlen(q->name)-strlen(gnunet_tld) + 1);
1454   memcpy(rh->name, q->name,
1455          strlen(q->name)-strlen(gnunet_tld));
1456
1457   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1458   
1459   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1460   rh->authority_chain_head->prev = NULL;
1461   rh->authority_chain_head->next = NULL;
1462   rh->authority_chain_tail = rh->authority_chain_head;
1463   rh->authority_chain_head->zone = zone_hash;
1464
1465   /* Start resolution in our zone */
1466   rh->proc = &process_delegation_ns;
1467   resolve_delegation_ns(rh);
1468 }
1469
1470
1471
1472 /**
1473  * The DNS request handler
1474  * Called for every incoming DNS request.
1475  *
1476  * @param cls closure
1477  * @param rh request handle to user for reply
1478  * @param request_length number of bytes in request
1479  * @param request udp payload of the DNS request
1480  */
1481 static void
1482 handle_dns_request(void *cls,
1483                    struct GNUNET_DNS_RequestHandle *rh,
1484                    size_t request_length,
1485                    const char *request)
1486 {
1487   struct GNUNET_DNSPARSER_Packet *p;
1488   int i;
1489   char *tldoffset;
1490
1491   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n");
1492   p = GNUNET_DNSPARSER_parse (request, request_length);
1493   
1494   if (NULL == p)
1495   {
1496     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1497                 "Received malformed DNS packet, leaving it untouched\n");
1498     GNUNET_DNS_request_forward (rh);
1499     GNUNET_DNSPARSER_free_packet (p);
1500     return;
1501   }
1502   
1503   /**
1504    * Check tld and decide if we or
1505    * legacy dns is responsible
1506    *
1507    * FIXME now in theory there could be more than 1 query in the request
1508    * but if this is case we get into trouble:
1509    * either we query the GNS or the DNS. We cannot do both!
1510    * So I suggest to either only allow a single query per request or
1511    * only allow GNS or DNS requests.
1512    * The way it is implemented here now is buggy and will lead to erratic
1513    * behaviour (if multiple queries are present).
1514    */
1515   if (p->num_queries == 0)
1516   {
1517     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1518                 "No Queries in DNS packet... forwarding\n");
1519     GNUNET_DNS_request_forward (rh);
1520     GNUNET_DNSPARSER_free_packet(p);
1521     return;
1522   }
1523
1524   if (p->num_queries > 1)
1525   {
1526     /* Note: We could also look for .gnunet */
1527     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1528                 ">1 queriy in DNS packet... odd. We only process #1\n");
1529   }
1530
1531   
1532   /**
1533    * Check for .gnunet
1534    */
1535   tldoffset = p->queries[0].name + strlen(p->queries[0].name) - 1;
1536   
1537   for (i=0; i<strlen(p->queries[0].name); i++)
1538   {
1539     if (*(tldoffset-i) == '.')
1540       break;
1541   }
1542   
1543   if ((i==strlen(gnunet_tld)-1) && (0 == strcmp(tldoffset-i, gnunet_tld)))
1544   {
1545     start_resolution_for_dns(rh, p, p->queries);
1546   }
1547   else
1548   {
1549     /**
1550      * This request does not concern us. Forward to real DNS.
1551      */
1552     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1553                "Request for %s is forwarded to DNS\n", p->queries[0].name);
1554     GNUNET_DNS_request_forward (rh);
1555     GNUNET_DNSPARSER_free_packet (p);
1556   }
1557
1558 }
1559
1560 /**
1561  * Method called periodicattluy that triggers
1562  * iteration over root zone
1563  *
1564  * @param cls closure
1565  * @param tc task context
1566  */
1567 static void
1568 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1569 {
1570   GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
1571 }
1572
1573 /**
1574  * Continuation for DHT put
1575  *
1576  * @param cls closure
1577  * @param tc task context
1578  */
1579 static void
1580 record_dht_put(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1581 {
1582   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n");
1583 }
1584
1585 /* prototype */
1586 static void
1587 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1588
1589 /**
1590  * Function used to put all records successively into the DHT.
1591  *
1592  * @param cls the closure (NULL)
1593  * @param key the public key of the authority (ours)
1594  * @param expiration lifetime of the namestore entry
1595  * @param name the name of the records
1596  * @param rd_count the number of records in data
1597  * @param rd the record data
1598  * @param signature the signature for the record data
1599  */
1600 static void
1601 put_gns_record(void *cls,
1602                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1603                 struct GNUNET_TIME_Absolute expiration,
1604                 const char *name,
1605                 unsigned int rd_count,
1606                 const struct GNUNET_NAMESTORE_RecordData *rd,
1607                 const struct GNUNET_CRYPTO_RsaSignature *signature)
1608 {
1609   
1610   struct GNSNameRecordBlock *nrb;
1611   GNUNET_HashCode name_hash;
1612   GNUNET_HashCode xor_hash;
1613   struct GNUNET_CRYPTO_HashAsciiEncoded xor_hash_string;
1614   uint32_t rd_payload_length;
1615   char* nrb_data = NULL;
1616
1617   /* we're done */
1618   if (NULL == name)
1619   {
1620     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Zone iteration finished\n");
1621     GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1622     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start,
1623                                                    NULL);
1624     return;
1625   }
1626   
1627   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1628              "Putting records for %s into the DHT\n", name);
1629   
1630   rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1631   
1632   nrb = GNUNET_malloc(rd_payload_length + strlen(name) + 1 
1633                       + sizeof(struct GNSNameRecordBlock));
1634   
1635   if (signature != NULL)
1636     nrb->signature = *signature;
1637   
1638   nrb->public_key = *key;
1639
1640   nrb->rd_count = htonl(rd_count);
1641   
1642   memset(&nrb[1], 0, strlen(name) + 1);
1643   memcpy(&nrb[1], name, strlen(name));
1644
1645   nrb_data = (char*)&nrb[1];
1646   nrb_data += strlen(name) + 1;
1647
1648   rd_payload_length += sizeof(struct GNSNameRecordBlock) +
1649     strlen(name) + 1;
1650
1651   if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count,
1652                                                 rd,
1653                                                 rd_payload_length,
1654                                                 nrb_data))
1655   {
1656     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n");
1657     GNUNET_free(nrb);
1658     return;
1659     //FIXME what to do
1660   }
1661
1662
1663   /*
1664    * calculate DHT key: H(name) xor H(pubkey)
1665    */
1666   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1667   GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
1668   GNUNET_CRYPTO_hash_to_enc (&xor_hash, &xor_hash_string);
1669   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1670              "putting records for %s under key: %s with size %d\n",
1671              name, (char*)&xor_hash_string, rd_payload_length);
1672
1673   GNUNET_DHT_put (dht_handle, &xor_hash,
1674                   DHT_GNS_REPLICATION_LEVEL,
1675                   GNUNET_DHT_RO_NONE,
1676                   GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1677                   rd_payload_length,
1678                   (char*)nrb,
1679                   expiration,
1680                   DHT_OPERATION_TIMEOUT,
1681                   &record_dht_put,
1682                   NULL); //cls for cont
1683   
1684   num_public_records++;
1685
1686   /**
1687    * Reschedule periodic put
1688    */
1689   zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1690                                 &update_zone_dht_next,
1691                                 NULL);
1692
1693   GNUNET_free(nrb);
1694
1695 }
1696
1697 /**
1698  * Periodically iterate over our zone and store everything in dht
1699  *
1700  * @param cls NULL
1701  * @param tc task context
1702  */
1703 static void
1704 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1705 {
1706   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting DHT zone update!\n");
1707   if (0 == num_public_records)
1708   {
1709     dht_update_interval = GNUNET_TIME_relative_multiply(
1710                                                       GNUNET_TIME_UNIT_SECONDS,
1711                                                       1);
1712   }
1713   else
1714   {
1715     dht_update_interval = GNUNET_TIME_relative_multiply(
1716                                                       GNUNET_TIME_UNIT_SECONDS,
1717                                                      (3600/num_public_records));
1718   }
1719   num_public_records = 0; //start counting again
1720   namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
1721                                                           &zone_hash,
1722                                                           GNUNET_NAMESTORE_RF_AUTHORITY,
1723                                                           GNUNET_NAMESTORE_RF_PRIVATE,
1724                                                           &put_gns_record,
1725                                                           NULL);
1726 }
1727
1728 //Prototype
1729 static void send_shorten_response(const char* name,
1730                                   struct ClientShortenHandle *csh);
1731 static void
1732 process_shorten_pseu_lookup_ns(void *cls,
1733                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1734                  struct GNUNET_TIME_Absolute expire,
1735                  const char *name,
1736                  unsigned int rd_len,
1737                  const struct GNUNET_NAMESTORE_RecordData *rd,
1738                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1739 {
1740   struct GNUNET_GNS_ResolverHandle *rh = 
1741     (struct GNUNET_GNS_ResolverHandle *)cls;
1742   struct GNUNET_TIME_Relative remaining_time;
1743
1744   GNUNET_TIME_absolute_get_remaining (expire);
1745   rh->status = 0;
1746   
1747   if (name != NULL)
1748   {
1749     rh->status |= EXISTS;
1750   }
1751   
1752   if (remaining_time.rel_value == 0)
1753   {
1754     rh->status |= EXPIRED;
1755   }
1756
1757   rh->proc(rh->proc_cls, rh, rd_len, rd);
1758 }
1759
1760
1761 /**
1762  * Start DHT lookup for a PSEUdonym record in
1763  * rh->authority's zone
1764  *
1765  * @param rh the pending gns query
1766  */
1767 static void
1768 resolve_pseu_dht(struct GNUNET_GNS_ResolverHandle *rh)
1769 {
1770   uint32_t xquery;
1771   GNUNET_HashCode name_hash;
1772   GNUNET_HashCode lookup_key;
1773
1774   //Empty string
1775   GNUNET_CRYPTO_hash("",
1776                      1,
1777                      &name_hash);
1778
1779   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1780
1781   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1782                                                   &dht_lookup_timeout,
1783                                                   rh);
1784
1785   xquery = htonl(GNUNET_GNS_RECORD_PSEU);
1786   
1787   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1788                        DHT_OPERATION_TIMEOUT,
1789                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1790                        &lookup_key,
1791                        DHT_GNS_REPLICATION_LEVEL,
1792                        GNUNET_DHT_RO_NONE,
1793                        &xquery,
1794                        sizeof(xquery),
1795                        &process_delegation_result_dht,
1796                        rh);
1797
1798 }
1799
1800 //Prototype
1801 static void
1802 handle_shorten_pseu_ns_result(void* cls,
1803                               struct GNUNET_GNS_ResolverHandle *rh,
1804                               uint32_t rd_count,
1805                               const struct GNUNET_NAMESTORE_RecordData *rd);
1806
1807 static void
1808 handle_shorten_zone_to_name(void *cls,
1809                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1810                  struct GNUNET_TIME_Absolute expire,
1811                  const char *name,
1812                  unsigned int rd_len,
1813                  const struct GNUNET_NAMESTORE_RecordData *rd,
1814                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1815 {
1816   struct GNUNET_GNS_ResolverHandle *rh = 
1817     (struct GNUNET_GNS_ResolverHandle *)cls;
1818   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) rh->proc_cls;
1819
1820   char* result;
1821   size_t answer_len;
1822   
1823   /* we found a match in our own zone */
1824   if (rd_len != 0)
1825   {
1826     answer_len = strlen(rh->name) + strlen(name) + strlen(gnunet_tld) + 2;
1827     result = GNUNET_malloc(answer_len);
1828     memset(result, 0, answer_len);
1829     strcpy(result, rh->name);
1830     strcpy(result+strlen(rh->name), ".");
1831     strcpy(result+strlen(rh->name)+1, name);
1832     strcpy(result+strlen(rh->name)+strlen(name), gnunet_tld);
1833     
1834     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1835                "Sending shorten result %s\n", result);
1836
1837     send_shorten_response(result, csh);
1838     free_resolver_handle(rh);
1839     GNUNET_free(result);
1840   }
1841   else
1842   {
1843     /**
1844      * Nothing in our zone
1845      * check PSEU for this authority in namestore
1846      */
1847     rh->proc = &handle_shorten_pseu_ns_result;
1848     GNUNET_NAMESTORE_lookup_record(namestore_handle,
1849                                    &rh->authority_chain_head->zone,
1850                                    "",
1851                                    GNUNET_GNS_RECORD_PSEU,
1852                                    &process_shorten_pseu_lookup_ns,
1853                                    rh);
1854   }
1855 }
1856
1857 /**
1858  * Process result from namestore delegation lookup
1859  * for shorten operation
1860  *
1861  * @param cls the client shorten handle
1862  * @param rh the resolver handle
1863  * @param rd_count number of results (0)
1864  * @param rd data (NULL)
1865  */
1866 void
1867 handle_shorten_pseu_dht_result(void* cls,
1868                       struct GNUNET_GNS_ResolverHandle *rh,
1869                       uint32_t rd_len,
1870                       const struct GNUNET_NAMESTORE_RecordData *rd)
1871 {
1872   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1873   struct AuthorityChain *auth_chain;
1874   char* pseu;
1875   char* result;
1876   char* new_name;
1877   size_t answer_len;
1878   int i;
1879   
1880   /**
1881    * PSEU found
1882    */
1883   if (rd_len != 0)
1884   {
1885     for (i=0; i < rd_len; i++)
1886     {
1887       if (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)
1888       {
1889         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1890                    "Found PSEU %s\n", (char*) rd[i].data);
1891         break;
1892       }
1893     }
1894
1895     pseu = (char*) rd[i].data;
1896     answer_len = strlen(rh->name) + strlen(pseu) + strlen(gnunet_tld) + 2;
1897     result = GNUNET_malloc(answer_len);
1898     memset(result, 0, answer_len);
1899     strcpy(result, rh->name);
1900     strcpy(result+strlen(rh->name), ".");
1901     strcpy(result+strlen(rh->name)+1, pseu);
1902     strcpy(result+strlen(rh->name)+strlen(pseu), gnunet_tld);
1903     
1904     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1905                "Sending pseudonym shorten result %s\n", result);
1906     
1907     send_shorten_response(result, csh);
1908     free_resolver_handle(rh);
1909     GNUNET_free(result);
1910     return;
1911   }
1912   
1913   /**
1914    * No PSEU found.
1915    * continue with next authority
1916    * backtrack
1917    */
1918   auth_chain = rh->authority_chain_head;
1919
1920   if ((auth_chain->next->next == NULL) &&
1921       GNUNET_CRYPTO_hash_cmp(&auth_chain->next->zone, &zone_hash) == 0)
1922   {
1923     /**
1924      * Our zone is next
1925      */
1926     answer_len = strlen(rh->name) + strlen(auth_chain->name)
1927       + strlen(gnunet_tld) + 2;
1928
1929     result = GNUNET_malloc(answer_len);
1930     memset(result, 0, answer_len);
1931     strcpy(result, rh->name);
1932     strcpy(result+strlen(rh->name), ".");
1933     strcpy(result+strlen(rh->name)+1, auth_chain->name);
1934     strcpy(result+strlen(rh->name)+strlen(auth_chain->name)+1, gnunet_tld);
1935     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1936                "Sending non pseudonym shorten result %s\n", result);
1937     
1938     send_shorten_response(result, csh);
1939     free_resolver_handle(rh);
1940     GNUNET_free(result);
1941     return;
1942   }
1943
1944   /**
1945    * Continue with next authority
1946    */
1947   new_name = GNUNET_malloc(strlen(rh->name)+
1948                            strlen(auth_chain->name) + 2);
1949   memset(new_name, 0, strlen(rh->name)+
1950                       strlen(auth_chain->name) + 2);
1951   strcpy(new_name, rh->name);
1952   strcpy(new_name+strlen(rh->name)+1, ".");
1953   strcpy(new_name+strlen(rh->name)+2, auth_chain->name);
1954   GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1955                               rh->authority_chain_tail,
1956                               auth_chain);
1957   GNUNET_free(rh->name);
1958   rh->name = new_name;
1959   GNUNET_free(auth_chain->name);
1960   GNUNET_free(auth_chain);
1961   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1962                                  &zone_hash,
1963                                  &rh->authority_chain_head->zone,
1964                                  &handle_shorten_zone_to_name,
1965                                  rh);
1966
1967 }
1968
1969
1970
1971 /**
1972  * Process result from namestore PSEU lookup
1973  * for shorten operation
1974  * FIXME do we need to check for own zone here?
1975  *
1976  * @param cls the client shorten handle
1977  * @param rh the resolver handle
1978  * @param rd_count number of results (0 if none found)
1979  * @param rd data (NULL if none found)
1980  */
1981 static void
1982 handle_shorten_pseu_ns_result(void* cls,
1983                       struct GNUNET_GNS_ResolverHandle *rh,
1984                       uint32_t rd_len,
1985                       const struct GNUNET_NAMESTORE_RecordData *rd)
1986 {
1987   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1988   struct AuthorityChain *auth_chain;
1989   char* pseu;
1990   char* result;
1991   char* new_name;
1992   size_t answer_len;
1993   int i;
1994   
1995   /**
1996    * PSEU found
1997    */
1998   if (rd_len != 0)
1999   {
2000     for (i=0; i < rd_len; i++)
2001     {
2002       if (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)
2003       {
2004         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2005                    "Found PSEU %s\n", (char*) rd[i].data);
2006         break;
2007       }
2008     }
2009     
2010     pseu = (char*) rd[i].data;
2011     answer_len = strlen(rh->name) + strlen(pseu) + strlen(gnunet_tld) + 2;
2012     result = GNUNET_malloc(answer_len);
2013     memset(result, 0, answer_len);
2014     strcpy(result, rh->name);
2015     strcpy(result+strlen(rh->name), ".");
2016     strcpy(result+strlen(rh->name)+1, pseu);
2017     strcpy(result+strlen(rh->name)+strlen(pseu)+1, gnunet_tld);
2018     
2019     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2020                "Sending shorten result %s\n", result);
2021     
2022     send_shorten_response(result, csh);
2023     free_resolver_handle(rh);
2024     GNUNET_free(result);
2025     return;
2026   }
2027   
2028   /**
2029    * No PSEU found. Ask DHT if expired.
2030    * Else contunue with next authority
2031    */
2032   if (rh->status & (EXISTS | !EXPIRED))
2033   {
2034     /**
2035      * backtrack
2036      */
2037     auth_chain = rh->authority_chain_head;
2038     new_name = GNUNET_malloc(strlen(rh->name)+
2039                              strlen(auth_chain->name) + 2);
2040     memset(new_name, 0, strlen(rh->name)+
2041                         strlen(auth_chain->name) + 2);
2042     strcpy(new_name, rh->name);
2043     strcpy(new_name+strlen(rh->name)+1, ".");
2044     strcpy(new_name+strlen(rh->name)+2, auth_chain->name);
2045     
2046     GNUNET_free(rh->name);
2047     rh->name = new_name;
2048     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2049                                 rh->authority_chain_tail,
2050                                 auth_chain);
2051
2052     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2053                                    &zone_hash,
2054                                    &rh->authority_chain_head->zone,
2055                                    &handle_shorten_zone_to_name,
2056                                    rh);
2057     return;
2058   }
2059
2060   /**
2061    * Ask DHT
2062    */
2063   rh->authority = rh->authority_chain_head->zone;
2064   rh->proc = &handle_shorten_pseu_dht_result;
2065   resolve_pseu_dht(rh);
2066
2067 }
2068
2069
2070
2071 /**
2072  * Process result from namestore delegation lookup
2073  * for shorten operation
2074  *
2075  * @param cls the client shorten handle
2076  * @param rh the resolver handle
2077  * @param rd_count number of results (0)
2078  * @param rd data (NULL)
2079  */
2080 void
2081 handle_shorten_delegation_result(void* cls,
2082                       struct GNUNET_GNS_ResolverHandle *rh,
2083                       uint32_t rd_count,
2084                       const struct GNUNET_NAMESTORE_RecordData *rd)
2085 {
2086   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
2087   struct AuthorityChain *auth_chain;
2088   char* result;
2089   size_t answer_len;
2090   
2091   /**
2092    * At this point rh->name contains the part of the name
2093    * that we do not have a PKEY in our namestore to resolve.
2094    * The authority chain in the resolver handle is now
2095    * useful to backtrack if needed
2096    */
2097   
2098   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2099              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2100
2101   if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
2102                              &zone_hash) == 0)
2103   {
2104     /**
2105      * This is our zone append .gnunet unless name is empty
2106      * (it shouldn't be, usually FIXME what happens if we
2107      * shorten to our zone to a "" record??)
2108      **/
2109     
2110     answer_len = strlen(rh->name) + strlen(gnunet_tld) + 2;
2111     result = GNUNET_malloc(answer_len);
2112     memset(result, 0, answer_len);
2113     strcpy(result, rh->name);
2114     strcpy(result+strlen(rh->name), ".");
2115     strcpy(result+strlen(rh->name)+1, gnunet_tld);
2116
2117     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2118                "Our zone: Sending name as shorten result %s\n", rh->name);
2119     
2120     send_shorten_response(result, csh); //FIXME +.gnunet!
2121     free_resolver_handle(rh);
2122     GNUNET_free(result);
2123     return;
2124   }
2125   
2126   auth_chain = rh->authority_chain_head;
2127   /* backtrack authorities for pseu */
2128   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2129                                  &zone_hash, //ours
2130                                  &auth_chain->zone,
2131                                  &handle_shorten_zone_to_name,
2132                                  rh);
2133
2134 }
2135
2136 typedef void (*ShortenResponseProc) (void* cls, const char* name);
2137
2138 /**
2139  * Shorten a given name
2140  *
2141  * @param name the name to shorten
2142  * @param csh the shorten handle of the request
2143  */
2144 static void
2145 shorten_name(char* name, struct ClientShortenHandle* csh)
2146 {
2147
2148   struct GNUNET_GNS_ResolverHandle *rh;
2149   
2150   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2151               "Starting resolution for %s (type=%d)!\n",
2152               name, GNUNET_GNS_RECORD_PKEY);
2153   
2154   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
2155   rh->authority = zone_hash;
2156   
2157   rh->name = GNUNET_malloc(strlen(name)
2158                               - strlen(gnunet_tld) + 1);
2159   memset(rh->name, 0,
2160          strlen(name)-strlen(gnunet_tld) + 1);
2161   memcpy(rh->name, name,
2162          strlen(name)-strlen(gnunet_tld));
2163
2164   csh->name = GNUNET_malloc(strlen(name)
2165                             - strlen(gnunet_tld) + 1);
2166   memset(csh->name, 0,
2167          strlen(name)-strlen(gnunet_tld) + 1);
2168   memcpy(csh->name, name,
2169          strlen(name)-strlen(gnunet_tld));
2170
2171   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
2172
2173   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2174   rh->authority_chain_tail = rh->authority_chain_head;
2175   rh->authority_chain_head->zone = zone_hash;
2176   rh->proc = &handle_shorten_delegation_result;
2177   rh->proc_cls = (void*)csh;
2178
2179   /* Start delegation resolution in our namestore */
2180   resolve_delegation_ns(rh);
2181
2182 }
2183
2184 /**
2185  * Send shorten response back to client
2186  * 
2187  * @param name the shortened name result or NULL if cannot be shortened
2188  * @param csh the handle to the shorten request
2189  */
2190 static void
2191 send_shorten_response(const char* name, struct ClientShortenHandle *csh)
2192 {
2193   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
2194               "SHORTEN_RESULT", name);
2195   struct GNUNET_GNS_ClientShortenResultMessage *rmsg;
2196   
2197   if (name == NULL)
2198   {
2199     name = "";
2200   }
2201
2202   rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientShortenResultMessage)
2203                        + strlen(name) + 1);
2204   
2205   rmsg->id = csh->unique_id;
2206   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT);
2207   rmsg->header.size = 
2208     htons(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) +
2209           strlen(name) + 1);
2210
2211   strcpy((char*)&rmsg[1], name);
2212
2213   GNUNET_SERVER_notification_context_unicast (nc, csh->client,
2214                               (const struct GNUNET_MessageHeader *) rmsg,
2215                               GNUNET_NO);
2216   GNUNET_SERVER_receive_done (csh->client, GNUNET_OK);
2217   
2218   GNUNET_free(rmsg);
2219   GNUNET_free(csh->name);
2220   GNUNET_free(csh);
2221
2222 }
2223
2224 /**
2225  * Handle a shorten message from the api
2226  *
2227  * @param cls the closure
2228  * @param client the client
2229  * @param message the message
2230  */
2231 static void handle_shorten(void *cls,
2232                            struct GNUNET_SERVER_Client * client,
2233                            const struct GNUNET_MessageHeader * message)
2234 {
2235   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "SHORTEN");
2236
2237   size_t msg_size = 0;
2238   struct ClientShortenHandle *csh;
2239
2240   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientShortenMessage))
2241   {
2242     GNUNET_break_op (0);
2243     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2244     return;
2245   }
2246
2247   GNUNET_SERVER_notification_context_add (nc, client);
2248
2249   struct GNUNET_GNS_ClientShortenMessage *sh_msg =
2250     (struct GNUNET_GNS_ClientShortenMessage *) message;
2251   
2252   msg_size = ntohs(message->size);
2253
2254   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2255   {
2256     GNUNET_break_op (0);
2257     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2258     return;
2259   }
2260
2261   csh = GNUNET_malloc(sizeof(struct ClientShortenHandle));
2262   csh->client = client;
2263   csh->unique_id = sh_msg->id;
2264   
2265   shorten_name((char*)&sh_msg[1], csh);
2266
2267 }
2268
2269
2270 /**
2271  * Send get authority response back to client
2272  * 
2273  * @param name the shortened name result or NULL if cannot be shortened
2274  * @param cah the handle to the get authority request
2275  */
2276 static void
2277 send_get_auth_response(const char* name, struct ClientGetAuthHandle *cah)
2278 {
2279   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
2280               "GET_AUTH_RESULT", name);
2281   struct GNUNET_GNS_ClientGetAuthResultMessage *rmsg;
2282   
2283   if (name == NULL)
2284   {
2285     name = "";
2286   }
2287
2288   rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage)
2289                        + strlen(name) + 1);
2290   
2291   rmsg->id = cah->unique_id;
2292   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT);
2293   rmsg->header.size = 
2294     htons(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage) +
2295           strlen(name) + 1);
2296
2297   strcpy((char*)&rmsg[1], name);
2298
2299   GNUNET_SERVER_notification_context_unicast (nc, cah->client,
2300                               (const struct GNUNET_MessageHeader *) rmsg,
2301                               GNUNET_NO);
2302   GNUNET_SERVER_receive_done (cah->client, GNUNET_OK);
2303   
2304   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up handles...\n");
2305
2306   GNUNET_free(rmsg);
2307   GNUNET_free(cah->name);
2308   GNUNET_free(cah);
2309
2310   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done.\n");
2311
2312 }
2313
2314 /**
2315  * Process result from namestore delegation lookup
2316  * for get authority operation
2317  *
2318  * @param cls the client get auth handle
2319  * @param rh the resolver handle
2320  * @param rd_count number of results (0)
2321  * @param rd data (NULL)
2322  */
2323 void
2324 handle_get_auth_delegation_result(void* cls,
2325                       struct GNUNET_GNS_ResolverHandle *rh,
2326                       uint32_t rd_count,
2327                       const struct GNUNET_NAMESTORE_RecordData *rd)
2328 {
2329   struct ClientGetAuthHandle* cah = (struct ClientGetAuthHandle*) cls;
2330   struct AuthorityChain *auth_chain;
2331   char* result;
2332   size_t answer_len;
2333   
2334   /**
2335    * At this point rh->name contains the part of the name
2336    * that we do not have a PKEY in our namestore to resolve.
2337    * The authority chain in the resolver handle is now
2338    * useful to backtrack if needed
2339    */
2340   
2341   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2342              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2343
2344   if (is_canonical(rh->name))
2345   {
2346     /**
2347      * We successfully resolved the authority in the ns
2348      * FIXME for our purposes this is fine
2349      * but maybe we want to have an api that also looks
2350      * into the dht (i.e. option in message)
2351      **/
2352     if (strlen(rh->name) > strlen(cah->name))
2353     {
2354       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2355                  "Record name longer than original lookup name... odd!\n");
2356       //FIXME to sth here
2357     }
2358
2359
2360     answer_len = strlen(cah->name) - strlen(rh->name) + strlen(gnunet_tld) + 1;
2361     result = GNUNET_malloc(answer_len);
2362     memset(result, 0, answer_len);
2363     strcpy(result, cah->name + strlen(rh->name) + 1);
2364     strcpy(result+strlen(result), gnunet_tld);
2365
2366     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2367                "Got authority result %s\n", result);
2368     
2369     send_get_auth_response(result, cah);
2370     free_resolver_handle(rh);
2371     GNUNET_free(result);
2372     return;
2373   }
2374   
2375   auth_chain = rh->authority_chain_head;
2376   /* backtrack authorities for pseu */
2377   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2378                                  &zone_hash, //ours
2379                                  &auth_chain->zone,
2380                                  &handle_shorten_zone_to_name,
2381                                  rh);
2382
2383 }
2384
2385
2386 /**
2387  * Get authority for a given name
2388  *
2389  * @param name the name to shorten
2390  * @param csh the shorten handle of the request
2391  */
2392 static void
2393 get_authority(char* name, struct ClientGetAuthHandle* cah)
2394 {
2395
2396   struct GNUNET_GNS_ResolverHandle *rh;
2397   
2398   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2399               "Starting authority resolution for %s (type=%d)!\n",
2400               name, GNUNET_GNS_RECORD_PKEY);
2401   
2402   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
2403   rh->authority = zone_hash;
2404   
2405   rh->name = GNUNET_malloc(strlen(name)
2406                               - strlen(gnunet_tld) + 1);
2407   memset(rh->name, 0,
2408          strlen(name)-strlen(gnunet_tld) + 1);
2409   memcpy(rh->name, name,
2410          strlen(name)-strlen(gnunet_tld));
2411
2412   cah->name = GNUNET_malloc(strlen(name)
2413                             - strlen(gnunet_tld) + 1);
2414   memset(cah->name, 0,
2415          strlen(name)-strlen(gnunet_tld) + 1);
2416   memcpy(cah->name, name,
2417          strlen(name)-strlen(gnunet_tld));
2418
2419   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
2420
2421   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2422   rh->authority_chain_tail = rh->authority_chain_head;
2423   rh->authority_chain_head->zone = zone_hash;
2424   rh->proc = &handle_get_auth_delegation_result;
2425   rh->proc_cls = (void*)cah;
2426
2427   /* Start delegation resolution in our namestore */
2428   resolve_delegation_ns(rh);
2429
2430 }
2431
2432
2433 /**
2434  * Handle a get authority message from the api
2435  *
2436  * @param cls the closure
2437  * @param client the client
2438  * @param message the message
2439  */
2440 static void handle_get_authority(void *cls,
2441                            struct GNUNET_SERVER_Client * client,
2442                            const struct GNUNET_MessageHeader * message)
2443 {
2444   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "GET_AUTH");
2445
2446   size_t msg_size = 0;
2447   struct ClientGetAuthHandle *cah;
2448
2449   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientGetAuthMessage))
2450   {
2451     GNUNET_break_op (0);
2452     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2453     return;
2454   }
2455
2456   GNUNET_SERVER_notification_context_add (nc, client);
2457
2458   struct GNUNET_GNS_ClientGetAuthMessage *sh_msg =
2459     (struct GNUNET_GNS_ClientGetAuthMessage *) message;
2460   
2461   msg_size = ntohs(message->size);
2462
2463   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2464   {
2465     GNUNET_break_op (0);
2466     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2467     return;
2468   }
2469
2470   cah = GNUNET_malloc(sizeof(struct ClientGetAuthHandle));
2471   cah->client = client;
2472   cah->unique_id = sh_msg->id;
2473   
2474   get_authority((char*)&sh_msg[1], cah);
2475
2476 }
2477
2478
2479 /**
2480  * Reply to client with the result from our lookup.
2481  *
2482  * @param cls the closure (our client lookup handle)
2483  * @param rh the request handle of the lookup
2484  * @param rd_count the number of records
2485  * @param rd the record data
2486  */
2487 static void
2488 reply_to_client(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
2489                 uint32_t rd_count,
2490                 const struct GNUNET_NAMESTORE_RecordData *rd)
2491 {
2492   struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls;
2493   struct GNUNET_GNS_ClientLookupResultMessage *rmsg;
2494   size_t len;
2495   
2496   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %d results\n",
2497               "LOOKUP_RESULT", rd_count);
2498   
2499   len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
2500   rmsg = GNUNET_malloc(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
2501   
2502   rmsg->id = clh->unique_id;
2503   rmsg->rd_count = htonl(rd_count);
2504   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
2505   rmsg->header.size = 
2506     htons(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
2507
2508   GNUNET_NAMESTORE_records_serialize (rd_count, rd, len, (char*)&rmsg[1]);
2509   
2510   GNUNET_SERVER_notification_context_unicast (nc, clh->client,
2511                                 (const struct GNUNET_MessageHeader *) rmsg,
2512                                 GNUNET_NO);
2513   GNUNET_SERVER_receive_done (clh->client, GNUNET_OK);
2514   
2515   GNUNET_free(rh->proc_cls);
2516   free_resolver_handle(rh);
2517   GNUNET_free(rmsg);
2518   GNUNET_free(clh->name);
2519   GNUNET_free(clh);
2520
2521 }
2522
2523 /**
2524  * Lookup a given name
2525  *
2526  * @param name the name to looku[
2527  * @param clh the client lookup handle
2528  */
2529 static void
2530 lookup_name(char* name, struct ClientLookupHandle* clh)
2531 {
2532
2533   struct GNUNET_GNS_ResolverHandle *rh;
2534   struct RecordLookupHandle* rlh;
2535   
2536   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2537               "Starting resolution for %s (type=%d)!\n",
2538               name, clh->type);
2539   
2540   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
2541   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
2542   
2543   rh->authority = zone_hash;
2544
2545   rlh->record_type = clh->type;
2546   rlh->name = clh->name;
2547   rlh->proc = &reply_to_client;
2548   rlh->proc_cls = clh;
2549
2550   rh->proc_cls = rlh;
2551   
2552   rh->name = GNUNET_malloc(strlen(name)
2553                               - strlen(gnunet_tld) + 1);
2554   memset(rh->name, 0,
2555          strlen(name)-strlen(gnunet_tld) + 1);
2556   memcpy(rh->name, name,
2557          strlen(name)-strlen(gnunet_tld));
2558
2559   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
2560   
2561   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2562   rh->authority_chain_head->prev = NULL;
2563   rh->authority_chain_head->next = NULL;
2564   rh->authority_chain_tail = rh->authority_chain_head;
2565   rh->authority_chain_head->zone = zone_hash;
2566
2567   /* Start resolution in our zone */
2568   rh->proc = &process_delegation_ns;
2569   resolve_delegation_ns(rh);
2570 }
2571
2572
2573 /**
2574  * Handle lookup requests from client
2575  *
2576  * @param cls the closure
2577  * @param client the client
2578  * @param message the message
2579  */
2580 static void
2581 handle_lookup(void *cls,
2582               struct GNUNET_SERVER_Client * client,
2583               const struct GNUNET_MessageHeader * message)
2584 {
2585   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "LOOKUP");
2586
2587   size_t msg_size = 0;
2588   struct ClientLookupHandle *clh;
2589
2590   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientLookupMessage))
2591   {
2592     GNUNET_break_op (0);
2593     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2594     return;
2595   }
2596
2597   GNUNET_SERVER_notification_context_add (nc, client);
2598
2599   struct GNUNET_GNS_ClientLookupMessage *sh_msg =
2600     (struct GNUNET_GNS_ClientLookupMessage *) message;
2601   
2602   msg_size = ntohs(message->size);
2603
2604   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2605   {
2606     GNUNET_break_op (0);
2607     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2608     return;
2609   }
2610
2611   clh = GNUNET_malloc(sizeof(struct ClientLookupHandle));
2612   clh->client = client;
2613   clh->name = GNUNET_malloc(strlen((char*)&sh_msg[1]) + 1);
2614   strcpy(clh->name, (char*)&sh_msg[1]);
2615   clh->unique_id = sh_msg->id;
2616   clh->type = ntohl(sh_msg->type);
2617   
2618   lookup_name((char*)&sh_msg[1], clh);
2619 }
2620
2621
2622
2623 /**
2624  * Process GNS requests.
2625  *
2626  * @param cls closure)
2627  * @param server the initialized server
2628  * @param c configuration to use
2629  */
2630 static void
2631 run (void *cls, struct GNUNET_SERVER_Handle *server,
2632      const struct GNUNET_CONFIGURATION_Handle *c)
2633 {
2634   
2635   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n");
2636
2637   char* keyfile;
2638   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
2639
2640   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2641     {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0},
2642     {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0},
2643     {&handle_get_authority, NULL, GNUNET_MESSAGE_TYPE_GNS_GET_AUTH, 0}
2644   };
2645
2646   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "gns",
2647                                              "ZONEKEY", &keyfile))
2648   {
2649     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2650                 "No private key for root zone specified%s!\n", keyfile);
2651     GNUNET_SCHEDULER_shutdown(0);
2652     return;
2653   }
2654
2655   zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2656   GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
2657
2658   GNUNET_CRYPTO_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2659                      &zone_hash);
2660   GNUNET_free(keyfile);
2661   
2662
2663   dns_handle = NULL;
2664   if (GNUNET_YES ==
2665       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
2666                                             "HIJACK_DNS"))
2667   {
2668     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2669                "DNS hijacking enabled... connecting to service.\n");
2670     /**
2671      * Do gnunet dns init here
2672      */
2673     dns_handle = GNUNET_DNS_connect(c,
2674                                     GNUNET_DNS_FLAG_PRE_RESOLUTION,
2675                                     &handle_dns_request, /* rh */
2676                                     NULL); /* Closure */
2677     if (NULL == dns_handle)
2678     {
2679       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2680                "Failed to connect to the dnsservice!\n");
2681     }
2682   }
2683
2684   
2685
2686   /**
2687    * handle to our local namestore
2688    */
2689   namestore_handle = GNUNET_NAMESTORE_connect(c);
2690
2691   if (NULL == namestore_handle)
2692   {
2693     //FIXME do error handling;
2694     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2695                "Failed to connect to the namestore!\n");
2696     GNUNET_SCHEDULER_shutdown(0);
2697     return;
2698   }
2699   
2700   /**
2701    * handle to the dht
2702    */
2703   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
2704
2705   if (NULL == dht_handle)
2706   {
2707     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
2708   }
2709
2710   //put_some_records(); //FIXME for testing
2711   
2712   /**
2713    * Schedule periodic put
2714    * for our records
2715    * We have roughly an hour for all records;
2716    */
2717   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
2718                                                       1);
2719   //zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
2720
2721   GNUNET_SERVER_add_handlers (server, handlers);
2722   
2723   //FIXME
2724   //GNUNET_SERVER_disconnect_notify (server,
2725   //                                 &client_disconnect_notification,
2726   //                                 NULL);
2727
2728   nc = GNUNET_SERVER_notification_context_create (server, 1);
2729
2730   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
2731                                 NULL);
2732 }
2733
2734
2735 /**
2736  * The main function for the GNS service.
2737  *
2738  * @param argc number of arguments from the command line
2739  * @param argv command line arguments
2740  * @return 0 ok, 1 on error
2741  */
2742 int
2743 main (int argc, char *const *argv)
2744 {
2745   int ret;
2746
2747   ret =
2748       (GNUNET_OK ==
2749        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
2750                            NULL)) ? 0 : 1;
2751   return ret;
2752 }
2753
2754 /* end of gnunet-service-gns.c */