-fixing leaks, warnings, adding missing 0-termination checks for IPC messages
[oweals/gnunet.git] / src / gns / gnunet-service-gns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011, 2012 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  * @file gns/gnunet-service-gns.c
24  * @brief GNUnet GNS service
25  * @author Martin Schanzenbach
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_transport_service.h"
30 #include "gnunet_dns_service.h"
31 #include "gnunet_dnsparser_lib.h"
32 #include "gnunet_dht_service.h"
33 #include "gnunet_namestore_service.h"
34 #include "gnunet_gns_service.h"
35 #include "gnunet_statistics_service.h"
36 #include "block_gns.h"
37 #include "gns.h"
38 #include "gns_common.h"
39 #include "gnunet-service-gns_resolver.h"
40 #include "gnunet-service-gns_interceptor.h"
41 #include "gnunet_protocols.h"
42
43 #define INITIAL_ZONE_ITERATION_INTERVAL GNUNET_TIME_UNIT_MILLISECONDS
44 #define MINIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_UNIT_SECONDS
45 #define DEFAULT_RECORD_PUT_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
46 #define LATE_ITERATION_SPEEDUP_FACTOR 2
47
48
49 /**
50  * Handle to a shorten operation from api
51  */
52 struct ClientShortenHandle
53 {
54
55   /* DLL */
56   struct ClientShortenHandle *next;
57
58   /* DLL */
59   struct ClientShortenHandle *prev;
60
61   /* the requesting client that */
62   struct GNUNET_SERVER_Client *client;
63
64   /* request id */
65   uint64_t unique_id;
66
67   /* request type */
68   enum GNUNET_GNS_RecordType type;
69
70   /* name to shorten */
71   char name[MAX_DNS_NAME_LENGTH];
72
73   /* name of private zone (relative to root) */
74   char private_zone_id[MAX_DNS_NAME_LENGTH];
75   
76   /* name of shorten zone (relative to root) */
77   char shorten_zone_id[MAX_DNS_NAME_LENGTH];
78   
79   /* root zone */
80   struct GNUNET_CRYPTO_ShortHashCode root_zone;
81
82   /* private zone */
83   struct GNUNET_CRYPTO_ShortHashCode private_zone;
84   
85   /* shorten zone */
86   struct GNUNET_CRYPTO_ShortHashCode shorten_zone;
87
88   /* Namestore lookup task */
89   struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
90
91 };
92
93
94 /**
95  * Handle to a get auhtority operation from api
96  */
97 struct ClientGetAuthHandle
98 {
99   /* the requesting client that */
100   struct GNUNET_SERVER_Client *client;
101
102   /* request id */
103   uint64_t unique_id;
104
105   /* name to lookup authority */
106   char *name;
107
108 };
109
110
111 /**
112  * Handle to a lookup operation from api
113  */
114 struct ClientLookupHandle
115 {
116
117   /* the requesting client that */
118   struct GNUNET_SERVER_Client *client;
119
120   /* The zone we look up in */
121   struct GNUNET_CRYPTO_ShortHashCode zone;
122
123   /* Do we only want to lookup from local cache? */
124   int only_cached;
125
126   /* request id */
127   uint64_t unique_id;
128
129   /* request type */
130   enum GNUNET_GNS_RecordType type;
131
132   /* optional zone private key used for shorten */
133   struct GNUNET_CRYPTO_RsaPrivateKey *shorten_key;
134
135   /* the name to look up */
136   char *name; 
137 };
138
139
140 /**
141  * Our handle to the DHT
142  */
143 static struct GNUNET_DHT_Handle *dht_handle;
144
145 /**
146  * Our zone's private key
147  */
148 static struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
149
150 /**
151  * Our handle to the namestore service
152  * FIXME maybe need a second handle for iteration
153  */
154 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
155
156 /**
157  * Handle to iterate over our authoritative zone in namestore
158  */
159 static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
160
161 /**
162  * Our notification context.
163  */
164 static struct GNUNET_SERVER_NotificationContext *nc;
165
166 /**
167  * Our zone hash
168  */
169 static struct GNUNET_CRYPTO_ShortHashCode zone_hash;
170
171 /**
172  * Useful for zone update for DHT put
173  */
174 static unsigned long long num_public_records;
175
176 /**
177  * Last seen record count
178  */
179 static unsigned long long last_num_public_records;
180
181 /**
182  * FIXME!
183  */
184 static struct GNUNET_TIME_Relative zone_iteration_interval;
185
186 /* dht update interval FIXME define? */
187 static struct GNUNET_TIME_Relative record_put_interval;
188
189 /* zone update task */
190 static GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid;
191
192 /* automatic pkey import for name shortening */
193 static int auto_import_pkey;
194
195 /* first zone iteration is specia */
196 static int first_zone_iteration;
197
198 /* lookup timeout */
199 static struct GNUNET_TIME_Relative default_lookup_timeout;
200
201 /* ipv6 support */
202 static int v6_enabled;
203
204 /* ipv4 support */
205 static int v4_enabled;
206
207 /* Shorten DLL for cancelling NS requests */
208 static struct ClientShortenHandle *csh_head;
209
210 /* Shorten DLL for cancelling NS requests */
211 static struct ClientShortenHandle *csh_tail;
212
213 /* Statistics handle */
214 static struct GNUNET_STATISTICS_Handle *statistics;
215
216
217 /**
218  * Task run during shutdown.
219  *
220  * @param cls unused
221  * @param tc unused
222  */
223 static void
224 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
225 {
226   struct ClientShortenHandle *csh_tmp;
227
228   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
229              "Shutting down!");
230   while (NULL != (csh_tmp = csh_head))
231   {
232     GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh_tmp);
233     GNUNET_free(csh_tmp);
234   }
235   GNUNET_SERVER_notification_context_destroy (nc);  
236   gns_interceptor_stop ();
237   gns_resolver_cleanup ();
238   if (NULL != statistics)
239     GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
240   if (zone_update_taskid != GNUNET_SCHEDULER_NO_TASK)
241     GNUNET_SCHEDULER_cancel (zone_update_taskid);
242   if (NULL != namestore_iter)
243     GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
244   GNUNET_NAMESTORE_disconnect(namestore_handle);
245   GNUNET_DHT_disconnect(dht_handle);
246 }
247
248
249 /**
250  * Method called periodically that triggers iteration over authoritative records
251  *
252  * @param cls closure
253  * @param tc task context
254  */
255 static void
256 update_zone_dht_next (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
257 {
258   zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
259   GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
260 }
261
262
263 /**
264  * Continuation for DHT put
265  *
266  * @param cls closure
267  * @param success GNUNET_OK if the PUT was transmitted,
268  *                GNUNET_NO on timeout,
269  *                GNUNET_SYSERR on disconnect from service
270  *                after the PUT message was transmitted
271  *                (so we don't know if it was received or not)
272  */
273 static void
274 record_dht_put(void *cls, int success)
275 {
276   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n");
277 }
278
279
280 /* prototype */
281 static void
282 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
283
284
285 /**
286  * Function used to put all records successively into the DHT.
287  *
288  * @param cls the closure (NULL)
289  * @param key the public key of the authority (ours)
290  * @param expiration lifetime of the namestore entry
291  * @param name the name of the records
292  * @param rd_count the number of records in data
293  * @param rd the record data
294  * @param signature the signature for the record data
295  */
296 static void
297 put_gns_record(void *cls,
298                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
299                 struct GNUNET_TIME_Absolute expiration,
300                 const char *name,
301                 unsigned int rd_count,
302                 const struct GNUNET_NAMESTORE_RecordData *rd,
303                 const struct GNUNET_CRYPTO_RsaSignature *signature)
304 {  
305   struct GNSNameRecordBlock *nrb;
306   struct GNUNET_CRYPTO_ShortHashCode zhash;
307   struct GNUNET_HashCode dht_key;
308   uint32_t rd_payload_length;
309   char* nrb_data = NULL;
310   size_t namelen;
311   struct GNUNET_TIME_Relative next_put_interval; 
312
313   if (NULL == name)
314   {
315     /* we're done */
316     namestore_iter = NULL;
317     last_num_public_records = num_public_records;
318     first_zone_iteration = GNUNET_NO;
319     if (0 == num_public_records)
320     {
321       /**
322        * If no records are known (startup) or none present
323        * we can safely set the interval to the value for a single
324        * record
325        */
326       zone_iteration_interval = GNUNET_TIME_relative_divide (record_put_interval,
327                                                              1);
328
329       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
330                   "No records in db.\n");
331     }
332     else
333     {
334       zone_iteration_interval = GNUNET_TIME_relative_divide (record_put_interval,
335                                                              num_public_records);
336     }
337     zone_iteration_interval = GNUNET_TIME_relative_max (MINIMUM_ZONE_ITERATION_INTERVAL,
338                                                         zone_iteration_interval);
339
340     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341                 "Zone iteration finished. Adjusted zone iteration interval to %s\n",
342                 GNUNET_STRINGS_relative_time_to_string (zone_iteration_interval, GNUNET_YES));
343     GNUNET_STATISTICS_set (statistics,
344                            "Current zone iteration interval (in ms)",
345                            zone_iteration_interval.rel_value,
346                            GNUNET_NO);
347     GNUNET_STATISTICS_update (statistics,
348                               "Number of zone iterations", 1, GNUNET_NO);
349     GNUNET_STATISTICS_set (statistics,
350                            "Number of public records in DHT",
351                            last_num_public_records,
352                            GNUNET_NO);
353     if (0 == num_public_records)
354       zone_update_taskid = GNUNET_SCHEDULER_add_delayed (zone_iteration_interval,
355                                                          &update_zone_dht_start,
356                                                          NULL);
357     else
358       zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
359     return;
360   }
361   
362   namelen = strlen (name) + 1;
363   if (0 == rd_count)
364   {
365     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
366                 "No records for name `%s'! Skipping.\n",
367                 name);
368     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next,
369                                                    NULL);
370     return;
371   }
372   if (NULL == signature)
373   {
374     GNUNET_break (0);
375     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next,
376                                                    NULL);
377     return;
378   }
379   
380   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
381               "Putting records for `%s' into the DHT\n", name); 
382   rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd); 
383   nrb = GNUNET_malloc (rd_payload_length + namelen
384                        + sizeof (struct GNSNameRecordBlock));
385   nrb->signature = *signature;
386   nrb->public_key = *key;
387   nrb->rd_count = htonl (rd_count);
388   memcpy (&nrb[1], name, namelen);
389   nrb_data = (char *) &nrb[1];
390   nrb_data += namelen;
391   rd_payload_length += sizeof(struct GNSNameRecordBlock) + namelen;
392   GNUNET_CRYPTO_short_hash (key,
393                             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
394                             &zhash);
395   if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count,
396                                                 rd,
397                                                 rd_payload_length,
398                                                 nrb_data))
399   {
400     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
401                 _("Records for name `%s' in zone %s too large to fit into DHT"),
402                 name,
403                 GNUNET_short_h2s (&zhash));
404     GNUNET_free(nrb);
405     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next,
406                                                    NULL);
407     return;
408   }
409
410   GNUNET_GNS_get_key_for_record (name, &zhash, &dht_key);
411   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412               "putting %u records from zone %s for `%s' under key: %s with size %u and timeout %s\n",
413               rd_count,
414               GNUNET_short_h2s (&zhash),
415               name, 
416               GNUNET_h2s (&dht_key), 
417               (unsigned int) rd_payload_length,
418               GNUNET_STRINGS_relative_time_to_string (DHT_OPERATION_TIMEOUT, GNUNET_YES));
419   
420   GNUNET_STATISTICS_update (statistics,
421                             "Record bytes put into DHT", rd_payload_length, GNUNET_NO);
422
423   (void) GNUNET_DHT_put (dht_handle, &dht_key,
424                          DHT_GNS_REPLICATION_LEVEL,
425                          GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
426                          GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
427                          rd_payload_length,
428                          (char*)nrb,
429                          expiration,
430                          DHT_OPERATION_TIMEOUT,
431                          &record_dht_put,
432                          NULL); 
433   GNUNET_free (nrb);
434
435   num_public_records++;  
436   if ( (num_public_records > last_num_public_records)
437        && (GNUNET_NO == first_zone_iteration) )
438   {
439     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
440                 "Last record count was lower than current record count.  Reducing interval.\n");
441     zone_iteration_interval = GNUNET_TIME_relative_divide (record_put_interval,
442                                                            num_public_records);
443     next_put_interval = GNUNET_TIME_relative_divide (zone_iteration_interval,
444                                                      LATE_ITERATION_SPEEDUP_FACTOR);
445   }
446   else
447     next_put_interval = zone_iteration_interval;
448
449   GNUNET_STATISTICS_set (statistics,
450                          "Current zone iteration interval (ms)",
451                          next_put_interval.rel_value,
452                          GNUNET_NO); 
453   zone_update_taskid = GNUNET_SCHEDULER_add_delayed (next_put_interval,
454                                                      &update_zone_dht_next,
455                                                      NULL);
456 }
457
458
459 /**
460  * Periodically iterate over our zone and store everything in dht
461  *
462  * @param cls NULL
463  * @param tc task context
464  */
465 static void
466 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
467 {
468   zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
469
470   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling DHT zone update!\n");  
471   /* start counting again */
472   num_public_records = 0;
473   namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
474                                                           NULL, /* All zones */
475                                                           GNUNET_NAMESTORE_RF_AUTHORITY,
476                                                           GNUNET_NAMESTORE_RF_PRIVATE,
477                                                           &put_gns_record,
478                                                           NULL);
479 }
480
481
482 /* END DHT ZONE PROPAGATION */
483
484
485 /**
486  * Send shorten response back to client
487  * 
488  * @param cls the closure containing a client shorten handle
489  * @param name the shortened name result or NULL if cannot be shortened
490  */
491 static void
492 send_shorten_response (void* cls, const char* name)
493 {
494   struct ClientShortenHandle *csh = cls;
495   struct GNUNET_GNS_ClientShortenResultMessage *rmsg;
496   size_t name_len;
497   
498   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
499               "SHORTEN_RESULT", name);
500   if (NULL == name)
501     name_len = 0;
502   else
503     name_len = strlen (name) + 1;
504   GNUNET_STATISTICS_update (statistics,
505                             "Name shorten results", 1, GNUNET_NO);
506
507   rmsg = GNUNET_malloc (sizeof (struct GNUNET_GNS_ClientShortenResultMessage) +
508                         name_len);
509   
510   rmsg->id = csh->unique_id;
511   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT);
512   rmsg->header.size = 
513     htons(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) +
514           name_len);
515   memcpy (&rmsg[1], name, name_len);
516   GNUNET_SERVER_notification_context_unicast (nc, csh->client,
517                                               &rmsg->header,
518                                               GNUNET_NO);
519   if (NULL != csh->namestore_task)
520     GNUNET_NAMESTORE_cancel (csh->namestore_task); 
521   GNUNET_free (rmsg);
522   GNUNET_free (csh);
523 }
524
525
526 /**
527  * Lookup the zone infos and shorten name
528  *
529  * @param cls the client shorten handle
530  * @param key key of the zone
531  * @param expiration expiration of record
532  * @param name name found or null if no result
533  * @param rd_count number of records found
534  * @param rd record data
535  * @param signature
536  *
537  */
538 static void
539 process_shorten_in_private_zone_lookup (void *cls,
540                                         const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
541                                         struct GNUNET_TIME_Absolute expiration,
542                                         const char *name,
543                                         unsigned int rd_count,
544                                         const struct GNUNET_NAMESTORE_RecordData *rd,
545                                         const struct GNUNET_CRYPTO_RsaSignature *signature)
546 {
547   struct ClientShortenHandle *csh = cls;
548   struct GNUNET_CRYPTO_ShortHashCode *szone = &csh->shorten_zone;
549   struct GNUNET_CRYPTO_ShortHashCode *pzone = &csh->private_zone;
550
551   csh->namestore_task = NULL;
552   if (0 == strcmp (csh->private_zone_id, ""))
553     pzone = NULL;
554   
555   if (rd_count == 0)
556   {
557     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
558                 "No shorten zone in private zone!\n");
559     strcpy (csh->shorten_zone_id, "");
560     szone = NULL;
561   }
562   else
563   {
564     GNUNET_assert (rd_count == 1);
565
566     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
567                 "Shorten zone %s found in private zone %s\n",
568                 name, csh->private_zone_id);
569
570     sprintf (csh->shorten_zone_id, "%s.%s", name, csh->private_zone_id);
571   }
572   
573   GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
574
575   gns_resolver_shorten_name (&csh->root_zone,
576                              pzone,
577                              szone,
578                              csh->name,
579                              csh->private_zone_id,
580                              csh->shorten_zone_id,
581                              &send_shorten_response, csh);
582
583 }
584
585
586 /**
587  * Lookup the zone infos and shorten name
588  *
589  * @param cls the shorten handle
590  * @param key key of the zone
591  * @param expiration expiration of record
592  * @param name name found or null if no result
593  * @param rd_count number of records found
594  * @param rd record data
595  * @param signature
596  *
597  */
598 static void
599 process_shorten_in_root_zone_lookup (void *cls,
600                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
601                       struct GNUNET_TIME_Absolute expiration,
602                       const char *name,
603                       unsigned int rd_count,
604                       const struct GNUNET_NAMESTORE_RecordData *rd,
605                       const struct GNUNET_CRYPTO_RsaSignature *signature)
606 {
607   struct ClientShortenHandle *csh = cls;
608   struct GNUNET_CRYPTO_ShortHashCode *szone = &csh->shorten_zone;
609   struct GNUNET_CRYPTO_ShortHashCode *pzone = &csh->private_zone;
610   
611   csh->namestore_task = NULL;
612   if (0 == strcmp (csh->private_zone_id, ""))
613     pzone = NULL;
614
615   if (rd_count == 0)
616   {
617     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
618                 "No shorten zone in zone and no private zone!\n");
619
620     strcpy (csh->shorten_zone_id, "");
621
622     GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
623     szone = NULL;
624
625     gns_resolver_shorten_name (&csh->root_zone,
626                                pzone,
627                                szone,
628                                csh->name,
629                                csh->private_zone_id,
630                                csh->shorten_zone_id,
631                                &send_shorten_response, csh);
632     return;
633   }
634
635   GNUNET_assert (rd_count == 1);
636
637   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
638               "Private zone %s found in root zone\n", name);
639
640   strcpy (csh->private_zone_id, name);
641
642   csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
643                                   pzone,
644                                   szone,
645                                   &process_shorten_in_private_zone_lookup,
646                                   csh);
647 }
648
649
650 /**
651  * Lookup the zone infos and shorten name
652  *
653  * @param cls the shorten handle
654  * @param key key of the zone
655  * @param expiration expiration of record
656  * @param name name found or null if no result
657  * @param rd_count number of records found
658  * @param rd record data
659  * @param signature
660  *
661  */
662 static void
663 process_private_in_root_zone_lookup (void *cls,
664                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
665                       struct GNUNET_TIME_Absolute expiration,
666                       const char *name,
667                       unsigned int rd_count,
668                       const struct GNUNET_NAMESTORE_RecordData *rd,
669                       const struct GNUNET_CRYPTO_RsaSignature *signature)
670 {
671   struct ClientShortenHandle *csh = cls;
672   csh->namestore_task = NULL;
673
674   if (rd_count == 0)
675   {
676     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
677                 "No private zone in root zone\n");
678
679     strcpy (csh->private_zone_id, "");
680   
681     csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
682                                   &csh->root_zone,
683                                   &csh->shorten_zone,
684                                   &process_shorten_in_root_zone_lookup,
685                                   csh);
686     return;
687   }
688
689   GNUNET_assert (rd_count == 1);
690
691   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
692               "Private zone %s found in root zone\n", name);
693
694   strcpy (csh->private_zone_id, name);
695
696   csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
697                                   &csh->private_zone,
698                                   &csh->shorten_zone,
699                                   &process_shorten_in_private_zone_lookup,
700                                   csh);
701 }
702
703
704 /**
705  * Lookup the zone infos and shorten name
706  *
707  * @param csh the shorten handle
708  *
709  */
710 static void
711 start_shorten_name (struct ClientShortenHandle *csh)
712 {
713   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
714               "Looking for private zone name in root zone\n");
715
716   csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
717                                   &csh->root_zone,
718                                   &csh->private_zone,
719                                   &process_private_in_root_zone_lookup,
720                                   csh);
721 }
722
723
724 /**
725  * Handle a shorten message from the api
726  *
727  * @param cls the closure (unused)
728  * @param client the client
729  * @param message the message
730  */
731 static void 
732 handle_shorten (void *cls,
733                 struct GNUNET_SERVER_Client * client,
734                 const struct GNUNET_MessageHeader * message)
735 {
736   uint16_t msg_size;
737   const struct GNUNET_GNS_ClientShortenMessage *sh_msg;
738   struct ClientShortenHandle *csh;
739   const char *utf_in;
740   char name[MAX_DNS_NAME_LENGTH];
741   char* nameptr = name;
742
743   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "SHORTEN");
744   msg_size = ntohs (message->size);
745   if (msg_size < sizeof (struct GNUNET_GNS_ClientShortenMessage))
746   {
747     GNUNET_break (0);
748     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
749     return;
750   }
751   sh_msg = (const struct GNUNET_GNS_ClientShortenMessage *) message;
752   utf_in = (const char *) &sh_msg[1];
753   if ('\0' != utf_in[msg_size - sizeof (struct GNUNET_GNS_ClientShortenMessage) - 1])
754   {
755     GNUNET_break (0);
756     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
757     return;
758   }
759   csh = GNUNET_malloc (sizeof (struct ClientShortenHandle));
760   csh->client = client;
761   csh->unique_id = sh_msg->id;
762   GNUNET_CONTAINER_DLL_insert (csh_head, csh_tail, csh); 
763   GNUNET_STRINGS_utf8_tolower (utf_in, &nameptr);
764   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
765                "SHORTEN: Converted `%s' to `%s'\n", 
766              utf_in, 
767              nameptr);
768   GNUNET_SERVER_notification_context_add (nc, client);  
769   if (strlen (name) < strlen (GNUNET_GNS_TLD)) 
770   {
771     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
772                "SHORTEN: %s is too short\n", name);
773     GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
774     send_shorten_response(csh, name);
775     GNUNET_SERVER_receive_done (client, GNUNET_OK);
776     return;
777   }
778   if (strlen (name) > MAX_DNS_NAME_LENGTH) 
779   {
780     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
781                "SHORTEN: %s is too long\n", name);
782     GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
783     send_shorten_response(csh, name);
784     GNUNET_SERVER_receive_done (client, GNUNET_OK);
785     return;
786   }  
787   if ( (! is_gnunet_tld (name)) && 
788        (! is_zkey_tld (name)) )
789   {
790     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
791                 "%s is not our domain. Returning\n", name);
792     GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
793     send_shorten_response (csh, name);
794     GNUNET_SERVER_receive_done (client, GNUNET_OK);
795     return;
796   }
797   csh->shorten_zone = sh_msg->shorten_zone;
798   csh->private_zone = sh_msg->private_zone;
799   strcpy (csh->name, name);  
800   if (1 == ntohl(sh_msg->use_default_zone))
801     csh->root_zone = zone_hash; //Default zone
802   else
803     csh->root_zone = sh_msg->zone;
804   start_shorten_name (csh);
805   GNUNET_STATISTICS_update (statistics,
806                             "Name shorten attempts", 1, GNUNET_NO);
807   GNUNET_SERVER_receive_done (client, GNUNET_OK);
808 }
809
810
811 /**
812  * Send get authority response back to client
813  * 
814  * @param cls the closure containing a client get auth handle
815  * @param name the shortened name result or NULL if cannot be shortened
816  */
817 static void 
818 send_get_auth_response(void *cls, const char* name)
819 {
820   struct ClientGetAuthHandle *cah = cls;
821   struct GNUNET_GNS_ClientGetAuthResultMessage *rmsg;
822   
823   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
824               "GET_AUTH_RESULT", name);
825   if (name != NULL)
826   {
827     GNUNET_STATISTICS_update (statistics,
828                               "Authorities resolved", 1, GNUNET_NO);
829   }  
830   if (name == NULL)  
831     name = "";  
832
833   rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage)
834                        + strlen(name) + 1);
835   
836   rmsg->id = cah->unique_id;
837   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT);
838   rmsg->header.size = 
839     htons(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage) +
840           strlen(name) + 1);
841   strcpy ((char*)&rmsg[1], name);
842
843   GNUNET_SERVER_notification_context_unicast (nc, cah->client,
844                                               &rmsg->header,
845                                               GNUNET_NO);
846   GNUNET_SERVER_receive_done (cah->client, GNUNET_OK);
847   
848   GNUNET_free(rmsg);
849   GNUNET_free_non_null(cah->name);
850   GNUNET_free(cah);  
851 }
852
853
854 /**
855  * Handle a get authority message from the api
856  *
857  * @param cls the closure
858  * @param client the client
859  * @param message the message
860  */
861 static void 
862 handle_get_authority (void *cls,
863                       struct GNUNET_SERVER_Client * client,
864                       const struct GNUNET_MessageHeader * message)
865 {
866   uint16_t msg_size;
867   const struct GNUNET_GNS_ClientGetAuthMessage *sh_msg;
868   struct ClientGetAuthHandle *cah;
869   const char *utf_in;
870   char name[MAX_DNS_NAME_LENGTH];
871   char* nameptr = name;
872
873   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "GET_AUTH");
874   msg_size = ntohs(message->size);
875   if (msg_size < sizeof (struct GNUNET_GNS_ClientGetAuthMessage))
876   {
877     GNUNET_break (0);
878     GNUNET_SERVER_receive_done (client, GNUNET_OK);
879     return;
880   }
881   GNUNET_SERVER_notification_context_add (nc, client);
882
883   sh_msg = (const struct GNUNET_GNS_ClientGetAuthMessage *) message;
884   utf_in = (const char *) &sh_msg[1];
885   if ('\0' != utf_in[msg_size - sizeof (struct GNUNET_GNS_ClientGetAuthMessage) - 1])
886   {
887     GNUNET_break (0);
888     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
889     return;
890   }  
891   GNUNET_STRINGS_utf8_tolower(utf_in, &nameptr);
892   cah = GNUNET_malloc(sizeof(struct ClientGetAuthHandle));
893   cah->client = client;
894   cah->unique_id = sh_msg->id;
895   if (strlen (name) < strlen(GNUNET_GNS_TLD))
896   {
897     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
898                 "GET_AUTH: `%s' is too short. Returning\n", name);
899     cah->name = NULL;
900     send_get_auth_response(cah, name);
901     return;
902   }  
903   if (strlen (name) > MAX_DNS_NAME_LENGTH) 
904   {
905     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
906                "GET_AUTH: `%s' is too long", name);
907     cah->name = NULL;
908     send_get_auth_response(cah, name);
909     return;
910   }  
911   if (0 != strcmp (name + strlen (name) - strlen(GNUNET_GNS_TLD),
912                    GNUNET_GNS_TLD))
913   {
914     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
915                 "GET_AUTH: %s is not our domain. Returning\n", name);
916     cah->name = NULL;
917     send_get_auth_response(cah, name);
918     return;
919   }
920
921   if (0 == strcmp(name, GNUNET_GNS_TLD))
922   {
923     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
924                 "GET_AUTH: %s is us. Returning\n", name);
925     cah->name = NULL;
926     send_get_auth_response(cah, name);
927     return;
928   }  
929   cah->name = GNUNET_malloc(strlen (name)
930                             - strlen (GNUNET_GNS_TLD) + 1);
931   memset (cah->name, 0,
932           strlen (name) - strlen (GNUNET_GNS_TLD) + 1);
933   memcpy (cah->name, name,
934           strlen (name) - strlen(GNUNET_GNS_TLD));
935
936   /* Start delegation resolution in our namestore */
937   gns_resolver_get_authority(zone_hash, zone_hash, name, &send_get_auth_response, cah);
938
939   GNUNET_STATISTICS_update (statistics,
940                             "Authority lookup attempts", 1, GNUNET_NO);
941 }
942
943
944
945 /**
946  * Reply to client with the result from our lookup.
947  *
948  * @param cls the closure (our client lookup handle)
949  * @param rd_count the number of records
950  * @param rd the record data
951  */
952 static void
953 send_lookup_response(void* cls,
954                      uint32_t rd_count,
955                      const struct GNUNET_NAMESTORE_RecordData *rd)
956 {
957   struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls;
958   struct GNUNET_GNS_ClientLookupResultMessage *rmsg;
959   size_t len;
960   
961   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %d results\n",
962               "LOOKUP_RESULT", rd_count);
963   
964   len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
965   rmsg = GNUNET_malloc(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
966   
967   rmsg->id = clh->unique_id;
968   rmsg->rd_count = htonl(rd_count);
969   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
970   rmsg->header.size = 
971     htons(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
972   
973   GNUNET_NAMESTORE_records_serialize (rd_count, rd, len, (char*)&rmsg[1]);
974   
975   GNUNET_SERVER_notification_context_unicast (nc, clh->client,
976                                 (const struct GNUNET_MessageHeader *) rmsg,
977                                 GNUNET_NO);
978   GNUNET_SERVER_receive_done (clh->client, GNUNET_OK);
979   
980   GNUNET_free(rmsg);
981   GNUNET_free(clh->name);
982   
983   if (NULL != clh->shorten_key)
984     GNUNET_CRYPTO_rsa_key_free (clh->shorten_key);
985
986   GNUNET_free(clh);
987
988   GNUNET_STATISTICS_update (statistics,
989                             "Completed lookups", 1, GNUNET_NO);
990
991   if (rd != NULL)
992   {
993     GNUNET_STATISTICS_update (statistics,
994                               "Records resolved", rd_count, GNUNET_NO);
995   }
996
997 }
998
999
1000 /**
1001  * Handle lookup requests from client
1002  *
1003  * @param cls the closure
1004  * @param client the client
1005  * @param message the message
1006  */
1007 static void
1008 handle_lookup(void *cls,
1009               struct GNUNET_SERVER_Client * client,
1010               const struct GNUNET_MessageHeader * message)
1011 {
1012   uint16_t msg_size;
1013   const struct GNUNET_GNS_ClientLookupMessage *sh_msg;
1014   size_t namelen;
1015   char name[MAX_DNS_NAME_LENGTH];
1016   struct ClientLookupHandle *clh;
1017   char* nameptr = name;
1018   const char *utf_in;
1019   int only_cached;
1020   struct GNUNET_CRYPTO_RsaPrivateKey *key;
1021   struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *pkey;
1022   char* tmp_pkey;
1023
1024   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "LOOKUP");
1025   msg_size = ntohs(message->size);
1026   if (msg_size < sizeof (struct GNUNET_GNS_ClientLookupMessage))
1027   {
1028     GNUNET_break (0);
1029     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1030     return;
1031   }
1032   sh_msg = (const struct GNUNET_GNS_ClientLookupMessage *) message;
1033   GNUNET_SERVER_notification_context_add (nc, client);
1034   if (GNUNET_YES == ntohl (sh_msg->have_key))
1035   {
1036     pkey = (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *)&sh_msg[1];
1037     tmp_pkey = (char*)&sh_msg[1];
1038     key = GNUNET_CRYPTO_rsa_decode_key (tmp_pkey, ntohs(pkey->len));
1039     GNUNET_STRINGS_utf8_tolower(&tmp_pkey[ntohs(pkey->len)], &nameptr);
1040   }
1041   else
1042   {
1043     key = NULL;
1044     utf_in = (const char *) &sh_msg[1];
1045     if ('\0' != utf_in[msg_size - sizeof (struct GNUNET_GNS_ClientLookupMessage) - 1])
1046     {
1047       GNUNET_break (0);
1048       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1049       return;
1050     }  
1051     GNUNET_STRINGS_utf8_tolower(utf_in, &nameptr);
1052   }  
1053   namelen = strlen (name)+1;
1054   clh = GNUNET_malloc (sizeof (struct ClientLookupHandle));
1055   memset (clh, 0, sizeof (struct ClientLookupHandle));
1056   clh->client = client;
1057   clh->name = GNUNET_malloc(namelen);
1058   strcpy(clh->name, name);
1059   clh->unique_id = sh_msg->id;
1060   clh->type = ntohl(sh_msg->type);
1061   clh->shorten_key = key;
1062
1063   only_cached = ntohl(sh_msg->only_cached);
1064   
1065   if (strlen (name) > MAX_DNS_NAME_LENGTH) {
1066     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1067                "LOOKUP: %s is too long", name);
1068     clh->name = NULL;
1069     send_lookup_response(clh, 0, NULL);
1070     return;
1071   }
1072
1073   if ((clh->type == GNUNET_GNS_RECORD_A) &&
1074       (GNUNET_OK != v4_enabled))
1075   {
1076     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1077                "LOOKUP: Query for A record but AF_INET not supported!");
1078     clh->name = NULL;
1079     send_lookup_response(clh, 0, NULL);
1080     return;
1081   }
1082   
1083   if ((clh->type == GNUNET_GNS_RECORD_AAAA) &&
1084       (GNUNET_OK != v6_enabled))
1085   {
1086     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1087                "LOOKUP: Query for AAAA record but AF_INET6 not supported!");
1088     clh->name = NULL;
1089     send_lookup_response(clh, 0, NULL);
1090     return;
1091   }
1092   
1093   if (1 == ntohl(sh_msg->use_default_zone))
1094     clh->zone = zone_hash; //Default zone
1095   else
1096     clh->zone = sh_msg->zone;
1097   
1098   if (GNUNET_YES == auto_import_pkey)
1099   {
1100     gns_resolver_lookup_record (clh->zone, clh->zone, clh->type, clh->name,
1101                                 clh->shorten_key,
1102                                 default_lookup_timeout,
1103                                 clh->only_cached,
1104                                 &send_lookup_response, clh);  
1105   }
1106   else
1107   {
1108     gns_resolver_lookup_record (clh->zone, clh->zone, clh->type, name,
1109                                 NULL,
1110                                 default_lookup_timeout,
1111                                 only_cached,
1112                                 &send_lookup_response, clh);
1113   }
1114
1115   GNUNET_STATISTICS_update (statistics,
1116                             "Record lookup attempts", 1, GNUNET_NO);
1117 }
1118
1119
1120 /**
1121  * Test if the given AF is supported by this system.
1122  *
1123  * @param af to test
1124  * @return GNUNET_OK if the AF is supported
1125  */
1126 static int
1127 test_af (int af)
1128 {
1129   int s;
1130
1131   s = socket (af, SOCK_STREAM, 0);
1132   if (-1 == s)
1133   {
1134     if (EAFNOSUPPORT == errno)
1135       return GNUNET_NO;
1136     fprintf (stderr, "Failed to create test socket: %s\n", STRERROR (errno));
1137     return GNUNET_SYSERR;
1138   }
1139 #if WINDOWS
1140   closesocket (s);
1141 #else
1142   close (s);
1143 #endif
1144   return GNUNET_OK;
1145 }
1146
1147
1148 /**
1149  * Process GNS requests.
1150  *
1151  * @param cls closure)
1152  * @param server the initialized server
1153  * @param c configuration to use
1154  */
1155 static void
1156 run (void *cls, struct GNUNET_SERVER_Handle *server,
1157      const struct GNUNET_CONFIGURATION_Handle *c)
1158 {
1159   char* keyfile;
1160   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
1161   unsigned long long max_parallel_bg_queries = 0;
1162   unsigned long long default_lookup_timeout_secs = 0;
1163   int ignore_pending = GNUNET_NO;
1164
1165   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1166     {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0},
1167     {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0},
1168     {&handle_get_authority, NULL, GNUNET_MESSAGE_TYPE_GNS_GET_AUTH, 0}
1169   };
1170
1171   v6_enabled = test_af (AF_INET6);
1172   v4_enabled = test_af (AF_INET);
1173
1174   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "gns",
1175                                              "ZONEKEY", &keyfile))
1176   {
1177     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1178                 "No private key for root zone specified!\n");
1179     GNUNET_SCHEDULER_shutdown ();
1180     return;
1181   }
1182
1183   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1184              "Using keyfile %s for root zone.\n", keyfile);
1185
1186   zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1187   GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
1188
1189   GNUNET_CRYPTO_short_hash(&pkey,
1190                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1191                      &zone_hash);
1192   GNUNET_free(keyfile);
1193   namestore_handle = GNUNET_NAMESTORE_connect (c);
1194   if (NULL == namestore_handle)
1195   {
1196     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1197                 _("Failed to connect to the namestore!\n"));
1198     GNUNET_SCHEDULER_shutdown ();
1199     return;
1200   }
1201   
1202   auto_import_pkey = GNUNET_NO;
1203   if (GNUNET_YES ==
1204       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
1205                                             "AUTO_IMPORT_PKEY"))
1206   {
1207     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1208                "Automatic PKEY import is enabled.\n");
1209     auto_import_pkey = GNUNET_YES;
1210
1211   }
1212
1213   zone_iteration_interval = INITIAL_ZONE_ITERATION_INTERVAL;
1214
1215   record_put_interval = DEFAULT_RECORD_PUT_INTERVAL;
1216
1217   if (GNUNET_OK ==
1218       GNUNET_CONFIGURATION_get_value_time (c, "gns",
1219                                              "RECORD_PUT_INTERVAL",
1220                                              &record_put_interval))
1221   {
1222     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1223                 "Record put interval: %s\n",
1224                 GNUNET_STRINGS_relative_time_to_string (record_put_interval, GNUNET_YES));
1225   }
1226
1227   if (GNUNET_OK ==
1228       GNUNET_CONFIGURATION_get_value_number (c, "gns",
1229                                             "MAX_PARALLEL_BACKGROUND_QUERIES",
1230                                             &max_parallel_bg_queries))
1231   {
1232     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1233                "Number of allowed parallel background queries: %llu\n",
1234                max_parallel_bg_queries);
1235   }
1236
1237   if (GNUNET_YES ==
1238       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
1239                                             "AUTO_IMPORT_CONFIRMATION_REQ"))
1240   {
1241     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1242                "Auto import requires user confirmation\n");
1243     ignore_pending = GNUNET_YES;
1244   }
1245
1246   if (GNUNET_OK ==
1247       GNUNET_CONFIGURATION_get_value_number(c, "gns",
1248                                             "DEFAULT_LOOKUP_TIMEOUT",
1249                                             &default_lookup_timeout_secs))
1250   {
1251     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1252                "Default lookup timeout: %llus\n", default_lookup_timeout_secs);
1253     default_lookup_timeout = GNUNET_TIME_relative_multiply(
1254                                             GNUNET_TIME_UNIT_SECONDS,
1255                                             default_lookup_timeout_secs);
1256   }
1257   
1258   /**
1259    * handle to the dht
1260    */
1261   dht_handle = GNUNET_DHT_connect(c,
1262                        //max_parallel_bg_queries); //FIXME get ht_len from cfg
1263                        1024);
1264
1265   if (NULL == dht_handle)
1266   {
1267     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
1268   }
1269   
1270   if (gns_resolver_init(namestore_handle, dht_handle, zone_hash, c,
1271                         max_parallel_bg_queries,
1272                         ignore_pending)
1273       == GNUNET_SYSERR)
1274   {
1275     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1276                "Unable to initialize resolver!\n");
1277     GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1278     return;
1279   }
1280
1281   if (GNUNET_YES ==
1282       GNUNET_CONFIGURATION_get_value_yesno (c, "gns", "HIJACK_DNS"))
1283   {
1284     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1285                "DNS hijacking enabled... connecting to service.\n");
1286
1287     if (gns_interceptor_init(zone_hash, zone_key, c) == GNUNET_SYSERR)
1288     {
1289       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1290                "Failed to enable the dns interceptor!\n");
1291     }
1292   }
1293   
1294   /**
1295    * Schedule periodic put
1296    * for our records
1297    * We have roughly an hour for all records;
1298    */
1299   first_zone_iteration = GNUNET_YES;
1300   zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
1301
1302   GNUNET_SERVER_add_handlers (server, handlers);
1303   
1304   //FIXME
1305   //GNUNET_SERVER_disconnect_notify (server,
1306   //                                 &client_disconnect_notification,
1307   //                                 NULL);
1308
1309   statistics = GNUNET_STATISTICS_create ("gns", c);
1310
1311   nc = GNUNET_SERVER_notification_context_create (server, 1);
1312
1313   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1314                                 NULL);
1315 }
1316
1317
1318 /**
1319  * The main function for the GNS service.
1320  *
1321  * @param argc number of arguments from the command line
1322  * @param argv command line arguments
1323  * @return 0 ok, 1 on error
1324  */
1325 int
1326 main (int argc, char *const *argv)
1327 {
1328   int ret;
1329
1330   ret =
1331       (GNUNET_OK ==
1332        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
1333                            NULL)) ? 0 : 1;
1334   return ret;
1335 }
1336
1337 /* end of gnunet-service-gns.c */