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