-new resolver (#3), for shortening
[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 /* Ignore for now not used anyway and probably never will */
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
53
54 struct AuthorityChain
55 {
56   struct AuthorityChain *prev;
57
58   struct AuthorityChain *next;
59
60   GNUNET_HashCode zone;
61
62   /* was the ns entry fresh */
63   int fresh;
64 };
65
66 struct GNUNET_GNS_ResolverHandle;
67
68 typedef void (*ResolutionResultProcessor) (void *cls,
69                                   struct GNUNET_GNS_ResolverHandle *rh,
70                                   uint32_t rd_count,
71                                   const struct GNUNET_NAMESTORE_RecordData *rd);
72
73 enum ResolutionStatus
74 {
75   EXISTS = 1,
76   EXPIRED = 2
77 };
78
79 /**
80  * Handle to a currenty pending resolution
81  */
82 struct GNUNET_GNS_ResolverHandle
83 {
84   /* The name to resolve */
85   char *name;
86
87   /* the request handle to reply to */
88   struct GNUNET_DNS_RequestHandle *request_handle;
89   
90   /* the dns parser packet received */
91   struct GNUNET_DNSPARSER_Packet *packet;
92   
93   /* the query parsed from the packet */
94
95   struct GNUNET_DNSPARSER_Query *query;
96   
97   /* has this query been answered? how many matches */
98   int answered;
99
100   /* the authoritative zone to query */
101   GNUNET_HashCode authority;
102
103   /* the name of the authoritative zone to query */
104   char *authority_name;
105
106   /**
107    * we have an authority in namestore that
108    * may be able to resolve
109    */
110   int authority_found;
111
112   /* a handle for dht lookups. should be NULL if no lookups are in progress */
113   struct GNUNET_DHT_GetHandle *get_handle;
114
115   /* timeout task for dht lookups */
116   GNUNET_SCHEDULER_TaskIdentifier dht_timeout_task;
117
118   ResolutionResultProcessor proc;
119
120   void* proc_cls;
121
122   struct AuthorityChain *authority_chain_head;
123   struct AuthorityChain *authority_chain_tail;
124
125   enum ResolutionStatus status;
126
127 };
128
129 struct ClientShortenHandle
130 {
131   struct GNUNET_SERVER_Client *client;
132   uint64_t unique_id;
133   GNUNET_HashCode key;
134   char* name;
135   uint32_t offset;
136 };
137
138 /**
139  * Our handle to the DNS handler library
140  */
141 struct GNUNET_DNS_Handle *dns_handle;
142
143 /**
144  * Our handle to the DHT
145  */
146 struct GNUNET_DHT_Handle *dht_handle;
147
148 /**
149  * Our zone's private key
150  */
151 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
152
153 /**
154  * Our handle to the namestore service
155  * FIXME maybe need a second handle for iteration
156  */
157 struct GNUNET_NAMESTORE_Handle *namestore_handle;
158
159 /**
160  * Handle to iterate over our authoritative zone in namestore
161  */
162 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
163
164 /**
165  * The configuration the GNS service is running with
166  */
167 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
168
169 /**
170  * Our notification context.
171  */
172 static struct GNUNET_SERVER_NotificationContext *nc;
173
174 /**
175  * Our zone hash
176  */
177 GNUNET_HashCode zone_hash;
178
179 /**
180  * Our tld. Maybe get from config file
181  */
182 const char* gnunet_tld = ".gnunet";
183
184 /**
185  * Useful for zone update for DHT put
186  */
187 static int num_public_records =  3600;
188 struct GNUNET_TIME_Relative dht_update_interval;
189 GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
190
191 //static void resolve_name(struct GNUNET_GNS_ResolverHandle *rh);
192
193 /**
194  * Reply to client with the result from our lookup.
195  *
196  * @param rh the request handle of the lookup
197  * @param rd_count the number of records to return
198  * @param rd the record data
199  */
200 static void
201 reply_to_dns(void* cls, struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count,
202              const struct GNUNET_NAMESTORE_RecordData *rd)
203 {
204   int i;
205   size_t len;
206   int ret;
207   char *buf;
208   struct GNUNET_DNSPARSER_Packet *packet = rh->packet;
209   struct GNUNET_DNSPARSER_Record answer_records[rh->answered];
210   struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)];
211   packet->answers = answer_records;
212   packet->additional_records = additional_records;
213   
214   /**
215    * Put records in the DNS packet and modify it
216    * to a response
217    */
218   len = sizeof(struct GNUNET_DNSPARSER_Record*);
219   for (i=0; i < rd_count; i++)
220   {
221     
222     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
223                "Adding type %d to DNS response\n", rd[i].record_type);
224     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", rh->name);
225     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "QName: %s\n", rh->query->name);
226     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count);
227     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size);
228     
229     if (rd[i].record_type == rh->query->type)
230     {
231       answer_records[i].name = rh->query->name;
232       answer_records[i].type = rd[i].record_type;
233       answer_records[i].data.raw.data_len = rd[i].data_size;
234       answer_records[i].data.raw.data = (char*)rd[i].data;
235       answer_records[i].expiration_time = rd[i].expiration;
236       answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
237     }
238     else
239     {
240       additional_records[i].name = rh->query->name;
241       additional_records[i].type = rd[i].record_type;
242       additional_records[i].data.raw.data_len = rd[i].data_size;
243       additional_records[i].data.raw.data = (char*)rd[i].data;
244       additional_records[i].expiration_time = rd[i].expiration;
245       additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
246     }
247   }
248   
249   packet->num_answers = rh->answered;
250   packet->num_additional_records = rd_count-(rh->answered);
251   
252   if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash))
253     packet->flags.authoritative_answer = 1;
254   else
255     packet->flags.authoritative_answer = 0;
256
257   if (rd == NULL)
258     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
259   else
260     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
261   
262   packet->flags.query_or_response = 1;
263
264   
265   /**
266    * Reply to DNS
267    */
268   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
269              "Building DNS response\n");
270   ret = GNUNET_DNSPARSER_pack (packet,
271                                1024, /* FIXME magic from dns redirector */
272                                &buf,
273                                &len);
274   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
275              "Built DNS response! (ret=%d,len=%d)\n", ret, len);
276   if (ret == GNUNET_OK)
277   {
278     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
279                "Answering DNS request\n");
280     GNUNET_DNS_request_answer(rh->request_handle,
281                               len,
282                               buf);
283     //GNUNET_free(answer);
284     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n");
285   }
286   else
287   {
288     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
289                "Error building DNS response! (ret=%d)", ret);
290   }
291
292   GNUNET_free(rh->name);
293   GNUNET_free(rh);
294 }
295
296
297 /**
298  * Task run during shutdown.
299  *
300  * @param cls unused
301  * @param tc unused
302  */
303 static void
304 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
305 {
306   /* Kill zone task for it may make the scheduler hang */
307   if (zone_update_taskid)
308     GNUNET_SCHEDULER_cancel(zone_update_taskid);
309
310   GNUNET_DNS_disconnect(dns_handle);
311   GNUNET_NAMESTORE_disconnect(namestore_handle, 1);
312   GNUNET_DHT_disconnect(dht_handle);
313 }
314
315 /**
316  * Callback when record data is put into namestore
317  *
318  * @param cls the closure
319  * @param success GNUNET_OK on success
320  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
321  */
322 void
323 on_namestore_record_put_result(void *cls,
324                                int32_t success,
325                                const char *emsg)
326 {
327   if (GNUNET_NO == success)
328   {
329     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
330     return;
331   }
332   else if (GNUNET_YES == success)
333   {
334     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
335                "records successfully put in namestore\n");
336     return;
337   }
338
339   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
340              "Error putting records into namestore: %s\n", emsg);
341 }
342
343 /**
344  * Handle timeout for DHT requests
345  *
346  * @param cls the request handle as closure
347  * @param tc the task context
348  */
349 static void
350 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
351 {
352   struct GNUNET_GNS_ResolverHandle *rh = cls;
353
354   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
355              "dht lookup for query %s (type=%d) timed out.\n",
356              rh->name, rh->query->type);
357
358   GNUNET_DHT_get_stop (rh->get_handle);
359   rh->proc(rh->proc_cls, rh, 0, NULL);
360 }
361
362
363
364 /**
365  * Function called when we get a result from the dht
366  * for our query
367  *
368  * @param cls the request handle
369  * @param exp lifetime
370  * @param key the key the record was stored under
371  * @param get_path get path
372  * @param get_path_length get path length
373  * @param put_path put path
374  * @param put_path_length put path length
375  * @param type the block type
376  * @param size the size of the record
377  * @param data the record data
378  */
379 static void
380 process_record_dht_result(void* cls,
381                  struct GNUNET_TIME_Absolute exp,
382                  const GNUNET_HashCode * key,
383                  const struct GNUNET_PeerIdentity *get_path,
384                  unsigned int get_path_length,
385                  const struct GNUNET_PeerIdentity *put_path,
386                  unsigned int put_path_length,
387                  enum GNUNET_BLOCK_Type type,
388                  size_t size, const void *data)
389 {
390   struct GNUNET_GNS_ResolverHandle *rh;
391   struct GNSNameRecordBlock *nrb;
392   uint32_t num_records;
393   char* name = NULL;
394   char* rd_data = (char*)data;
395   int i;
396   int rd_size;
397   
398   GNUNET_HashCode zone, name_hash;
399   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
400   
401   if (data == NULL)
402     return;
403
404   //FIXME maybe check expiration here, check block type
405   
406   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
407   nrb = (struct GNSNameRecordBlock*)data;
408   
409   /* stop lookup and timeout task */
410   GNUNET_DHT_get_stop (rh->get_handle);
411   GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
412   
413   rh->get_handle = NULL;
414   name = (char*)&nrb[1];
415   num_records = ntohl(nrb->rd_count);
416   {
417     struct GNUNET_NAMESTORE_RecordData rd[num_records];
418
419     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
420     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
421   
422     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
423                                                                rd_data,
424                                                                num_records,
425                                                                rd))
426     {
427       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
428       return;
429     }
430
431     for (i=0; i<num_records; i++)
432     {
433       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
434                "Got name: %s (wanted %s)\n", name, rh->name);
435       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
436                "Got type: %d (wanted %d)\n",
437                rd[i].record_type, rh->query->type);
438       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
439                "Got data length: %d\n", rd[i].data_size);
440       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
441                "Got flag %d\n", rd[i].flags);
442     
443      if ((strcmp(name, rh->name) == 0) &&
444          (rd[i].record_type == rh->query->type))
445       {
446         rh->answered++;
447       }
448
449     }
450
451     GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
452     GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
453   
454     /**
455      * FIXME check pubkey against existing key in namestore?
456      * https://gnunet.org/bugs/view.php?id=2179
457      */
458
459     /* Save to namestore */
460     GNUNET_NAMESTORE_record_put (namestore_handle,
461                                  &nrb->public_key,
462                                  name,
463                                  exp,
464                                  num_records,
465                                  rd,
466                                  &nrb->signature,
467                                  &on_namestore_record_put_result, //cont
468                                  NULL); //cls
469   
470     if (rh->answered)
471       rh->proc(rh->proc_cls, rh, num_records, rd);
472     else
473       rh->proc(rh->proc_cls, rh, 0, NULL);
474   }
475
476 }
477
478
479 /**
480  * Start DHT lookup for a (name -> query->record_type) record in
481  * query->authority's zone
482  *
483  * @param rh the pending gns query context
484  * @param name the name to query record
485  */
486 static void
487 resolve_record_from_dht(struct GNUNET_GNS_ResolverHandle *rh)
488 {
489   uint32_t xquery;
490   GNUNET_HashCode name_hash;
491   GNUNET_HashCode lookup_key;
492   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
493
494   GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash);
495   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
496   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
497   
498   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
499              "starting dht lookup for %s with key: %s\n",
500              rh->name, (char*)&lookup_key_string);
501
502   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
503                                                       &dht_lookup_timeout, rh);
504
505   xquery = htonl(rh->query->type);
506   rh->get_handle = GNUNET_DHT_get_start(dht_handle, 
507                        DHT_OPERATION_TIMEOUT,
508                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
509                        &lookup_key,
510                        DHT_GNS_REPLICATION_LEVEL,
511                        GNUNET_DHT_RO_NONE,
512                        &xquery, 
513                        sizeof(xquery),
514                        &process_record_dht_result,
515                        rh);
516
517 }
518
519
520 /**
521  * Namestore calls this function if we have record for this name.
522  * (or with rd_count=0 to indicate no matches)
523  *
524  * @param cls the pending query
525  * @param key the key of the zone we did the lookup
526  * @param expiration expiration date of the namestore entry
527  * @param name the name for which we need an authority
528  * @param rd_count the number of records with 'name'
529  * @param rd the record data
530  * @param signature the signature of the authority for the record data
531  */
532 static void
533 process_record_lookup_ns(void* cls,
534                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
535                   struct GNUNET_TIME_Absolute expiration,
536                   const char *name, unsigned int rd_count,
537                   const struct GNUNET_NAMESTORE_RecordData *rd,
538                   const struct GNUNET_CRYPTO_RsaSignature *signature)
539 {
540   struct GNUNET_GNS_ResolverHandle *rh;
541   struct GNUNET_TIME_Relative remaining_time;
542   GNUNET_HashCode zone;
543
544   rh = (struct GNUNET_GNS_ResolverHandle *) cls;
545   GNUNET_CRYPTO_hash(key,
546                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
547                      &zone);
548   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
549
550   rh->status = 0;
551   
552   if (name != NULL)
553   {
554     rh->status |= EXISTS;
555   }
556   
557   if (remaining_time.rel_value == 0)
558   {
559     rh->status |= EXPIRED;
560   }
561   
562   if (rd_count == 0)
563   {
564     /**
565      * Lookup terminated and no results
566      */
567     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
568                "Namestore lookup for %s terminated without results\n", name);
569     
570     
571
572     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
573                "Record %s unknown in namestore\n",
574                rh->name);
575     /**
576      * Our zone and no result? Cannot resolve TT
577      */
578     rh->proc(rh->proc_cls, rh, 0, NULL);
579     return;
580
581   }
582   else
583   {
584     
585     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
586                "Processing additional result %s from namestore\n", name);
587     int i;
588     for (i=0; i<rd_count;i++)
589     {
590       
591       if (rd[i].record_type != rh->query->type)
592         continue;
593       
594       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
595           == 0)
596       {
597         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n");
598         continue;
599       }
600       
601       rh->answered++;
602       
603     }
604     
605     /**
606      * no answers found
607      */
608     if (rh->answered == 0)
609     {
610       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
611                  "No answers found. This is odd!\n");
612       rh->proc(rh->proc_cls, rh, 0, NULL);
613       return;
614     }
615     
616     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
617                rh->answered);
618
619     rh->proc(rh->proc_cls, rh, rd_count, rd);
620   }
621 }
622
623 /**
624  * The final phase of resolution.
625  * This is a name that is canonical and we do not have a delegation.
626  *
627  * @param rh the pending lookup
628  */
629 static void
630 resolve_record_from_ns(struct GNUNET_GNS_ResolverHandle *rh)
631 {
632   
633   /**
634    * Try to resolve this record in our namestore.
635    * The name to resolve is now in rh->authority_name
636    * since we tried to resolve it to an authority
637    * and failed.
638    **/
639   GNUNET_NAMESTORE_lookup_record(namestore_handle,
640                                  &rh->authority,
641                                  rh->name,
642                                  rh->query->type,
643                                  &process_record_lookup_ns,
644                                  rh);
645
646 }
647
648
649 /**
650  * Handle timeout for DHT requests
651  *
652  * @param cls the request handle as closure
653  * @param tc the task context
654  */
655 static void
656 dht_authority_lookup_timeout(void *cls,
657                              const struct GNUNET_SCHEDULER_TaskContext *tc)
658 {
659   struct GNUNET_GNS_ResolverHandle *rh = cls;
660
661   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
662              "dht lookup for query %s (type=%d) timed out.\n",
663              rh->name, rh->query->type);
664
665   GNUNET_DHT_get_stop (rh->get_handle);
666   if (strcmp(rh->name, "") == 0)
667   {
668     /*
669      * promote authority back to name and try to resolve record
670      */
671     strcpy(rh->name, rh->authority_name);
672   }
673   rh->proc(rh->proc_cls, rh, 0, NULL);
674 }
675
676 // Prototype
677 static void resolve_delegation_from_dht(struct GNUNET_GNS_ResolverHandle *rh);
678
679 /**
680  * Function called when we get a result from the dht
681  * for our query
682  *
683  * @param cls the request handle
684  * @param exp lifetime
685  * @param key the key the record was stored under
686  * @param get_path get path
687  * @param get_path_length get path length
688  * @param put_path put path
689  * @param put_path_length put path length
690  * @param type the block type
691  * @param size the size of the record
692  * @param data the record data
693  */
694 static void
695 process_authority_dht_result(void* cls,
696                  struct GNUNET_TIME_Absolute exp,
697                  const GNUNET_HashCode * key,
698                  const struct GNUNET_PeerIdentity *get_path,
699                  unsigned int get_path_length,
700                  const struct GNUNET_PeerIdentity *put_path,
701                  unsigned int put_path_length,
702                  enum GNUNET_BLOCK_Type type,
703                  size_t size, const void *data)
704 {
705   struct GNUNET_GNS_ResolverHandle *rh;
706   struct GNSNameRecordBlock *nrb;
707   uint32_t num_records;
708   char* name = NULL;
709   char* rd_data = (char*) data;
710   int i;
711   int rd_size;
712   GNUNET_HashCode zone, name_hash;
713   
714   if (data == NULL)
715     return;
716   
717   //FIXME check expiration?
718   
719   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
720   nrb = (struct GNSNameRecordBlock*)data;
721   
722   /* stop dht lookup and timeout task */
723   GNUNET_DHT_get_stop (rh->get_handle);
724   GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
725
726   rh->get_handle = NULL;
727   num_records = ntohl(nrb->rd_count);
728   name = (char*)&nrb[1];
729   {
730     struct GNUNET_NAMESTORE_RecordData rd[num_records];
731     
732     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
733     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
734   
735     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
736                                                                rd_data,
737                                                                num_records,
738                                                                rd))
739     {
740       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
741       return;
742     }
743
744     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
745                "Got name: %s (wanted %s)\n", name, rh->authority_name);
746     for (i=0; i<num_records; i++)
747     {
748     
749       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
750                 "Got name: %s (wanted %s)\n", name, rh->authority_name);
751       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
752                  "Got type: %d (wanted %d)\n",
753                  rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
754       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
755                  "Got data length: %d\n", rd[i].data_size);
756       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
757                  "Got flag %d\n", rd[i].flags);
758
759       if ((strcmp(name, rh->authority_name) == 0) &&
760           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
761       {
762         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
763         rh->answered = 1;
764         memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
765         struct AuthorityChain *auth =
766           GNUNET_malloc(sizeof(struct AuthorityChain));
767         auth->zone = rh->authority;
768         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
769                                      rh->authority_chain_tail,
770                                      auth);
771       }
772
773     }
774
775
776     GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
777     GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
778
779     /* Save to namestore */
780     if (0 != GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone))
781     {
782       GNUNET_NAMESTORE_record_put (namestore_handle,
783                                  &nrb->public_key,
784                                  name,
785                                  exp,
786                                  num_records,
787                                  rd,
788                                  &nrb->signature,
789                                  &on_namestore_record_put_result, //cont
790                                  NULL); //cls
791     }
792   }
793   
794   if (rh->answered)
795   {
796     rh->answered = 0;
797     /* delegate */
798     if (strcmp(rh->name, "") == 0)
799       rh->proc(rh->proc_cls, rh, 0, NULL);
800     else
801       resolve_delegation_from_dht(rh);
802     return;
803   }
804
805   /* resolve never get here, should timeout??*/
806   
807   
808   if (strcmp(rh->name, "") == 0)
809   {
810     /* promote authority back to name */
811     strcpy(rh->name, rh->authority_name);
812   }
813   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No authority in records\n");
814   rh->proc(rh->proc_cls, rh, 0, NULL);
815 }
816
817
818 /**
819  * DHT lookup result for record.
820  *
821  * @param cls the closure
822  * @param rh resolver handle
823  * @param rd_count number of results (always 0)
824  * @param rd record data (always NULL)
825  */
826 static void
827 process_record_result_dht(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
828                        unsigned int rd_count,
829                        const struct GNUNET_NAMESTORE_RecordData *rd)
830 {
831   if (rd_count == 0)
832   {
833     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
834                "No records for %s found in DHT. Aborting\n",
835                rh->name);
836     /* give up, cannot resolve */
837     reply_to_dns(NULL, rh, 0, NULL);
838     return;
839   }
840
841   /* results found yay */
842   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
843              "Record resolved from namestore!");
844   reply_to_dns(NULL, rh, rd_count, rd);
845
846 }
847
848
849 /**
850  * Namestore lookup result for record.
851  *
852  * @param cls the closure
853  * @param rh resolver handle
854  * @param rd_count number of results (always 0)
855  * @param rd record data (always NULL)
856  */
857 static void
858 process_record_result_ns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
859                        unsigned int rd_count,
860                        const struct GNUNET_NAMESTORE_RecordData *rd)
861 {
862   if (rd_count == 0)
863   {
864     /* ns entry expired. try dht */
865     if (rh->status & (EXPIRED | !EXISTS))
866     {
867       rh->proc = &process_record_result_dht;
868       resolve_record_from_dht(rh);
869       return;
870     }
871     /* give up, cannot resolve */
872     reply_to_dns(NULL, rh, 0, NULL);
873     return;
874   }
875
876   /* results found yay */
877   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
878              "Record resolved from namestore!");
879   reply_to_dns(NULL, rh, rd_count, rd);
880
881 }
882
883
884 /**
885  * Determine if this name is canonical.
886  * i.e.
887  * a.b.gnunet  = not canonical
888  * a           = canonical
889  *
890  * @param name the name to test
891  * @return 1 if canonical
892  */
893 static int
894 is_canonical(char* name)
895 {
896   uint32_t len = strlen(name);
897   int i;
898
899   for (i=0; i<len; i++)
900   {
901     if (*(name+i) == '.')
902       return 0;
903   }
904   return 1;
905 }
906
907 /**
908  * Move one level up in the domain hierarchy and return the
909  * passed top level domain.
910  *
911  * @param name the domain
912  * @param dest the destination where the tld will be put
913  */
914 void
915 pop_tld(char* name, char* dest)
916 {
917   uint32_t len;
918
919   if (is_canonical(name))
920   {
921     strcpy(dest, name);
922     strcpy(name, "");
923     return;
924   }
925
926   for (len = strlen(name); len > 0; len--)
927   {
928     if (*(name+len) == '.')
929       break;
930   }
931   
932   //Was canonical?
933   if (len == 0)
934     return;
935
936   name[len] = '\0';
937
938   strcpy(dest, (name+len+1));
939 }
940
941 /**
942  * Namestore resolution for delegation finished. Processing result.
943  *
944  * @param cls the closure
945  * @param rh resolver handle
946  * @param rd_count number of results (always 0)
947  * @param rd record data (always NULL)
948  */
949 static void
950 process_dht_delegation_dns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
951                           unsigned int rd_count,
952                           const struct GNUNET_NAMESTORE_RecordData *rd)
953 {
954   if (strcmp(rh->name, "") == 0)
955   {
956     /* We resolved full name for delegation. resolving record */
957     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
958       "Resolved full name for delegation via DHT. resolving record '' in ns\n");
959     rh->proc = &process_record_result_ns;
960     resolve_record_from_ns(rh);
961     return;
962   }
963
964   /**
965    * we still have some left
966    **/
967   if (is_canonical(rh->name))
968   {
969     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
970                "Resolving canonical record %s in ns\n", rh->name);
971     rh->proc = &process_record_result_ns;
972     resolve_record_from_ns(rh);
973     return;
974   }
975   /* give up, cannot resolve */
976   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
977              "Cannot fully resolve delegation for %s via DHT!\n",
978              rh->name);
979   reply_to_dns(NULL, rh, 0, NULL);
980 }
981
982
983 /**
984  * Start DHT lookup for a name -> PKEY (compare NS) record in
985  * rh->authority's zone
986  *
987  * @param rh the pending gns query
988  * @param name the name of the PKEY record
989  */
990 static void
991 resolve_delegation_from_dht(struct GNUNET_GNS_ResolverHandle *rh)
992 {
993   uint32_t xquery;
994   GNUNET_HashCode name_hash;
995   GNUNET_HashCode lookup_key;
996
997   GNUNET_CRYPTO_hash(rh->authority_name,
998                      strlen(rh->authority_name),
999                      &name_hash);
1000   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1001
1002   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1003                                                   &dht_authority_lookup_timeout,
1004                                                        rh);
1005
1006   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1007   //FIXME how long to wait for results?
1008   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1009                        DHT_OPERATION_TIMEOUT,
1010                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1011                        &lookup_key,
1012                        DHT_GNS_REPLICATION_LEVEL,
1013                        GNUNET_DHT_RO_NONE,
1014                        NULL,
1015                        sizeof(xquery),
1016                        &process_authority_dht_result,
1017                        rh);
1018
1019 }
1020
1021
1022 /**
1023  * Namestore resolution for delegation finished. Processing result.
1024  *
1025  * @param cls the closure
1026  * @param rh resolver handle
1027  * @param rd_count number of results (always 0)
1028  * @param rd record data (always NULL)
1029  */
1030 static void
1031 process_ns_delegation_dns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1032                           unsigned int rd_count,
1033                           const struct GNUNET_NAMESTORE_RecordData *rd)
1034 {
1035   if (strcmp(rh->name, "") == 0)
1036   {
1037     /* We resolved full name for delegation. resolving record */
1038     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1039                "Resolved full name for delegation. resolving record ''\n");
1040     rh->proc = &process_record_result_ns;
1041     resolve_record_from_ns(rh);
1042     return;
1043   }
1044
1045   /**
1046    * we still have some left
1047    * check if ns entry is fresh
1048    **/
1049   if (rh->status & (EXISTS | !EXPIRED))
1050   {
1051     if (is_canonical(rh->name))
1052     {
1053       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1054                  "Resolving canonical record %s\n", rh->name);
1055       rh->proc = &process_record_result_ns;
1056       resolve_record_from_ns(rh);
1057     }
1058     else
1059     {
1060       /* give up, cannot resolve */
1061       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1062                  "Cannot fully resolve delegation for %s!\n",
1063                  rh->name);
1064       reply_to_dns(NULL, rh, 0, NULL);
1065     }
1066     return;
1067   }
1068   
1069   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1070              "Trying to resolve delegation for %s via DHT\n",
1071              rh->name);
1072   rh->proc = &process_dht_delegation_dns;
1073   resolve_delegation_from_dht(rh);
1074 }
1075
1076 //Prototype
1077 static void resolve_delegation_from_ns(struct GNUNET_GNS_ResolverHandle *rh);
1078
1079 /**
1080  * This is a callback function that should give us only PKEY
1081  * records. Used to query the namestore for the authority (PKEY)
1082  * for 'name'
1083  *
1084  * @param cls the pending query
1085  * @param key the key of the zone we did the lookup
1086  * @param expiration expiration date of the record data set in the namestore
1087  * @param name the name for which we need an authority
1088  * @param rd_count the number of records with 'name'
1089  * @param rd the record data
1090  * @param signature the signature of the authority for the record data
1091  */
1092 static void
1093 process_authority_lookup_ns(void* cls,
1094                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1095                    struct GNUNET_TIME_Absolute expiration,
1096                    const char *name,
1097                    unsigned int rd_count,
1098                    const struct GNUNET_NAMESTORE_RecordData *rd,
1099                    const struct GNUNET_CRYPTO_RsaSignature *signature)
1100 {
1101   struct GNUNET_GNS_ResolverHandle *rh;
1102   struct GNUNET_TIME_Relative remaining_time;
1103   GNUNET_HashCode zone;
1104   char* new_name;
1105   
1106   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1107              rd_count);
1108
1109   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
1110   GNUNET_CRYPTO_hash(key,
1111                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1112                      &zone);
1113   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1114   
1115   rh->status = 0;
1116   
1117   if (name != NULL)
1118   {
1119     rh->status |= EXISTS;
1120   }
1121   
1122   if (remaining_time.rel_value == 0)
1123   {
1124     rh->status |= EXPIRED;
1125   }
1126   
1127   /**
1128    * No authority found in namestore.
1129    */
1130   if (rd_count == 0)
1131   {
1132     /**
1133      * We did not find an authority in the namestore
1134      */
1135     
1136     /**
1137      * No PKEY in zone.
1138      * Promote this authority back to a name maybe it is
1139      * our record.
1140      */
1141     if (strcmp(rh->name, "") == 0)
1142     {
1143       /* simply promote back */
1144       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1145                  "Promoting %s back to name\n", rh->authority_name);
1146       strcpy(rh->name, rh->authority_name);
1147     }
1148     else
1149     {
1150       /* add back to existing name */
1151       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1152                  "Adding %s back to %s\n",
1153                  rh->authority_name, rh->name);
1154       new_name = GNUNET_malloc(strlen(rh->name)
1155                                + strlen(rh->authority_name) + 2);
1156       memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1157       strcpy(new_name, rh->name);
1158       strcpy(new_name+strlen(new_name)+1, ".");
1159       strcpy(new_name+strlen(new_name)+2, rh->authority_name);
1160       GNUNET_free(rh->name);
1161       rh->name = new_name;
1162     }
1163     rh->proc(rh->proc_cls, rh, 0, NULL);
1164     return;
1165   }
1166
1167   //Note only 1 pkey should have been returned.. anything else would be strange
1168   /**
1169    * We found an authority that may be able to help us
1170    * move on with query
1171    */
1172   int i;
1173   for (i=0; i<rd_count;i++)
1174   {
1175   
1176     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1177       continue;
1178     
1179     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1180          == 0)
1181     {
1182       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1183       if (remaining_time.rel_value == 0)
1184       {
1185         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1186                    "This dht entry is expired.\n");
1187         rh->authority_chain_head->fresh = 0;
1188         rh->proc(rh->proc_cls, rh, 0, NULL);
1189         return;
1190       }
1191
1192       continue;
1193     }
1194
1195     /**
1196      * Resolve rest of query with new authority
1197      */
1198     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1199     memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1200     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1201     auth->zone = rh->authority;
1202     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1203                                  rh->authority_chain_tail,
1204                                  auth);
1205
1206     if (strcmp(rh->name, "") == 0)
1207       rh->proc(rh->proc_cls, rh, 0, NULL);
1208     else
1209       resolve_delegation_from_ns(rh);
1210     return;
1211   }
1212     
1213   /**
1214    * no answers found
1215    */
1216   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1217              "Authority lookup successful but no PKEY... never get here\n");
1218   rh->proc(rh->proc_cls, rh, 0, NULL);
1219 }
1220
1221
1222
1223 /**
1224  * The first phase of resolution.
1225  * First check if the name is canonical.
1226  * If it is then try to resolve directly.
1227  * If not then we first have to resolve the authoritative entities.
1228  *
1229  * @param rh the pending lookup
1230  */
1231 /*static void
1232 resolve_name(struct GNUNET_GNS_ResolverHandle *rh)
1233 {
1234   
1235   pop_tld(rh->name, rh->authority_name);
1236   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1237                                  &rh->authority,
1238                                  rh->authority_name,
1239                                  GNUNET_GNS_RECORD_PKEY,
1240                                  &process_authority_lookup,
1241                                  rh);
1242
1243 }*/
1244
1245
1246
1247 static void
1248 resolve_delegation_from_ns(struct GNUNET_GNS_ResolverHandle *rh)
1249 {
1250   
1251   /**
1252    * Try to resolve this name to a delegation.
1253    **/
1254   pop_tld(rh->name, rh->authority_name);
1255   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1256                                  &rh->authority,
1257                                  rh->authority_name,
1258                                  GNUNET_GNS_RECORD_PKEY,
1259                                  &process_authority_lookup_ns,
1260                                  rh);
1261
1262 }
1263
1264 /**
1265  * Entry point for name resolution
1266  * Setup a new query and try to resolve
1267  *
1268  * @param request the request handle of the DNS request from a client
1269  * @param p the DNS query packet we received
1270  * @param q the DNS query we received parsed from p
1271  */
1272 static void
1273 start_resolution_from_dns(struct GNUNET_DNS_RequestHandle *request,
1274                           struct GNUNET_DNSPARSER_Packet *p,
1275                           struct GNUNET_DNSPARSER_Query *q)
1276 {
1277   struct GNUNET_GNS_ResolverHandle *rh;
1278   
1279   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1280               "Starting resolution for %s (type=%d)!\n",
1281               q->name, q->type);
1282   
1283   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
1284   rh->packet = p;
1285   rh->query = q;
1286   rh->authority = zone_hash;
1287   
1288   
1289   rh->name = GNUNET_malloc(strlen(q->name)
1290                               - strlen(gnunet_tld) + 1);
1291   memset(rh->name, 0,
1292          strlen(q->name)-strlen(gnunet_tld) + 1);
1293   memcpy(rh->name, q->name,
1294          strlen(q->name)-strlen(gnunet_tld));
1295
1296   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1297
1298   rh->request_handle = request;
1299
1300   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1301   rh->authority_chain_tail = rh->authority_chain_head;
1302   rh->authority_chain_head->zone = zone_hash;
1303
1304   /* Start resolution in our zone */
1305   rh->proc = &process_ns_delegation_dns;
1306   resolve_delegation_from_ns(rh);
1307   //resolve_name(rh);
1308 }
1309
1310 /**
1311  * The DNS request handler
1312  * Called for every incoming DNS request.
1313  *
1314  * @param cls closure
1315  * @param rh request handle to user for reply
1316  * @param request_length number of bytes in request
1317  * @param request udp payload of the DNS request
1318  */
1319 static void
1320 handle_dns_request(void *cls,
1321                    struct GNUNET_DNS_RequestHandle *rh,
1322                    size_t request_length,
1323                    const char *request)
1324 {
1325   struct GNUNET_DNSPARSER_Packet *p;
1326   char *tldoffset;
1327
1328   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n");
1329   p = GNUNET_DNSPARSER_parse (request, request_length);
1330   
1331   if (NULL == p)
1332   {
1333     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1334                 "Received malformed DNS packet, leaving it untouched\n");
1335     GNUNET_DNS_request_forward (rh);
1336     return;
1337   }
1338   
1339   /**
1340    * Check tld and decide if we or
1341    * legacy dns is responsible
1342    *
1343    * FIXME now in theory there could be more than 1 query in the request
1344    * but if this is case we get into trouble:
1345    * either we query the GNS or the DNS. We cannot do both!
1346    * So I suggest to either only allow a single query per request or
1347    * only allow GNS or DNS requests.
1348    * The way it is implemented here now is buggy and will lead to erratic
1349    * behaviour (if multiple queries are present).
1350    */
1351   if (p->num_queries == 0)
1352   {
1353     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1354                 "No Queries in DNS packet... forwarding\n");
1355     GNUNET_DNS_request_forward (rh);
1356   }
1357
1358   if (p->num_queries > 1)
1359   {
1360     /* Note: We could also look for .gnunet */
1361     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1362                 ">1 queriy in DNS packet... odd. We only process #1\n");
1363   }
1364
1365   
1366   /**
1367    * Check for .gnunet
1368    */
1369   tldoffset = p->queries[0].name + strlen(p->queries[0].name);
1370
1371   while ((*tldoffset) != '.')
1372     tldoffset--;
1373   
1374   if (0 == strcmp(tldoffset, gnunet_tld))
1375   {
1376     start_resolution_from_dns(rh, p, p->queries);
1377   }
1378   else
1379   {
1380     /**
1381      * This request does not concern us. Forward to real DNS.
1382      */
1383     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1384                "Request for %s is forwarded to DNS\n", p->queries[0].name);
1385     GNUNET_DNS_request_forward (rh);
1386   }
1387
1388 }
1389
1390 /**
1391  * Method called periodicattluy that triggers
1392  * iteration over root zone
1393  *
1394  * @param cls closure
1395  * @param tc task context
1396  */
1397 static void
1398 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1399 {
1400   GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
1401 }
1402
1403 /**
1404  * Continuation for DHT put
1405  *
1406  * @param cls closure
1407  * @param tc task context
1408  */
1409 static void
1410 record_dht_put(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1411 {
1412   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n");
1413 }
1414
1415 /* prototype */
1416 static void
1417 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1418
1419 /**
1420  * Function used to put all records successively into the DHT.
1421  *
1422  * @param cls the closure (NULL)
1423  * @param key the public key of the authority (ours)
1424  * @param expiration lifetime of the namestore entry
1425  * @param name the name of the records
1426  * @param rd_count the number of records in data
1427  * @param rd the record data
1428  * @param signature the signature for the record data
1429  */
1430 static void
1431 put_gns_record(void *cls,
1432                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1433                 struct GNUNET_TIME_Absolute expiration,
1434                 const char *name,
1435                 unsigned int rd_count,
1436                 const struct GNUNET_NAMESTORE_RecordData *rd,
1437                 const struct GNUNET_CRYPTO_RsaSignature *signature)
1438 {
1439   
1440   struct GNSNameRecordBlock *nrb;
1441   GNUNET_HashCode name_hash;
1442   GNUNET_HashCode xor_hash;
1443   struct GNUNET_CRYPTO_HashAsciiEncoded xor_hash_string;
1444   uint32_t rd_payload_length;
1445   char* nrb_data = NULL;
1446
1447   /* we're done */
1448   if (NULL == name)
1449   {
1450     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Zone iteration finished\n");
1451     GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1452     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start,
1453                                                    NULL);
1454     return;
1455   }
1456   
1457   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1458              "Putting records for %s into the DHT\n", name);
1459   
1460   rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1461   
1462   nrb = GNUNET_malloc(rd_payload_length + strlen(name) + 1 
1463                       + sizeof(struct GNSNameRecordBlock));
1464   
1465   if (signature != NULL)
1466     nrb->signature = *signature;
1467   
1468   nrb->public_key = *key;
1469
1470   nrb->rd_count = htonl(rd_count);
1471   
1472   memset(&nrb[1], 0, strlen(name) + 1);
1473   memcpy(&nrb[1], name, strlen(name));
1474
1475   nrb_data = (char*)&nrb[1];
1476   nrb_data += strlen(name) + 1;
1477
1478   rd_payload_length += sizeof(struct GNSNameRecordBlock) +
1479     strlen(name) + 1;
1480
1481   if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count,
1482                                                 rd,
1483                                                 rd_payload_length,
1484                                                 nrb_data))
1485   {
1486     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n");
1487     return;
1488     //FIXME what to do
1489   }
1490
1491
1492   /*
1493    * calculate DHT key: H(name) xor H(pubkey)
1494    */
1495   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1496   GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
1497   GNUNET_CRYPTO_hash_to_enc (&xor_hash, &xor_hash_string);
1498   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1499              "putting records for %s under key: %s with size %d\n",
1500              name, (char*)&xor_hash_string, rd_payload_length);
1501
1502   GNUNET_DHT_put (dht_handle, &xor_hash,
1503                   DHT_GNS_REPLICATION_LEVEL,
1504                   GNUNET_DHT_RO_NONE,
1505                   GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1506                   rd_payload_length,
1507                   (char*)nrb,
1508                   expiration,
1509                   DHT_OPERATION_TIMEOUT,
1510                   &record_dht_put,
1511                   NULL); //cls for cont
1512   
1513   num_public_records++;
1514
1515   /**
1516    * Reschedule periodic put
1517    */
1518   zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1519                                 &update_zone_dht_next,
1520                                 NULL);
1521
1522 }
1523
1524 /**
1525  * Periodically iterate over our zone and store everything in dht
1526  *
1527  * @param cls NULL
1528  * @param tc task context
1529  */
1530 static void
1531 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1532 {
1533   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting DHT zone update!\n");
1534   if (0 == num_public_records)
1535   {
1536     dht_update_interval = GNUNET_TIME_relative_multiply(
1537                                                       GNUNET_TIME_UNIT_SECONDS,
1538                                                       1);
1539   }
1540   else
1541   {
1542     dht_update_interval = GNUNET_TIME_relative_multiply(
1543                                                       GNUNET_TIME_UNIT_SECONDS,
1544                                                      (3600/num_public_records));
1545   }
1546   num_public_records = 0; //start counting again
1547   namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
1548                                                           &zone_hash,
1549                                                           GNUNET_NAMESTORE_RF_AUTHORITY,
1550                                                           GNUNET_NAMESTORE_RF_PRIVATE,
1551                                                           &put_gns_record,
1552                                                           NULL);
1553 }
1554
1555 //Prototype
1556 static void send_shorten_response(const char* name,
1557                                   struct ClientShortenHandle *csh);
1558
1559 void
1560 handle_local_zone_to_name(void *cls,
1561                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1562                  struct GNUNET_TIME_Absolute expire,
1563                  const char *name,
1564                  unsigned int rd_len,
1565                  const struct GNUNET_NAMESTORE_RecordData *rd,
1566                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1567 {
1568   struct GNUNET_GNS_ResolverHandle *rh = 
1569     (struct GNUNET_GNS_ResolverHandle *)cls;
1570   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) rh->proc_cls;
1571   /* we found a match in our own zone */
1572   if (rd_len != 0)
1573   {
1574     send_shorten_response(name, csh);
1575     //FIXME free, add .gnunet
1576   }
1577   else
1578   {
1579     
1580   }
1581 }
1582
1583 void
1584 handle_shorten_result(void* cls,
1585                       struct GNUNET_GNS_ResolverHandle *rh,
1586                       uint32_t rd_count,
1587                       const struct GNUNET_NAMESTORE_RecordData *rd)
1588 {
1589   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1590   struct AuthorityChain *auth_chain;
1591   
1592   /**
1593    * Couldn't completely resolve
1594    * Search authority chain
1595    */
1596   
1597   if (rd_count == 0)
1598   {
1599     /* Nothing we can do. That name is unknown */
1600     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1601                "PKEY for %s unknown!\n", csh->name);
1602     if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1603                                &zone_hash) == 0)
1604     {
1605       /* either we can shorten completely or we don't know this name */
1606       if (rh->authority_chain_head->next == NULL)
1607         send_shorten_response('\0', csh);
1608       else
1609         send_shorten_response(rh->name, csh); //FIXME +.gnunet!
1610       //FIXME free
1611       return;
1612     }
1613     csh->offset++;
1614     auth_chain = rh->authority_chain_head;
1615     /* backtrack authorities for pseu */
1616     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1617                                    &zone_hash, //ours
1618                                    &auth_chain->zone,
1619                                    &handle_local_zone_to_name,
1620                                    rh);
1621   }
1622   else /* we can use the result directly */
1623   {
1624     /* First check local namestore for name */
1625     /* Then try dht/namestore for PSEU */
1626   }
1627
1628
1629 }
1630
1631 typedef void (*ShortenResponseProc) (void* cls, const char* name);
1632
1633 /**
1634  * Shorten a given name
1635  *
1636  * @param name the name to shorten
1637  * @param proc the processor to call when finished
1638  * @praram cls the closure to the processor
1639  */
1640 static void
1641 shorten_name(char* name, struct ClientShortenHandle* csh)
1642 {
1643
1644   struct GNUNET_GNS_ResolverHandle *rh;
1645   
1646   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1647               "Starting resolution for %s (type=%d)!\n",
1648               name, GNUNET_GNS_RECORD_PKEY);
1649   
1650   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
1651   rh->authority = zone_hash;
1652   
1653   rh->name = GNUNET_malloc(strlen(name)
1654                               - strlen(gnunet_tld) + 1);
1655   memset(rh->name, 0,
1656          strlen(name)-strlen(gnunet_tld) + 1);
1657   memcpy(rh->name, name,
1658          strlen(name)-strlen(gnunet_tld));
1659
1660   csh->name = GNUNET_malloc(strlen(name)
1661                             - strlen(gnunet_tld) + 1);
1662   memset(rh->name, 0,
1663          strlen(name)-strlen(gnunet_tld) + 1);
1664   memcpy(rh->name, name,
1665          strlen(name)-strlen(gnunet_tld));
1666
1667   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1668
1669   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1670   rh->authority_chain_tail = rh->authority_chain_head;
1671   rh->authority_chain_head->zone = zone_hash;
1672   rh->proc = handle_shorten_result;
1673   rh->proc_cls = (void*)csh;
1674
1675   /* Start resolution in our zone */
1676   //resolve_name(rh);
1677
1678 }
1679
1680 /**
1681  * Send shorten response back to client
1682  * FIXME this is without .gnunet!
1683  * 
1684  * @param cls the client handle in closure
1685  * @param name the shortened name result or NULL if cannot be shortened
1686  */
1687 static void
1688 send_shorten_response(const char* name, struct ClientShortenHandle *csh)
1689 {
1690   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n",
1691               "SHORTEN_RESULT");
1692   struct GNUNET_GNS_ClientShortenResultMessage *rmsg;
1693   
1694   if (name == NULL)
1695   {
1696     name = '\0';
1697   }
1698
1699   rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientShortenResultMessage *)
1700                        + strlen(name));
1701   
1702   rmsg->unique_id = csh->unique_id;
1703   rmsg->key = csh->key;
1704   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT);
1705   rmsg->header.size = 
1706     htons(sizeof(struct GNUNET_GNS_ClientShortenResultMessage *) +
1707           strlen(name));
1708
1709   strcpy((char*)&rmsg[1], name);
1710
1711   GNUNET_SERVER_notification_context_unicast (nc, csh->client,
1712                               (const struct GNUNET_MessageHeader *) &rmsg,
1713                               GNUNET_NO);
1714
1715   GNUNET_SERVER_receive_done (csh->client, GNUNET_OK);
1716   
1717   GNUNET_free(csh);
1718   GNUNET_free(rmsg);
1719
1720 }
1721
1722 /**
1723  * Handle a shorten message from the api
1724  *
1725  * @param cls the closure
1726  * @param client the client
1727  * @param message the message
1728  */
1729 static void handle_shorten(void *cls,
1730                            struct GNUNET_SERVER_Client * client,
1731                            const struct GNUNET_MessageHeader * message)
1732 {
1733   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "SHORTEN");
1734
1735   size_t msg_size = 0;
1736   struct ClientShortenHandle *csh;
1737
1738   if (ntohs (message->size) != sizeof (struct GNUNET_GNS_ClientShortenMessage))
1739   {
1740     GNUNET_break_op (0);
1741     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1742     return;
1743   }
1744
1745   struct GNUNET_GNS_ClientShortenMessage *sh_msg =
1746     (struct GNUNET_GNS_ClientShortenMessage *) message;
1747   
1748   msg_size = ntohs(message->size);
1749
1750   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
1751   {
1752     GNUNET_break_op (0);
1753     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1754     return;
1755   }
1756
1757   csh = GNUNET_malloc(sizeof(struct ClientShortenHandle));
1758   csh->client = client;
1759   csh->unique_id = sh_msg->unique_id;
1760   csh->key = sh_msg->key;
1761   
1762   //Offset in original name
1763   csh->offset = 0;
1764   
1765
1766   shorten_name((char*)&sh_msg[1], csh);
1767
1768 }
1769
1770 /**
1771  * TODO
1772  */
1773 static void
1774 handle_lookup(void *cls,
1775               struct GNUNET_SERVER_Client * client,
1776               const struct GNUNET_MessageHeader * message)
1777 {
1778 }
1779
1780 /**
1781  * Process GNS requests.
1782  *
1783  * @param cls closure)
1784  * @param server the initialized server
1785  * @param c configuration to use
1786  */
1787 static void
1788 run (void *cls, struct GNUNET_SERVER_Handle *server,
1789      const struct GNUNET_CONFIGURATION_Handle *c)
1790 {
1791   
1792   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n");
1793
1794   char* keyfile;
1795   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
1796
1797   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1798     {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0},
1799     {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0}
1800   };
1801
1802   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "gns",
1803                                              "ZONEKEY", &keyfile))
1804   {
1805     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1806                 "No private key for root zone specified%s!\n", keyfile);
1807     GNUNET_SCHEDULER_shutdown(0);
1808     return;
1809   }
1810
1811   zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1812   GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
1813
1814   GNUNET_CRYPTO_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1815                      &zone_hash);
1816   
1817
1818   if (GNUNET_YES ==
1819       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
1820                                             "HIJACK_DNS"))
1821   {
1822     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1823                "DNS hijacking enabled... connecting to service.\n");
1824     /**
1825      * Do gnunet dns init here
1826      */
1827     dns_handle = GNUNET_DNS_connect(c,
1828                                     GNUNET_DNS_FLAG_PRE_RESOLUTION,
1829                                     &handle_dns_request, /* rh */
1830                                     NULL); /* Closure */
1831     if (NULL == dns_handle)
1832     {
1833       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1834                "Failed to connect to the dnsservice!\n");
1835     }
1836   }
1837
1838   
1839
1840   /**
1841    * handle to our local namestore
1842    */
1843   namestore_handle = GNUNET_NAMESTORE_connect(c);
1844
1845   if (NULL == namestore_handle)
1846   {
1847     //FIXME do error handling;
1848     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1849                "Failed to connect to the namestore!\n");
1850     GNUNET_SCHEDULER_shutdown(0);
1851     return;
1852   }
1853   
1854   /**
1855    * handle to the dht
1856    */
1857   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
1858
1859   if (NULL == dht_handle)
1860   {
1861     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
1862   }
1863
1864   //put_some_records(); //FIXME for testing
1865   
1866   /**
1867    * Schedule periodic put
1868    * for our records
1869    * We have roughly an hour for all records;
1870    */
1871   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
1872                                                       1);
1873   //zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
1874
1875   GNUNET_SERVER_add_handlers (server, handlers);
1876   
1877   //FIXME
1878   //GNUNET_SERVER_disconnect_notify (server,
1879   //                                 &client_disconnect_notification,
1880   //                                 NULL);
1881
1882   nc = GNUNET_SERVER_notification_context_create (server, 1);
1883
1884   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1885                                 NULL);
1886 }
1887
1888
1889 /**
1890  * The main function for the GNS service.
1891  *
1892  * @param argc number of arguments from the command line
1893  * @param argv command line arguments
1894  * @return 0 ok, 1 on error
1895  */
1896 int
1897 main (int argc, char *const *argv)
1898 {
1899   int ret;
1900
1901   ret =
1902       (GNUNET_OK ==
1903        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
1904                            NULL)) ? 0 : 1;
1905   return ret;
1906 }
1907
1908 /* end of gnunet-service-gns.c */