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