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