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