-tiny fix, comments
[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  *    - Finish dht lookup
25  *    - Think about mixed dns queries (.gnunet and .org)
26  *    - The smaller FIXME issues all around
27  *
28  * @file gns/gnunet-service-gns.c
29  * @brief GNUnet GNS service
30  * @author Martin Schanzenbach
31  */
32 #include "platform.h"
33 #include "gnunet_util_lib.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_dns_service.h"
36 #include "gnunet_dnsparser_lib.h"
37 #include "gnunet_dht_service.h"
38 #include "gnunet_namestore_service.h"
39 #include "gnunet_gns_service.h"
40 #include "gns.h"
41
42 /* Ignore for now not used anyway and probably never will */
43 #define GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP 23
44 #define GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT 24
45
46 struct GNUNET_GNS_QueryRecordList
47 {
48   /**
49    * DLL
50    */
51   struct GNUNET_GNS_QueryRecordList * next;
52   struct GNUNET_GNS_QueryRecordList * prev;
53
54   struct GNUNET_DNSPARSER_Record * record;
55 };
56
57 /**
58  * A result list for namestore queries
59  */
60 struct GNUNET_GNS_PendingQuery
61 {
62   /* the answer packet */
63   struct GNUNET_DNSPARSER_Packet *answer;
64
65   /* records to put into answer packet */
66   struct GNUNET_GNS_QueryRecordList * records_head;
67   struct GNUNET_GNS_QueryRecordList * records_tail;
68
69   int num_records;
70   int num_authority_records; //FIXME are all of our replies auth?
71   
72   char *name;
73   uint16_t type;
74   /* the dns request id */
75   int id; // FIXME can handle->request_id also be used here?
76
77   /* the request handle to reply to */
78   struct GNUNET_DNS_RequestHandle *request_handle;
79
80   /* hast this query been answered? */
81   int answered;
82
83   /* we have an authority in namestore that
84    * may be able to resolve
85    */
86   int authority_found;
87 };
88
89
90 /**
91  * Our handle to the DNS handler library
92  */
93 struct GNUNET_DNS_Handle *dns_handle;
94
95 /**
96  * Our handle to the DHT
97  */
98 struct GNUNET_DHT_Handle *dht_handle;
99
100 struct GNUNET_TIME_Relative dht_update_interval;
101
102 /**
103  * Our private "key"
104  * FIXME get the real deal
105  */
106 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
107
108 /**
109  * Our handle to the namestore service
110  */
111 struct GNUNET_NAMESTORE_Handle *namestore_handle;
112
113 /**
114  * The configuration the GNS service is running with
115  */
116 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
117
118 /**
119  * Our notification context.
120  */
121 static struct GNUNET_SERVER_NotificationContext *nc;
122
123 /**
124  * Our zone hash
125  */
126 GNUNET_HashCode *zone_hash;
127
128 /**
129  * Task run during shutdown.
130  *
131  * @param cls unused
132  * @param tc unused
133  */
134 static void
135 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
136 {
137   GNUNET_DNS_disconnect(dns_handle);
138   GNUNET_NAMESTORE_disconnect(namestore_handle, 0);
139   GNUNET_DHT_disconnect(dht_handle);
140 }
141
142 /**
143  * FIXME
144  * This is where it gets tricky
145  * First we store (cache) all replies. Simple.
146  * If we see an authority "closer" to the name
147  * we have to start a new query. Unless we get
148  * a resolution.
149  * It is important that the authority is closer
150  * because else we might end up in an endless loop
151  * (maybe keep track of queried keys?)
152  * Of course we could just limit the resolution
153  * with a timeout (makes sense for clients) but we need
154  * to know when to stop querying.
155  */
156 void
157 handle_dht_reply(void* cls,
158                  struct GNUNET_TIME_Absolute exp,
159                  const GNUNET_HashCode * key,
160                  const struct GNUNET_PeerIdentity *get_path,
161                  unsigned int get_path_length,
162                  const struct GNUNET_PeerIdentity *put_path,
163                  unsigned int put_path_length,
164                  enum GNUNET_BLOCK_Type type,
165                  size_t size, const void *data)
166 {
167 }
168
169 void
170 process_auth_query(void* cls, const GNUNET_HashCode *zone,
171                    const char *name, uint32_t record_type,
172                    struct GNUNET_TIME_Absolute expiration,
173                    enum GNUNET_NAMESTORE_RecordFlags flags,
174                    const struct GNUNET_NAMESTORE_SignatureLocation *sig_loc,
175                    size_t size, const void *data)
176 {
177   struct GNUNET_GNS_PendingQuery *query;
178
179   query = (struct GNUNET_GNS_PendingQuery *)cls;
180   
181   /**
182    * No authority found
183    * FIXME We assume this will never return our authority
184    */
185   if ((NULL == data) && !query->authority_found)
186   {
187     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Find authority\n");
188     if (0 == strcmp(name, "gnunet"))
189     {
190       // Reached tld return nx
191       GNUNET_log(GNUNET_ERROR_TYPE_INFO, "NX record\n");
192       return;
193     }
194     
195     //Move name to next level
196     while ((*name) != '.')
197       name++;
198
199     name++;
200     GNUNET_NAMESTORE_lookup_name(namestore_handle,
201                                  zone_hash,
202                                  name,
203                                  GNUNET_GNS_RECORD_PKEY,
204                                  &process_auth_query,
205                                  query);
206     return;
207   }
208   
209   /**
210    * We found a PKEY that may be able to help us
211    */
212   query->authority_found = 1;
213   GNUNET_HashCode *key = (GNUNET_HashCode*) data;
214   
215   //FIXME magic number
216   struct GNUNET_TIME_Relative timeout =
217     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
218   GNUNET_DHT_get_start (dht_handle,
219                         timeout,
220                         GNUNET_BLOCK_TYPE_TEST, //TODO our plugin
221                         key,
222                         5, //replication
223                         GNUNET_DHT_RO_NONE,
224                         query->name, //xquery FIXME nobody will know this name
225                         strlen(query->name),
226                         &handle_dht_reply,
227                         query); //iter cls
228
229
230 }
231
232
233 /**
234  * Phase 2 of resolution.
235  */
236 void
237 lookup_dht(struct GNUNET_GNS_PendingQuery *query)
238 {
239   /**
240    * In this phase we first want to find the
241    * responsible authority in the namestore
242    */
243   GNUNET_NAMESTORE_lookup_name(namestore_handle,
244                                zone_hash,
245                                query->name,
246                                GNUNET_GNS_RECORD_PKEY,
247                                &process_auth_query,
248                                query);
249 }
250
251 void
252 reply_to_dns(struct GNUNET_GNS_PendingQuery *answer)
253 {
254   struct GNUNET_GNS_QueryRecordList *i;
255   struct GNUNET_DNSPARSER_Packet *packet;
256   struct GNUNET_DNSPARSER_Flags dnsflags;
257   int j;
258   size_t len;
259   int ret;
260   char *buf;
261   
262   packet = GNUNET_malloc(sizeof(struct GNUNET_DNSPARSER_Packet));
263   packet->answers =
264     GNUNET_malloc(sizeof(struct GNUNET_DNSPARSER_Record) * answer->num_records);
265   
266   len = sizeof(struct GNUNET_DNSPARSER_Record*);
267   j = 0;
268   for (i=answer->records_head; i != NULL; i=i->next)
269   {
270     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
271                "Adding %s to DNS response\n", i->record->name);
272     memcpy(&packet->answers[j], 
273            i->record,
274            sizeof (struct GNUNET_DNSPARSER_Record));
275     GNUNET_free(i->record);
276     j++;
277   }
278   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "after memcpy\n");
279   /* FIXME how to handle auth, additional etc */
280   packet->num_answers = answer->num_records;
281   packet->num_authority_records = answer->num_authority_records;
282
283   dnsflags.authoritative_answer = 1;
284   dnsflags.opcode = GNUNET_DNSPARSER_OPCODE_QUERY;
285   dnsflags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR; //not sure
286   dnsflags.query_or_response = 1;
287   packet->flags = dnsflags;
288
289   packet->id = answer->id;
290   ret = GNUNET_DNSPARSER_pack (packet,
291                                1024, /* FIXME magic from dns redirector */
292                                &buf,
293                                &len);
294   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
295              "Built DNS response! (ret=%d)\n", ret);
296   if (ret == GNUNET_OK)
297   {
298     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
299                "Answering DNS request\n");
300     GNUNET_DNS_request_answer(answer->request_handle,
301                               len,
302                               buf);
303     GNUNET_free(answer);
304     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Answered DNS request\n");
305     //FIXME return code, free datastructures
306   }
307   else
308   {
309     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
310                "Error building DNS response! (ret=%d)", ret);
311   }
312 }
313
314 static void
315 process_ns_result(void* cls, const GNUNET_HashCode *zone,
316                   const char *name, uint32_t record_type,
317                   struct GNUNET_TIME_Absolute expiration,
318                   enum GNUNET_NAMESTORE_RecordFlags flags,
319                   const struct GNUNET_NAMESTORE_SignatureLocation *sig_loc,
320                   size_t size, const void *data)
321 {
322   struct GNUNET_GNS_PendingQuery *query;
323   struct GNUNET_GNS_QueryRecordList *qrecord;
324   struct GNUNET_DNSPARSER_Record *record;
325   query = (struct GNUNET_GNS_PendingQuery *) cls;
326
327
328   if (NULL == data)
329   {
330     /**
331      * Last result received (or none)
332      * Do we have what we need to answer?
333      * If not -> DHT Phase
334      * FIXME free memory
335      */
336     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
337                "Namestore lookup terminated. (answered=%d)", query->answered);
338
339     if (query->answered)
340       reply_to_dns(query);
341     else
342       lookup_dht(query); //TODO
343
344   }
345   else
346   {
347     /**
348      * New result
349      */
350     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
351                "Processing additional result %s from namestore\n", name);
352
353     qrecord = GNUNET_malloc(sizeof(struct GNUNET_GNS_QueryRecordList));
354     record = GNUNET_malloc(sizeof(struct GNUNET_DNSPARSER_Record));
355     qrecord->record = record;
356
357     record->name = (char*)name;
358     /* FIXME for gns records this requires the dnsparser to be modified!
359      * or use RAW
360      * maybe store record data appropriately in namestore to avoid this
361      * huge switch?
362      **/
363     if (record_type == GNUNET_DNSPARSER_TYPE_A)
364     {
365       record->data.raw.data = (char*)data;
366       record->data.raw.data_len = size;
367     }
368     record->expiration_time = expiration;
369     record->type = record_type;
370     record->class = GNUNET_DNSPARSER_CLASS_INTERNET; /* srsly? */
371
372     if (flags == GNUNET_NAMESTORE_RF_AUTHORITY)
373     {
374       //query->num_authority_records++;
375     }
376
377     if ((0 == strcmp(query->name , name)) &&
378         (query->type == record_type))
379     {
380       GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Found answer to query!\n");
381       query->answered = 1;
382     }
383
384     query->num_records++;
385
386     //FIXME watch for leaks
387     GNUNET_CONTAINER_DLL_insert(query->records_head,
388                                 query->records_tail,
389                                 qrecord);
390   }
391 }
392
393
394 /**
395  * Phase 1 of name resolution: Lookup local namestore
396  *
397  * @param name the name to look up
398  * @param id the id of the dns request (for the reply)
399  * @param type the record type to look for
400  */
401 void
402 lookup_namestore(struct GNUNET_DNS_RequestHandle *rh,
403                  char* name, uint16_t id, uint16_t type)
404 {
405   struct GNUNET_GNS_PendingQuery *answer;
406   
407   /**
408    * Do db lookup here. Make dht lookup if necessary 
409    * FIXME for now only local lookups for our zone!
410    */
411   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "This is .gnunet (%s)!\n", name);
412   answer = GNUNET_malloc(sizeof (struct GNUNET_GNS_PendingQuery));
413   answer->id = id;
414   answer->name = name;
415   answer->type =type;
416   answer->request_handle = rh;
417   
418   GNUNET_NAMESTORE_lookup_name(namestore_handle,
419                                zone_hash,
420                                name,
421                                type,
422                                &process_ns_result,
423                                answer);
424 }
425
426 /**
427  * The DNS request handler
428  *
429  * @param cls closure
430  * @param rh request handle to user for reply
431  * @param request_length number of bytes in request
432  * @param request udp payload of the DNS request
433  */
434 void
435 handle_dns_request(void *cls,
436                    struct GNUNET_DNS_RequestHandle *rh,
437                    size_t request_length,
438                    const char *request)
439 {
440   /**
441    * parse request for tld
442    */
443   struct GNUNET_DNSPARSER_Packet *p;
444   int namelen;
445   int i;
446   char *tail;
447
448   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "hijacked a request...processing\n");
449   p = GNUNET_DNSPARSER_parse (request, request_length);
450   
451   if (NULL == p)
452   {
453     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
454                 "Received malformed DNS packet, leaving it untouched\n");
455     GNUNET_DNS_request_forward (rh);
456     return;
457   }
458   
459   /**
460    * Check tld and decide if we or
461    * legacy dns is responsible
462    */
463   for (i=0;i<p->num_queries;i++)
464   {
465     namelen = strlen(p->queries[i].name);
466     
467     if (namelen < 7) /* this can't be .gnunet */
468       continue;
469     /**
470      * Move our tld/root to config file
471      * Generate fake DNS reply that replaces .gnunet with .org for testing?
472      */
473     tail = p->queries[i].name+(namelen-7);
474     if (0 == strcmp(tail, ".gnunet"))
475     {
476       /* FIXME we need to answer to ALL queries in ONE response...
477        * What happens if some requests should be handled by us and
478        * others by DNS?
479        * Like this we only answer one...
480        */
481       lookup_namestore(rh, p->queries[i].name, p->id, p->queries[i].type);
482     }
483     else
484     {
485       /**
486        * This request does not concern us. Forward to real DNS.
487        */
488       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
489                  "Request for %s is forwarded to DNS\n", p->queries[i].name);
490       GNUNET_DNS_request_forward (rh);
491     }
492   }
493 }
494
495 /*TODO*/
496 static void
497 handle_client_record_lookup(void *cls,
498                             struct GNUNET_SERVER_Client *client,
499                             const struct GNUNET_MessageHeader *message)
500 {
501 }
502
503 /**
504  * test function
505  */
506 void
507 put_some_records(void)
508 {
509   /* put a few records into namestore */
510   char* ipA = "1.2.3.4";
511   char* ipB = "5.6.7.8";
512   struct in_addr *alice = GNUNET_malloc(sizeof(struct in_addr));
513   struct in_addr *bob = GNUNET_malloc(sizeof(struct in_addr));
514   GNUNET_assert(1 == inet_pton (AF_INET, ipA, alice));
515   GNUNET_assert(1 == inet_pton (AF_INET, ipB, bob));
516   GNUNET_NAMESTORE_record_put (namestore_handle,
517                                zone_hash,
518                                "alice.gnunet",
519                                GNUNET_GNS_RECORD_TYPE_A,
520                                GNUNET_TIME_absolute_get_forever(),
521                                GNUNET_NAMESTORE_RF_AUTHORITY,
522                                NULL, //sig loc
523                                sizeof(struct in_addr),
524                                alice,
525                                NULL,
526                                NULL);
527   GNUNET_NAMESTORE_record_put (namestore_handle,
528                                zone_hash,
529                                "bob.gnunet",
530                                GNUNET_GNS_RECORD_TYPE_A,
531                                GNUNET_TIME_absolute_get_forever(),
532                                GNUNET_NAMESTORE_RF_AUTHORITY,
533                                NULL, //sig loc
534                                sizeof(struct in_addr),
535                                bob,
536                                NULL,
537                                NULL);
538 }
539
540 //Prototype... needed in put function
541 static void
542 update_zone_dht(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
543
544 void
545 put_gns_record(void *cls, const GNUNET_HashCode *zone, const char *name,
546                uint32_t record_type, struct GNUNET_TIME_Absolute expiration,
547                enum GNUNET_NAMESTORE_RecordFlags flags,
548                const struct GNUNET_NAMESTORE_SignatureLocation *sig_loc,
549                size_t size, const void *record_data)
550 {
551   struct GNUNET_TIME_Relative timeout;
552
553   char* data;
554   char* data_ptr;
555   struct GNUNET_TIME_AbsoluteNBO exp_nbo;
556   exp_nbo = GNUNET_TIME_absolute_hton (expiration);
557   uint32_t namelen = htonl(strlen(name));
558   uint16_t flags_nbo = htons(flags);
559   uint64_t offset = GNUNET_htonll(sig_loc->offset);
560   uint32_t depth = htonl(sig_loc->depth);
561   uint32_t revision = htonl(sig_loc->revision);
562
563   /**
564    * I guess this can be done prettier
565    */
566   size_t record_len = sizeof(size_t) + sizeof(uint32_t) +
567     sizeof(uint16_t) +
568     sizeof(struct GNUNET_NAMESTORE_SignatureLocation) +
569     sizeof(uint32_t) + strlen(name) + size;
570   
571   record_type = htonl(record_type);
572
573   data = GNUNET_malloc(record_len);
574   
575   /* -_- */
576   data_ptr = data;
577   memcpy(data_ptr, &namelen, sizeof(size_t));
578   data_ptr += sizeof(size_t);
579
580   memcpy(data_ptr, name, namelen);
581   data_ptr += namelen;
582   
583   memcpy(data_ptr, &record_type, sizeof(uint32_t));
584   data_ptr += sizeof(uint32_t);
585
586   memcpy(data_ptr, &exp_nbo, sizeof(struct GNUNET_TIME_AbsoluteNBO));
587   data_ptr += sizeof(struct GNUNET_TIME_AbsoluteNBO);
588
589   memcpy(data_ptr, &flags_nbo, sizeof(uint16_t));
590   data_ptr += sizeof(uint16_t);
591
592   memcpy(data_ptr, &offset, sizeof(uint64_t));
593   data_ptr += sizeof(uint64_t);
594
595   memcpy(data_ptr, &depth, sizeof(uint32_t));
596   data_ptr += sizeof(uint32_t);
597   
598   memcpy(data_ptr, &revision, sizeof(uint32_t));
599   data_ptr += sizeof(uint32_t);
600
601   memcpy(data_ptr, &size, sizeof(uint32_t));
602   data_ptr += sizeof(uint32_t);
603
604   /**
605    * FIXME note that this only works with raw data in nbo
606    * write helper function that converts properly and returns buffer
607    */
608   memcpy(data_ptr, record_data, size);
609   data_ptr += size;
610   /*Doing this made me sad...*/
611
612   /**
613    * FIXME magic number
614    */
615   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
616
617   GNUNET_DHT_put (dht_handle, zone_hash,
618                   5, //replication
619                   GNUNET_DHT_RO_NONE,
620                   GNUNET_BLOCK_TYPE_TEST, //FIXME todo
621                   (data_ptr-data),
622                   data,
623                   expiration, //FIXME from record makes sense?
624                   timeout,
625                   NULL, //FIXME continuation needed? success check?
626                   NULL); //cls for cont
627
628   /**
629    * Reschedule update
630    */
631   GNUNET_SCHEDULER_add_delayed (dht_update_interval,
632                                 &update_zone_dht,
633                                 NULL);
634
635 }
636
637 /**
638  * Periodically iterate over our zone and store everything in dht
639  */
640 static void
641 update_zone_dht(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
642 {
643   GNUNET_NAMESTORE_zone_transfer (namestore_handle, zone_hash,
644                                   &put_gns_record,
645                                   NULL);
646 }
647
648 /**
649  * Process GNS requests.
650  *
651  * @param cls closure
652  * @param server the initialized server
653  * @param c configuration to use
654  */
655 static void
656 run (void *cls, struct GNUNET_SERVER_Handle *server,
657      const struct GNUNET_CONFIGURATION_Handle *c)
658 {
659   
660   /* The IPC message types */
661   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
662     /* callback, cls, type, size */
663     {&handle_client_record_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP,
664       0},
665     {NULL, NULL, 0, 0}
666   };
667   
668   zone_key = GNUNET_CRYPTO_rsa_key_create ();
669   GNUNET_CRYPTO_hash(zone_key, GNUNET_CRYPTO_RSA_KEY_LENGTH,//FIXME is this ok?
670                      zone_hash);
671
672   nc = GNUNET_SERVER_notification_context_create (server, 1);
673
674   /* FIXME - do some config parsing 
675    *       - Maybe only hijack dns if option is set (HIJACK_DNS=1)
676    */
677
678   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
679                                 NULL);
680   /**
681    * Do gnunet dns init here
682    */
683   dns_handle = GNUNET_DNS_connect(c,
684                                   GNUNET_DNS_FLAG_PRE_RESOLUTION,
685                                   &handle_dns_request, /* rh */
686                                   NULL); /* Closure */
687
688   if (NULL == dns_handle)
689   {
690     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
691                "Failed to connect to the dnsservice!\n");
692   }
693
694   /**
695    * handle to our local namestore
696    */
697   namestore_handle = GNUNET_NAMESTORE_connect(c);
698
699   if (NULL == namestore_handle)
700   {
701     //FIXME do error handling;
702     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
703                "Failed to connect to the namestore!\n");
704   }
705
706   /**
707    * handle to the dht
708    */
709   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
710
711   if (NULL == dht_handle)
712   {
713     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
714   }
715   
716   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
717                                                       60); //FIXME from cfg
718   GNUNET_SCHEDULER_add_delayed (dht_update_interval,
719                                 &update_zone_dht,
720                                 NULL);
721   
722   put_some_records();
723
724   GNUNET_SERVER_add_handlers (server, handlers);
725   /**
726    * Esp the lookup would require to keep track of the clients' context
727    * See dht.
728    * GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
729    **/
730 }
731
732
733 /**
734  * The main function for the GNS service.
735  *
736  * @param argc number of arguments from the command line
737  * @param argv command line arguments
738  * @return 0 ok, 1 on error
739  */
740 int
741 main (int argc, char *const *argv)
742 {
743   int ret;
744
745   ret =
746       (GNUNET_OK ==
747        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
748                            NULL)) ? 0 : 1;
749   return ret;
750 }
751
752 /* end of gnunet-service-gns.c */