-fix stub, add better task handling to dht update zone task
[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 "gns.h"
40
41 /* Ignore for now not used anyway and probably never will */
42 #define GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP 23
43 #define GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT 24
44
45 /**
46  * A result list for namestore queries
47  */
48 struct GNUNET_GNS_ResolverHandle
49 {
50   /* The name to resolve */
51   char *name;
52
53   /* the request handle to reply to */
54   struct GNUNET_DNS_RequestHandle *request_handle;
55   
56   /* the dns parser packet received */
57   struct GNUNET_DNSPARSER_Packet *packet;
58   
59   /* the query parsed from the packet */
60
61   struct GNUNET_DNSPARSER_Query *query;
62   
63   /* has this query been answered? how many matches */
64   int answered;
65
66   /* the authoritative zone to query */
67   GNUNET_HashCode authority;
68
69   /**
70    * we have an authority in namestore that
71    * may be able to resolve
72    */
73   int authority_found;
74
75   /* a handle for dht lookups. should be NULL if no lookups are in progress */
76   struct GNUNET_DHT_GetHandle *get_handle;
77
78 };
79
80
81 /**
82  * Our handle to the DNS handler library
83  */
84 struct GNUNET_DNS_Handle *dns_handle;
85
86 /**
87  * Our handle to the DHT
88  */
89 struct GNUNET_DHT_Handle *dht_handle;
90
91 /**
92  * Our zone's private key
93  */
94 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
95
96 /**
97  * Our handle to the namestore service
98  * FIXME maybe need a second handle for iteration
99  */
100 struct GNUNET_NAMESTORE_Handle *namestore_handle;
101
102 /**
103  * Handle to iterate over our authoritative zone in namestore
104  */
105 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
106
107 /**
108  * The configuration the GNS service is running with
109  */
110 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
111
112 /**
113  * Our notification context.
114  */
115 static struct GNUNET_SERVER_NotificationContext *nc;
116
117 /**
118  * Our zone hash
119  */
120 GNUNET_HashCode zone_hash;
121
122 /**
123  * Our tld. Maybe get from config file
124  */
125 const char* gnunet_tld = ".gnunet";
126
127 /**
128  * Useful for zone update for DHT put
129  */
130 static int num_public_records =  3600;
131 struct GNUNET_TIME_Relative dht_update_interval;
132 GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
133
134 //Prototypes
135 void reply_to_dns(struct GNUNET_GNS_ResolverHandle *answer, uint32_t rd_count,
136                   const struct GNUNET_NAMESTORE_RecordData *rd);
137 void resolve_name(struct GNUNET_GNS_ResolverHandle *rh);
138
139 /**
140  * Task run during shutdown.
141  *
142  * @param cls unused
143  * @param tc unused
144  */
145 static void
146 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
147 {
148   //Kill zone task for it may make the scheduler hang
149   GNUNET_SCHEDULER_cancel(zone_update_taskid);
150   GNUNET_DNS_disconnect(dns_handle);
151   GNUNET_NAMESTORE_disconnect(namestore_handle, 0);
152   GNUNET_DHT_disconnect(dht_handle);
153 }
154
155 /**
156  * Callback when record data is put into namestore
157  *
158  * @param cls the closure
159  * @param success GNUNET_OK on success
160  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
161  */
162 void
163 on_namestore_record_put_result(void *cls,
164                                int32_t success,
165                                const char *emsg)
166 {
167   if (GNUNET_NO == success)
168   {
169     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
170     return;
171   }
172   else if (GNUNET_YES == success)
173   {
174     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
175                "records successfully put in namestore\n");
176     return;
177   }
178
179   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
180              "Error putting records into namestore: %s\n", emsg);
181 }
182
183 /**
184  * Function called when we get a result from the dht
185  * for our query
186  *
187  * @param cls the request handle
188  * @param exp lifetime
189  * @param key the key the record was stored under
190  * @param get_path get path
191  * @param get_path_length get path length
192  * @param put_path put path
193  * @param put_path_length put path length
194  * @param type the block type
195  * @param size the size of the record
196  * @param data the record data
197  */
198 void
199 process_authority_dht_result(void* cls,
200                  struct GNUNET_TIME_Absolute exp,
201                  const GNUNET_HashCode * key,
202                  const struct GNUNET_PeerIdentity *get_path,
203                  unsigned int get_path_length,
204                  const struct GNUNET_PeerIdentity *put_path,
205                  unsigned int put_path_length,
206                  enum GNUNET_BLOCK_Type type,
207                  size_t size, const void *data)
208 {
209   struct GNUNET_GNS_ResolverHandle *rh;
210   uint32_t num_records;
211   uint16_t namelen;
212   char* name = NULL;
213   struct GNUNET_CRYPTO_RsaSignature *signature;
214   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
215   int i;
216   char* pos;
217   GNUNET_HashCode zone, name_hash;
218
219   if (data == NULL)
220     return;
221   
222   //FIXME check expiration?
223   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
224   pos = (char*)data;
225   
226   GNUNET_DHT_get_stop (rh->get_handle);
227   rh->get_handle = NULL;
228   num_records = ntohl(*pos);
229   struct GNUNET_NAMESTORE_RecordData rd[num_records];
230
231   pos += sizeof(uint32_t);
232   
233   for (i=0; i<num_records; i++)
234   {
235     namelen = ntohs(*pos);
236     pos += sizeof(uint16_t);
237     
238     //name must be 0 terminated
239     name = pos;
240     pos += namelen;
241   
242     rd[i].record_type = ntohl(*pos);
243     pos += sizeof(uint32_t);
244   
245     rd[i].data_size = ntohl(*pos);
246     pos += sizeof(uint32_t);
247   
248     rd[i].data = pos;
249     pos += rd[i].data_size;
250
251     rd[i].expiration = GNUNET_TIME_absolute_ntoh(
252                               *((struct GNUNET_TIME_AbsoluteNBO*)pos));
253     pos += sizeof(struct GNUNET_TIME_AbsoluteNBO);
254
255     rd[i].flags = ntohs(*pos);
256     pos += sizeof(uint16_t);
257     
258     if (strcmp(name, rh->query->name) && rd[i].record_type == rh->query->type)
259     {
260       rh->answered = 1;
261     }
262
263   }
264
265   if ((((char*)data)-pos) < 
266       (sizeof(struct GNUNET_CRYPTO_RsaSignature) +
267        sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
268   {
269     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
270             "Cannot parse signature/key in DHT response. Corrupted or Missing");
271     return;
272   }
273
274   signature = (struct GNUNET_CRYPTO_RsaSignature*)pos;
275   pos += sizeof(struct GNUNET_CRYPTO_RsaSignature);
276   
277   public_key = (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded*)pos;
278   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
279   GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
280
281   //Save to namestore
282   GNUNET_NAMESTORE_record_put (namestore_handle,
283                                public_key,
284                                name,
285                                exp,
286                                num_records,
287                                rd,
288                                signature,
289                                &on_namestore_record_put_result, //cont
290                                NULL); //cls
291   
292   if (rh->answered)
293   {
294     rh->answered = 0;
295     rh->authority = zone;
296     resolve_name(rh);
297     return;
298   }
299   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "No authority in records\n");
300   reply_to_dns(rh, 0, NULL);
301 }
302
303 /**
304  * Start DHT lookup for a name -> PKEY (compare NS) record in
305  * query->authority's zone
306  *
307  * @param rh the pending gns query
308  * @param name the name of the PKEY record
309  */
310 void
311 resolve_authority_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name)
312 {
313   enum GNUNET_GNS_RecordType rtype = GNUNET_GNS_RECORD_PKEY;
314   struct GNUNET_TIME_Relative timeout;
315   GNUNET_HashCode name_hash;
316   GNUNET_HashCode lookup_key;
317
318   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
319   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
320
321   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
322   
323   //FIXME how long to wait for results?
324   rh->get_handle = GNUNET_DHT_get_start(dht_handle, timeout,
325                        GNUNET_BLOCK_TYPE_TEST, //FIXME todo
326                        &lookup_key,
327                        5, //Replication level FIXME
328                        GNUNET_DHT_RO_NONE,
329                        &rtype, //xquery FIXME this is bad
330                        sizeof(GNUNET_GNS_RECORD_PKEY),
331                        &process_authority_dht_result,
332                        rh);
333
334 }
335
336 /**
337  * Function called when we get a result from the dht
338  * for our query
339  *
340  * @param cls the request handle
341  * @param exp lifetime
342  * @param key the key the record was stored under
343  * @param get_path get path
344  * @param get_path_length get path length
345  * @param put_path put path
346  * @param put_path_length put path length
347  * @param type the block type
348  * @param size the size of the record
349  * @param data the record data
350  */
351 void
352 process_name_dht_result(void* cls,
353                  struct GNUNET_TIME_Absolute exp,
354                  const GNUNET_HashCode * key,
355                  const struct GNUNET_PeerIdentity *get_path,
356                  unsigned int get_path_length,
357                  const struct GNUNET_PeerIdentity *put_path,
358                  unsigned int put_path_length,
359                  enum GNUNET_BLOCK_Type type,
360                  size_t size, const void *data)
361 {
362   struct GNUNET_GNS_ResolverHandle *rh;
363   uint32_t num_records;
364   uint16_t namelen;
365   char* name = NULL;
366   struct GNUNET_CRYPTO_RsaSignature *signature;
367   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
368   int i;
369   char* pos;
370   GNUNET_HashCode zone, name_hash;
371
372   if (data == NULL)
373     return;
374
375   //FIXME maybe check expiration here
376   
377   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
378   pos = (char*)data;
379   
380
381   GNUNET_DHT_get_stop (rh->get_handle);
382   rh->get_handle = NULL;
383   num_records = ntohl(*pos);
384   struct GNUNET_NAMESTORE_RecordData rd[num_records];
385
386   pos += sizeof(uint32_t);
387   
388   for (i=0; i<num_records; i++)
389   {
390     namelen = ntohs(*pos);
391     pos += sizeof(uint16_t);
392     
393     //name must be 0 terminated
394     name = pos;
395     pos += namelen;
396   
397     rd[i].record_type = ntohl(*pos);
398     pos += sizeof(uint32_t);
399   
400     rd[i].data_size = ntohl(*pos);
401     pos += sizeof(uint32_t);
402   
403     rd[i].data = pos;
404     pos += rd[i].data_size;
405
406     rd[i].expiration = GNUNET_TIME_absolute_ntoh(
407                               *((struct GNUNET_TIME_AbsoluteNBO*)pos));
408     pos += sizeof(struct GNUNET_TIME_AbsoluteNBO);
409
410     rd[i].flags = ntohs(*pos);
411     pos += sizeof(uint16_t);
412     //FIXME class?
413     //
414     if (strcmp(name, rh->query->name) && rd[i].record_type == rh->query->type)
415     {
416       rh->answered++;
417     }
418
419   }
420
421   if ((((char*)data)-pos) < 
422       (sizeof(struct GNUNET_CRYPTO_RsaSignature) +
423        sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
424   {
425     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
426             "Cannot parse signature/key in DHT response. Corrupted or Missing");
427     return;
428   }
429
430   signature = (struct GNUNET_CRYPTO_RsaSignature*)pos;
431   pos += sizeof(struct GNUNET_CRYPTO_RsaSignature);
432   
433   public_key = (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded*)pos;
434
435   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
436   GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
437   
438   //FIXME check pubkey against existing key in namestore?
439   //https://gnunet.org/bugs/view.php?id=2179
440
441   //Save to namestore
442   GNUNET_NAMESTORE_record_put (namestore_handle,
443                                public_key,
444                                name,
445                                exp,
446                                num_records,
447                                rd,
448                                signature,
449                                &on_namestore_record_put_result, //cont
450                                NULL); //cls
451   
452   if (rh->answered)
453     reply_to_dns(rh, num_records, rd);
454   else
455     reply_to_dns(rh, 0, NULL);
456
457 }
458
459 /**
460  * Start DHT lookup for a (name -> query->record_type) record in
461  * query->authority's zone
462  *
463  * @param rh the pending gns query context
464  * @param name the name to query record
465  */
466 void
467 resolve_name_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name)
468 {
469   struct GNUNET_TIME_Relative timeout;
470   GNUNET_HashCode name_hash;
471   GNUNET_HashCode lookup_key;
472
473   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
474   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
475   
476
477   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
478   
479   //FIXME how long to wait for results?
480   rh->get_handle = GNUNET_DHT_get_start(dht_handle, timeout,
481                        GNUNET_BLOCK_TYPE_TEST, //FIXME todo
482                        &lookup_key,
483                        5, //Replication level FIXME
484                        GNUNET_DHT_RO_NONE,
485                        &rh->query->type, //xquery
486                        sizeof(rh->query->type),
487                        &process_name_dht_result,
488                        rh);
489
490 }
491
492 //Prototype
493 void
494 resolve_name(struct GNUNET_GNS_ResolverHandle *rh);
495
496 /**
497  * This is a callback function that should give us only PKEY
498  * records. Used to query the namestore for the authority (PKEY)
499  * for 'name'
500  *
501  * @param cls the pending query
502  * @param key the key of the zone we did the lookup
503  * @param expiration expiration date of the record data set in the namestore
504  * @param name the name for which we need an authority
505  * @param rd_count the number of records with 'name'
506  * @param rd the record data
507  * @param signature the signature of the authority for the record data
508  */
509 void
510 process_authority_lookup(void* cls,
511                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
512                    struct GNUNET_TIME_Absolute expiration,
513                    const char *name,
514                    unsigned int rd_count,
515                    const struct GNUNET_NAMESTORE_RecordData *rd,
516                    const struct GNUNET_CRYPTO_RsaSignature *signature)
517 {
518   struct GNUNET_GNS_ResolverHandle *rh;
519   struct GNUNET_TIME_Relative remaining_time;
520   GNUNET_HashCode zone;
521
522   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
523   GNUNET_CRYPTO_hash(key, GNUNET_CRYPTO_RSA_KEY_LENGTH, &zone);
524   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
525   
526   /**
527    * No authority found in namestore.
528    */
529   if (rd_count == 0)
530   {
531     /**
532      * We did not find an authority in the namestore
533      * _IF_ the current authoritative zone is us we cannot resolve
534      * _ELSE_ we can still check the _expired_ dht
535      */
536     if (0 != GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash) &&
537         (remaining_time.rel_value == 0))
538     {
539       resolve_authority_dht(rh, name);
540       return;
541     }
542     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Authority unknown\n");
543     reply_to_dns(rh, 0, NULL);
544     return;
545   }
546
547   //Note only 1 pkey should have been returned.. anything else would be strange
548   /**
549    * We found an authority that may be able to help us
550    * move on with query
551    */
552   int i;
553   for (i=0; i<rd_count;i++)
554   {
555   
556     if (strcmp(name, rh->query->name) && rd[i].record_type
557         != GNUNET_GNS_RECORD_PKEY)
558       continue;
559     
560       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
561           == 0)
562       {
563         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
564         if (remaining_time.rel_value == 0)
565         {
566           GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
567                      "This dht entry is expired. Refreshing\n");
568           resolve_authority_dht(rh, name);
569         }
570
571         continue;
572       }
573
574       GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
575       GNUNET_CRYPTO_hash(rd[i].data, GNUNET_CRYPTO_RSA_KEY_LENGTH,
576                          &rh->authority);
577       resolve_name(rh);
578       return;
579       
580   }
581     
582   /**
583    * no answers found
584    */
585   
586   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
587              "Authority lookup successful but no PKEY... never get here?\n");
588   reply_to_dns(rh, 0, NULL);
589 }
590
591
592 /**
593  * Reply to client with the result from our lookup.
594  *
595  * @param rh the request handle of the lookup
596  * @param rd_count the number of records to return
597  * @param rd the record data
598  */
599 void
600 reply_to_dns(struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count,
601              const struct GNUNET_NAMESTORE_RecordData *rd)
602 {
603   int i;
604   size_t len;
605   int ret;
606   char *buf;
607   struct GNUNET_DNSPARSER_Packet *packet = rh->packet;
608   struct GNUNET_DNSPARSER_Record answer_records[rh->answered];
609   struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)];
610   packet->answers = answer_records;
611   packet->additional_records = additional_records;
612   
613   len = sizeof(struct GNUNET_DNSPARSER_Record*);
614   for (i=0; i < rd_count; i++)
615   {
616     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
617                "Adding type %d to DNS response\n", rd[i].record_type);
618     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Name: %s\n", rh->name);
619     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "QName: %s\n", rh->query->name);
620     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Record %d/%d\n", i+1, rd_count);
621     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Record len %d\n", rd[i].data_size);
622     if (rd[i].record_type == rh->query->type)
623     {
624       answer_records[i].name = rh->query->name;
625       answer_records[i].type = rd[i].record_type;
626       answer_records[i].data.raw.data_len = rd[i].data_size;
627       answer_records[i].data.raw.data = (char*)rd[i].data;
628       answer_records[i].expiration_time = rd[i].expiration;
629       answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
630     }
631     else
632     {
633       additional_records[i].name = rh->query->name;
634       additional_records[i].type = rd[i].record_type;
635       additional_records[i].data.raw.data_len = rd[i].data_size;
636       additional_records[i].data.raw.data = (char*)rd[i].data;
637       additional_records[i].expiration_time = rd[i].expiration;
638       additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
639     }
640     //GNUNET_free(i->record); DO this later!
641   }
642   
643   packet->num_answers = rh->answered; //answer->num_records;
644   packet->num_additional_records = rd_count-(rh->answered);
645   
646   if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash))
647     packet->flags.authoritative_answer = 1;
648   else
649    packet->flags.authoritative_answer = 0;
650
651   if (rd == NULL)
652     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
653   else
654     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
655   
656   packet->flags.query_or_response = 1;
657
658   //FIXME this is silently discarded
659   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
660              "Building DNS response\n");
661   ret = GNUNET_DNSPARSER_pack (packet,
662                                1024, /* FIXME magic from dns redirector */
663                                &buf,
664                                &len);
665   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
666              "Built DNS response! (ret=%d,len=%d)\n", ret, len);
667   if (ret == GNUNET_OK)
668   {
669     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
670                "Answering DNS request\n");
671     GNUNET_DNS_request_answer(rh->request_handle,
672                               len,
673                               buf);
674     //GNUNET_free(answer);
675     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Answered DNS request\n");
676     //FIXME return code, free datastructures
677   }
678   else
679   {
680     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
681                "Error building DNS response! (ret=%d)", ret);
682   }
683
684   //FIXME into free_resolver(rh)
685   GNUNET_free(rh->name);
686   GNUNET_free(rh);
687 }
688
689
690 /**
691  * Namestore calls this function if we have an entry for this name.
692  * (or data=null to indicate the lookup has finished
693  *
694  * @param cls the pending query
695  * @param key the key of the zone we did the lookup
696  * @param expiration expiration date of the namestore entry
697  * @param name the name for which we need an authority
698  * @param rd_count the number of records with 'name'
699  * @param rd the record data
700  * @param signature the signature of the authority for the record data
701  */
702 static void
703 process_authoritative_result(void* cls,
704                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
705                   struct GNUNET_TIME_Absolute expiration,
706                   const char *name, unsigned int rd_count,
707                   const struct GNUNET_NAMESTORE_RecordData *rd,
708                   const struct GNUNET_CRYPTO_RsaSignature *signature)
709 {
710   struct GNUNET_GNS_ResolverHandle *rh;
711   struct GNUNET_TIME_Relative remaining_time;
712   GNUNET_HashCode zone;
713
714   rh = (struct GNUNET_GNS_ResolverHandle *) cls;
715   GNUNET_CRYPTO_hash(key, GNUNET_CRYPTO_RSA_KEY_LENGTH, &zone);
716   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
717
718   //FIXME Handle results in rd
719
720   if (rd_count == 0)
721   {
722     /**
723      * Lookup terminated and no results
724      * -> DHT Phase unless data is recent
725      */
726     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
727                "Namestore lookup for %s terminated without results\n", name);
728     
729     /**
730      * if this is not our zone we cannot rely on the namestore to be
731      * complete. -> Query DHT
732      */
733     if (!GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash))
734     {
735       if (remaining_time.rel_value == 0)
736       {
737         resolve_name_dht(rh, name);
738         return;
739       }
740       else
741       {
742         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
743                    "Record is still recent. No DHT lookup\n");
744       }
745     }
746
747     /**
748      * Our zone and no result? Cannot resolve TT
749      */
750     GNUNET_assert(rh->answered == 0);
751     reply_to_dns(rh, 0, NULL); //answered should be 0
752     return;
753
754   }
755   else
756   {
757     
758     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
759                "Processing additional result %s from namestore\n", name);
760     int i;
761     for (i=0; i<rd_count;i++)
762     {
763       
764       if (strcmp(name, rh->query->name) && rd[i].record_type != rh->query->type)
765         continue;
766       
767       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
768           == 0)
769       {
770         //FIXME there is a catch here...
771         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n");
772         continue;
773       }
774       
775       rh->answered++;
776       
777     }
778     
779     /**
780      * no answers found
781      * consult dht if expired
782      */
783     if ((remaining_time.rel_value == 0) && (rh->answered == 0))
784     {
785       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
786                  "This dht entry is old. Refreshing.\n");
787       resolve_name_dht(rh, name);
788       return;
789     }
790     
791     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Found %d answer(s) to query!\n",
792                rh->answered);
793
794     reply_to_dns(rh, rd_count, rd);
795   }
796 }
797
798 /**
799  * Determine if this name is canonical.
800  * i.e.
801  * a.b.gnunet  = not canonical
802  * a           = canonical
803  *
804  * @param name the name to test
805  * @return 1 if canonical
806  */
807 int
808 is_canonical(char* name)
809 {
810   uint32_t len = strlen(name);
811   int i;
812
813   for (i=0; i<len; i++)
814   {
815     if (*(name+i) == '.')
816       return 0;
817   }
818   return 1;
819 }
820
821 /**
822  * Move one level up in the domain hierarchy and return the
823  * passed top level domain.
824  *
825  * @param name the domain
826  * @return the tld
827  */
828 char* pop_tld(char* name)
829 {
830   uint32_t len;
831
832   if (is_canonical(name))
833     return NULL;
834
835   for (len = strlen(name); len > 0; len--)
836   {
837     if (*(name+len) == '.')
838       break;
839   }
840
841   if (len == 0)
842     return NULL; //Error
843
844   name[len] = '\0'; //terminate string
845
846   return (name+len+1);
847 }
848
849
850 /**
851  * The first phase of resolution.
852  * First check if the name is canonical.
853  * If it is then try to resolve directly.
854  * If not then first have to resolve the authoritative entities.
855  *
856  * @param rh the pending lookup
857  * @param zone the zone we are currently resolving in
858  */
859 void
860 resolve_name(struct GNUNET_GNS_ResolverHandle *rh)
861 {
862   if (is_canonical(rh->name))
863   {
864     //We only need to check this zone's ns
865     GNUNET_NAMESTORE_lookup_record(namestore_handle,
866                                &rh->authority,
867                                rh->name,
868                                rh->query->type,
869                                &process_authoritative_result,
870                                rh);
871   }
872   else
873   {
874     //We have to resolve the authoritative entity
875     char *new_authority = pop_tld(rh->name);
876     GNUNET_NAMESTORE_lookup_record(namestore_handle,
877                                  &rh->authority,
878                                  new_authority,
879                                  GNUNET_GNS_RECORD_PKEY,
880                                  &process_authority_lookup,
881                                  rh);
882   }
883 }
884
885 /**
886  * Entry point for name resolution
887  * Lookup local namestore of our zone.
888  *
889  * Setup a new query and try to resolve
890  *
891  * @param request the request handle of the DNS request from a client
892  * @param p the DNS query packet we received
893  * @param q the DNS query we received parsed from p
894  */
895 void
896 start_resolution(struct GNUNET_DNS_RequestHandle *request,
897                  struct GNUNET_DNSPARSER_Packet *p,
898                  struct GNUNET_DNSPARSER_Query *q)
899 {
900   struct GNUNET_GNS_ResolverHandle *rh;
901   
902   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting resolution for (%s)!\n",
903               q->name);
904   
905   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
906   rh->packet = p;
907   rh->query = q;
908   rh->authority = zone_hash;
909   
910   //FIXME do not forget to free!!
911   rh->name = GNUNET_malloc(strlen(q->name)
912                               - strlen(gnunet_tld) + 1);
913   memset(rh->name, 0,
914          strlen(q->name)-strlen(gnunet_tld) + 1);
915   memcpy(rh->name, q->name,
916          strlen(q->name)-strlen(gnunet_tld));
917
918   rh->request_handle = request;
919
920   //Start resolution in our zone
921   resolve_name(rh);
922 }
923
924 /**
925  * The DNS request handler
926  * Called for every incoming DNS request.
927  *
928  * @param cls closure
929  * @param rh request handle to user for reply
930  * @param request_length number of bytes in request
931  * @param request udp payload of the DNS request
932  */
933 void
934 handle_dns_request(void *cls,
935                    struct GNUNET_DNS_RequestHandle *rh,
936                    size_t request_length,
937                    const char *request)
938 {
939   struct GNUNET_DNSPARSER_Packet *p;
940   char *tldoffset;
941
942   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Hijacked a DNS request...processing\n");
943   p = GNUNET_DNSPARSER_parse (request, request_length);
944   
945   if (NULL == p)
946   {
947     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
948                 "Received malformed DNS packet, leaving it untouched\n");
949     GNUNET_DNS_request_forward (rh);
950     return;
951   }
952   
953   /**
954    * Check tld and decide if we or
955    * legacy dns is responsible
956    *
957    * FIXME now in theory there could be more than 1 query in the request
958    * but if this is case we get into trouble:
959    * either we query the GNS or the DNS. We cannot do both!
960    * So I suggest to either only allow a single query per request or
961    * only allow GNS or DNS requests.
962    * The way it is implemented here now is buggy and will lead to erratic
963    * behaviour (if multiple queries are present).
964    */
965   if (p->num_queries == 0)
966   {
967     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
968                 "No Queries in DNS packet... forwarding\n");
969     GNUNET_DNS_request_forward (rh);
970   }
971
972   if (p->num_queries > 1)
973   {
974     //Note: We could also look for .gnunet
975     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
976                 ">1 queriy in DNS packet... odd. We only process #1\n");
977   }
978
979
980   tldoffset = p->queries[0].name + strlen(p->queries[0].name);
981
982   while ((*tldoffset) != '.')
983     tldoffset--;
984   
985   if (0 == strcmp(tldoffset, gnunet_tld))
986   {
987     start_resolution(rh, p, p->queries);
988   }
989   else
990   {
991     /**
992      * This request does not concern us. Forward to real DNS.
993      */
994     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
995                "Request for %s is forwarded to DNS\n", p->queries[0].name);
996     GNUNET_DNS_request_forward (rh);
997   }
998
999 }
1000
1001 /**
1002  * test function that stores some data in the namestore
1003  */
1004 void
1005 put_some_records(void)
1006 {
1007   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Populating namestore\n");
1008   /* put a few records into namestore */
1009   char* ipA = "1.2.3.4";
1010   char* ipB = "5.6.7.8";
1011   struct GNUNET_CRYPTO_RsaPrivateKey *bob_key = GNUNET_CRYPTO_rsa_key_create ();  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *bob;
1012   bob = GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1013
1014   GNUNET_CRYPTO_rsa_key_get_public (bob_key, bob);
1015
1016   GNUNET_HashCode *bob_zone = GNUNET_malloc(sizeof(GNUNET_HashCode));
1017
1018   GNUNET_CRYPTO_hash(bob, GNUNET_CRYPTO_RSA_KEY_LENGTH, bob_zone);
1019
1020   struct in_addr *alice = GNUNET_malloc(sizeof(struct in_addr));
1021   struct in_addr *bob_web = GNUNET_malloc(sizeof(struct in_addr));
1022   struct GNUNET_NAMESTORE_RecordData rda;
1023   struct GNUNET_NAMESTORE_RecordData rdb;
1024   struct GNUNET_NAMESTORE_RecordData rdb_web;
1025
1026   GNUNET_assert(1 == inet_pton (AF_INET, ipA, alice));
1027   GNUNET_assert(1 == inet_pton (AF_INET, ipB, bob_web));
1028
1029   rda.data_size = sizeof(struct in_addr);
1030   rdb_web.data_size = sizeof(struct in_addr);
1031   rdb.data_size = sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded);
1032   rda.data = alice;
1033   rdb.data = bob;
1034   rdb_web.data = bob_web;
1035   rda.record_type = GNUNET_GNS_RECORD_TYPE_A;
1036   rdb_web.record_type = GNUNET_GNS_RECORD_TYPE_A;
1037   rdb.record_type = GNUNET_GNS_RECORD_PKEY;
1038   rdb_web.expiration = GNUNET_TIME_absolute_get_forever ();
1039   rda.expiration = GNUNET_TIME_absolute_get_forever ();
1040   rdb.expiration = GNUNET_TIME_absolute_get_forever ();
1041   
1042   //alice.gnunet A IN 1.2.3.4
1043   GNUNET_NAMESTORE_record_create (namestore_handle,
1044                                zone_key,
1045                                "alice",
1046                                &rda,
1047                                NULL,
1048                                NULL);
1049
1050   //www.bob.gnunet A IN 5.6.7.8
1051   GNUNET_NAMESTORE_record_create (namestore_handle,
1052                                zone_key,
1053                                "bob",
1054                                &rdb,
1055                                NULL,
1056                                NULL);
1057   GNUNET_NAMESTORE_record_put(namestore_handle,
1058                               bob,
1059                               "www",
1060                               GNUNET_TIME_absolute_get_forever (),
1061                               1,
1062                               &rdb_web,
1063                               NULL, //Signature
1064                               NULL, //Cont
1065                               NULL); //cls
1066 }
1067
1068 void
1069 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1070 {
1071   GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
1072 }
1073
1074 /* prototype */
1075 static void
1076 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1077
1078 /**
1079  * Function used to put all records successively into the DHT.
1080  * FIXME bug here
1081  *
1082  * @param cls the closure (NULL)
1083  * @param key the public key of the authority (ours)
1084  * @param expiration lifetime of the namestore entry
1085  * @param name the name of the records
1086  * @param rd_count the number of records in data
1087  * @param rd the record data
1088  * @param signature the signature for the record data
1089  */
1090 void
1091 put_gns_record(void *cls,
1092                 const const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1093                 struct GNUNET_TIME_Absolute expiration,
1094                 const char *name,
1095                 unsigned int rd_count,
1096                 const struct GNUNET_NAMESTORE_RecordData *rd,
1097                 const struct GNUNET_CRYPTO_RsaSignature *signature)
1098 {
1099   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Putting records into the DHT\n");
1100   struct GNUNET_TIME_Relative timeout;
1101   GNUNET_HashCode name_hash;
1102   GNUNET_HashCode xor_hash;
1103
1104   if (NULL == name) //We're done
1105   {
1106     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Zone iteration finished\n");
1107     GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1108     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start,
1109                                                    NULL);
1110     return;
1111   }
1112   /**
1113    * FIXME magic number 20 move to config file
1114    */
1115   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
1116   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1117   GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
1118   GNUNET_DHT_put (dht_handle, &xor_hash,
1119                   5, //replication level
1120                   GNUNET_DHT_RO_NONE,
1121                   GNUNET_BLOCK_TYPE_TEST, //FIXME todo block plugin
1122                   rd->data_size,
1123                   rd->data,
1124                   expiration,
1125                   timeout,
1126                   NULL, //FIXME continuation needed? success check? yes ofc
1127                   NULL); //cls for cont
1128   
1129   num_public_records++;
1130
1131   /**
1132    * Reschedule periodic put
1133    */
1134   zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1135                                 &update_zone_dht_next,
1136                                 NULL);
1137
1138 }
1139
1140 /**
1141  * Periodically iterate over our zone and store everything in dht
1142  *
1143  * @param cls NULL
1144  * @param tc task context
1145  */
1146 static void
1147 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1148 {
1149   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Update zone!\n");
1150   if (0 == num_public_records)
1151   {
1152     dht_update_interval = GNUNET_TIME_relative_multiply(
1153                                                       GNUNET_TIME_UNIT_SECONDS,
1154                                                       1);
1155   }
1156   else
1157   {
1158     dht_update_interval = GNUNET_TIME_relative_multiply(
1159                                                       GNUNET_TIME_UNIT_SECONDS,
1160                                                      (3600/num_public_records));
1161   }
1162   num_public_records = 0; //start counting again
1163   namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
1164                                                           &zone_hash,
1165                                                           GNUNET_NAMESTORE_RF_AUTHORITY,
1166                                                           GNUNET_NAMESTORE_RF_PRIVATE,
1167                                                           &put_gns_record,
1168                                                           NULL);
1169 }
1170
1171 /**
1172  * Process GNS requests.
1173  *
1174  * @param cls closure
1175  * @param server the initialized server
1176  * @param c configuration to use
1177  */
1178 static void
1179 run (void *cls, struct GNUNET_SERVER_Handle *server,
1180      const struct GNUNET_CONFIGURATION_Handle *c)
1181 {
1182   
1183   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Init GNS\n");
1184   zone_key = GNUNET_CRYPTO_rsa_key_create ();
1185
1186   GNUNET_CRYPTO_hash(zone_key, GNUNET_CRYPTO_RSA_KEY_LENGTH,//FIXME is this ok?
1187                      &zone_hash);
1188   nc = GNUNET_SERVER_notification_context_create (server, 1);
1189
1190   /* FIXME - do some config parsing 
1191    *       - Maybe only hijack dns if option is set (HIJACK_DNS=1)
1192    */
1193
1194   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1195                                 NULL);
1196   /**
1197    * Do gnunet dns init here
1198    */
1199   dns_handle = GNUNET_DNS_connect(c,
1200                                   GNUNET_DNS_FLAG_PRE_RESOLUTION,
1201                                   &handle_dns_request, /* rh */
1202                                   NULL); /* Closure */
1203
1204   if (NULL == dns_handle)
1205   {
1206     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1207                "Failed to connect to the dnsservice!\n");
1208   }
1209
1210   /**
1211    * handle to our local namestore
1212    */
1213   namestore_handle = GNUNET_NAMESTORE_connect(c);
1214
1215   if (NULL == namestore_handle)
1216   {
1217     //FIXME do error handling;
1218     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1219                "Failed to connect to the namestore!\n");
1220   }
1221
1222   /**
1223    * handle to the dht
1224    */
1225   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
1226
1227   if (NULL == dht_handle)
1228   {
1229     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
1230   }
1231
1232   put_some_records(); //FIXME for testing
1233   
1234   /**
1235    * Schedule periodic put
1236    * for our records
1237    * We have roughly an hour for all records;
1238    */
1239   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
1240                                                       1); //FIXME from cfg
1241   zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
1242   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "GNS Init done!\n");
1243
1244 }
1245
1246
1247 /**
1248  * The main function for the GNS service.
1249  *
1250  * @param argc number of arguments from the command line
1251  * @param argv command line arguments
1252  * @return 0 ok, 1 on error
1253  */
1254 int
1255 main (int argc, char *const *argv)
1256 {
1257   int ret;
1258
1259   ret =
1260       (GNUNET_OK ==
1261        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
1262                            NULL)) ? 0 : 1;
1263   return ret;
1264 }
1265
1266 /* end of gnunet-service-gns.c */