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