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