-add bg lookups for shorten
[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  * @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 "block_gns.h"
36 #include "gns.h"
37 #include "gnunet-service-gns_resolver.h"
38 #include "gnunet-service-gns_interceptor.h"
39
40 /* FIXME move to proper header in include */
41 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP 23
42 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT 24
43 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN 25
44 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT 26
45 #define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH 27
46 #define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT 28
47
48
49 /**
50  * Handle to a shorten operation from api
51  */
52 struct ClientShortenHandle
53 {
54   /* the requesting client that */
55   struct GNUNET_SERVER_Client *client;
56
57   /* request id */
58   uint64_t unique_id;
59
60   /* request type */
61   enum GNUNET_GNS_RecordType type;
62
63   /* name to shorten */
64   char* name;
65
66 };
67
68
69 /**
70  * Handle to a get auhtority operation from api
71  */
72 struct ClientGetAuthHandle
73 {
74   /* the requesting client that */
75   struct GNUNET_SERVER_Client *client;
76
77   /* request id */
78   uint64_t unique_id;
79
80   /* name to lookup authority */
81   char* name;
82
83 };
84
85
86 /**
87  * Handle to a lookup operation from api
88  */
89 struct ClientLookupHandle
90 {
91   /* the requesting client that */
92   struct GNUNET_SERVER_Client *client;
93
94   /* request id */
95   uint64_t unique_id;
96
97   /* request type */
98   enum GNUNET_GNS_RecordType type;
99
100   /* the name to look up */
101   char* name; //Needed?
102 };
103
104 /**
105  * Our handle to the DHT
106  */
107 static struct GNUNET_DHT_Handle *dht_handle;
108
109 /**
110  * Our zone's private key
111  */
112 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
113
114 /**
115  * Our handle to the namestore service
116  * FIXME maybe need a second handle for iteration
117  */
118 struct GNUNET_NAMESTORE_Handle *namestore_handle;
119
120 /**
121  * Handle to iterate over our authoritative zone in namestore
122  */
123 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
124
125 /**
126  * The configuration the GNS service is running with
127  */
128 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
129
130 /**
131  * Our notification context.
132  */
133 static struct GNUNET_SERVER_NotificationContext *nc;
134
135 /**
136  * Our zone hash
137  */
138 struct GNUNET_CRYPTO_ShortHashCode zone_hash;
139
140 /**
141  * Useful for zone update for DHT put
142  */
143 static int num_public_records =  3600;
144
145 /* dht update interval FIXME define? */
146 static struct GNUNET_TIME_Relative dht_update_interval;
147
148 /* zone update task */
149 GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
150
151 /* automatic pkey import for name shortening */
152 static int auto_import_pkey;
153
154 /* lookup timeout */
155 static struct GNUNET_TIME_Relative default_lookup_timeout;
156
157 /**
158  * Continue shutdown
159  */
160 static void
161 on_resolver_cleanup(void)
162 {
163   GNUNET_NAMESTORE_disconnect(namestore_handle, 1);
164   GNUNET_DHT_disconnect(dht_handle);
165 }
166
167 /**
168  * Task run during shutdown.
169  *
170  * @param cls unused
171  * @param tc unused
172  */
173 static void
174 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
175 {
176
177   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
178              "Shutting down!");
179   /* Kill zone task for it may make the scheduler hang */
180   if (zone_update_taskid)
181     GNUNET_SCHEDULER_cancel(zone_update_taskid);
182   
183   GNUNET_SERVER_notification_context_destroy (nc);
184   
185   gns_interceptor_stop();
186   gns_resolver_cleanup(&on_resolver_cleanup);
187
188 }
189
190
191 /**
192  * Method called periodicattluy that triggers
193  * iteration over root zone
194  *
195  * @param cls closure
196  * @param tc task context
197  */
198 static void
199 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
200 {
201   GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
202 }
203
204 /**
205  * Continuation for DHT put
206  *
207  * @param cls closure
208  * @param tc task context
209  */
210 static void
211 record_dht_put(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
212 {
213   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n");
214 }
215
216 /* prototype */
217 static void
218 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
219
220 /**
221  * Function used to put all records successively into the DHT.
222  *
223  * @param cls the closure (NULL)
224  * @param key the public key of the authority (ours)
225  * @param expiration lifetime of the namestore entry
226  * @param name the name of the records
227  * @param rd_count the number of records in data
228  * @param rd the record data
229  * @param signature the signature for the record data
230  */
231 static void
232 put_gns_record(void *cls,
233                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
234                 struct GNUNET_TIME_Absolute expiration,
235                 const char *name,
236                 unsigned int rd_count,
237                 const struct GNUNET_NAMESTORE_RecordData *rd,
238                 const struct GNUNET_CRYPTO_RsaSignature *signature)
239 {
240   
241   struct GNSNameRecordBlock *nrb;
242   struct GNUNET_CRYPTO_ShortHashCode name_hash;
243   GNUNET_HashCode xor_hash;
244   GNUNET_HashCode name_hash_double;
245   GNUNET_HashCode zone_hash_double;
246   struct GNUNET_CRYPTO_HashAsciiEncoded xor_hash_string;
247   uint32_t rd_payload_length;
248   char* nrb_data = NULL;
249   size_t namelen;
250
251   /* we're done */
252   if (NULL == name)
253   {
254     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
255                "Zone iteration finished. Rescheduling put in %ds\n",
256                GNUNET_GNS_DHT_MAX_UPDATE_INTERVAL);
257     zone_update_taskid = GNUNET_SCHEDULER_add_delayed (
258                                         GNUNET_TIME_relative_multiply(
259                                             GNUNET_TIME_UNIT_SECONDS,
260                                             GNUNET_GNS_DHT_MAX_UPDATE_INTERVAL
261                                             ),
262                                             &update_zone_dht_start,
263                                             NULL);
264     return;
265   }
266   
267   namelen = strlen(name) + 1;
268   
269   if (signature == NULL)
270   {
271     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
272                "No signature for %s record data provided! Skipping...\n",
273                name);
274     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next,
275                                                    NULL);
276     return;
277
278   }
279   
280   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
281              "Putting records for %s into the DHT\n", name);
282   
283   rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
284   
285   nrb = GNUNET_malloc(rd_payload_length + namelen
286                       + sizeof(struct GNSNameRecordBlock));
287   
288   nrb->signature = *signature;
289   
290   nrb->public_key = *key;
291
292   nrb->rd_count = htonl(rd_count);
293   
294   memcpy(&nrb[1], name, namelen);
295
296   nrb_data = (char*)&nrb[1];
297   nrb_data += namelen;
298
299   rd_payload_length += sizeof(struct GNSNameRecordBlock) + namelen;
300
301   if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count,
302                                                 rd,
303                                                 rd_payload_length,
304                                                 nrb_data))
305   {
306     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
307                "Record serialization failed! Skipping...\n");
308     GNUNET_free(nrb);
309     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next,
310                                                    NULL);
311     return;
312   }
313
314
315   /*
316    * calculate DHT key: H(name) xor H(pubkey)
317    */
318   GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
319   GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
320   GNUNET_CRYPTO_short_hash_double (&zone_hash, &zone_hash_double);
321   GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash);
322   GNUNET_CRYPTO_hash_to_enc (&xor_hash, &xor_hash_string);
323
324   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
325              "putting records for %s under key: %s with size %d\n",
326              name, (char*)&xor_hash_string, rd_payload_length);
327
328   GNUNET_DHT_put (dht_handle, &xor_hash,
329                   DHT_GNS_REPLICATION_LEVEL,
330                   GNUNET_DHT_RO_NONE,
331                   GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
332                   rd_payload_length,
333                   (char*)nrb,
334                   expiration,
335                   DHT_OPERATION_TIMEOUT,
336                   &record_dht_put,
337                   NULL); //cls for cont
338   
339   num_public_records++;
340
341   /**
342    * Reschedule periodic put
343    */
344   zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval,
345                                 &update_zone_dht_next,
346                                 NULL);
347
348   GNUNET_free(nrb);
349
350 }
351
352 /**
353  * Periodically iterate over our zone and store everything in dht
354  *
355  * @param cls NULL
356  * @param tc task context
357  */
358 static void
359 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
360 {
361   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling DHT zone update!\n");
362   if (0 == num_public_records)
363   {
364     dht_update_interval = GNUNET_TIME_relative_multiply(
365                                             GNUNET_TIME_UNIT_SECONDS,
366                                             GNUNET_GNS_DHT_MAX_UPDATE_INTERVAL);
367     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
368                "No records in db. Adjusted DHT update interval to %ds\n",
369                GNUNET_GNS_DHT_MAX_UPDATE_INTERVAL);
370   }
371   else
372   {
373     
374     dht_update_interval = GNUNET_TIME_relative_multiply(
375                                                       GNUNET_TIME_UNIT_SECONDS,
376                                                      (3600/num_public_records));
377     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
378                "Adjusted DHT update interval to %ds!\n",
379                (3600/num_public_records));
380   }
381
382   /* start counting again */
383   num_public_records = 0;
384   namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
385                                                  &zone_hash,
386                                                  GNUNET_NAMESTORE_RF_AUTHORITY,
387                                                  GNUNET_NAMESTORE_RF_PRIVATE,
388                                                  &put_gns_record,
389                                                  NULL);
390 }
391
392
393 /* END DHT ZONE PROPAGATION */
394
395 /**
396  * Send shorten response back to client
397  * 
398  * @param cls the closure containing a client shorten handle
399  * @param name the shortened name result or NULL if cannot be shortened
400  */
401 static void
402 send_shorten_response(void* cls, const char* name)
403 {
404   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
405               "SHORTEN_RESULT", name);
406   struct GNUNET_GNS_ClientShortenResultMessage *rmsg;
407   struct ClientShortenHandle *csh = (struct ClientShortenHandle *)cls;
408   
409   if (name == NULL)
410   {
411     name = "";
412   }
413
414   rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientShortenResultMessage)
415                        + strlen(name) + 1);
416   
417   rmsg->id = csh->unique_id;
418   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT);
419   rmsg->header.size = 
420     htons(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) +
421           strlen(name) + 1);
422
423   strcpy((char*)&rmsg[1], name);
424
425   GNUNET_SERVER_notification_context_unicast (nc, csh->client,
426                               (const struct GNUNET_MessageHeader *) rmsg,
427                               GNUNET_NO);
428   GNUNET_SERVER_receive_done (csh->client, GNUNET_OK);
429   
430   GNUNET_free(rmsg);
431   GNUNET_free_non_null(csh->name);
432   GNUNET_free(csh);
433
434 }
435
436 /**
437  * Handle a shorten message from the api
438  *
439  * @param cls the closure
440  * @param client the client
441  * @param message the message
442  */
443 static void handle_shorten(void *cls,
444                            struct GNUNET_SERVER_Client * client,
445                            const struct GNUNET_MessageHeader * message)
446 {
447   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "SHORTEN");
448
449   size_t msg_size = 0;
450   struct ClientShortenHandle *csh;
451   const char* name;
452
453   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientShortenMessage))
454   {
455     GNUNET_break_op (0);
456     GNUNET_SERVER_receive_done (client, GNUNET_OK);
457     return;
458   }
459
460   GNUNET_SERVER_notification_context_add (nc, client);
461
462   struct GNUNET_GNS_ClientShortenMessage *sh_msg =
463     (struct GNUNET_GNS_ClientShortenMessage *) message;
464   
465   msg_size = ntohs(message->size);
466
467   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
468   {
469     GNUNET_break_op (0);
470     GNUNET_SERVER_receive_done (client, GNUNET_OK);
471     return;
472   }
473
474   csh = GNUNET_malloc(sizeof(struct ClientShortenHandle));
475   csh->client = client;
476   csh->unique_id = sh_msg->id;
477   
478   name = (char*)&sh_msg[1];
479
480   if (strlen (name) < strlen(GNUNET_GNS_TLD)) {
481     csh->name = NULL;
482     send_shorten_response(csh, name);
483     return;
484   }
485   
486   if (!is_gnunet_tld(name) && !is_zkey_tld(name))
487   {
488     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
489                 "%s is not our domain. Returning\n", name);
490     csh->name = NULL;
491     send_shorten_response(csh, name);
492     return;
493   }
494   
495   /* Start shortening */
496   if (GNUNET_YES == auto_import_pkey)
497     gns_resolver_shorten_name(zone_hash, name, zone_key,
498                               &send_shorten_response, csh);
499   else
500     gns_resolver_shorten_name(zone_hash, name, NULL,
501                               &send_shorten_response, csh);
502 }
503
504
505 /**
506  * Send get authority response back to client
507  * 
508  * @param cls the closure containing a client get auth handle
509  * @param name the shortened name result or NULL if cannot be shortened
510  */
511 static void
512 send_get_auth_response(void *cls, const char* name)
513 {
514   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
515               "GET_AUTH_RESULT", name);
516   struct GNUNET_GNS_ClientGetAuthResultMessage *rmsg;
517   struct ClientGetAuthHandle *cah = (struct ClientGetAuthHandle *)cls;
518   
519   if (name == NULL)
520   {
521     name = "";
522   }
523
524   rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage)
525                        + strlen(name) + 1);
526   
527   rmsg->id = cah->unique_id;
528   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT);
529   rmsg->header.size = 
530     htons(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage) +
531           strlen(name) + 1);
532
533   strcpy((char*)&rmsg[1], name);
534
535   GNUNET_SERVER_notification_context_unicast (nc, cah->client,
536                               (const struct GNUNET_MessageHeader *) rmsg,
537                               GNUNET_NO);
538   GNUNET_SERVER_receive_done (cah->client, GNUNET_OK);
539   
540   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up handles...\n");
541
542   GNUNET_free(rmsg);
543   GNUNET_free_non_null(cah->name);
544   GNUNET_free(cah);
545
546   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done.\n");
547
548 }
549
550
551 /**
552  * Handle a get authority message from the api
553  *
554  * @param cls the closure
555  * @param client the client
556  * @param message the message
557  */
558 static void handle_get_authority(void *cls,
559                            struct GNUNET_SERVER_Client * client,
560                            const struct GNUNET_MessageHeader * message)
561 {
562   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "GET_AUTH");
563
564   size_t msg_size = 0;
565   struct ClientGetAuthHandle *cah;
566   const char* name;
567
568   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientGetAuthMessage))
569   {
570     GNUNET_break_op (0);
571     GNUNET_SERVER_receive_done (client, GNUNET_OK);
572     return;
573   }
574
575   GNUNET_SERVER_notification_context_add (nc, client);
576
577   struct GNUNET_GNS_ClientGetAuthMessage *sh_msg =
578     (struct GNUNET_GNS_ClientGetAuthMessage *) message;
579   
580   msg_size = ntohs(message->size);
581
582   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
583   {
584     GNUNET_break_op (0);
585     GNUNET_SERVER_receive_done (client, GNUNET_OK);
586     return;
587   }
588   
589   name = (char*)&sh_msg[1];
590
591   cah = GNUNET_malloc(sizeof(struct ClientGetAuthHandle));
592   cah->client = client;
593   cah->unique_id = sh_msg->id;
594
595   if (strlen(name) < strlen(GNUNET_GNS_TLD))
596   {
597     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
598                 "%s is too short. Returning\n", name);
599     cah->name = NULL;
600     send_get_auth_response(cah, name);
601     return;
602   }
603
604   if (strcmp(name+strlen(name)-strlen(GNUNET_GNS_TLD),
605              GNUNET_GNS_TLD) != 0)
606   {
607     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
608                 "%s is not our domain. Returning\n", name);
609     cah->name = NULL;
610     send_get_auth_response(cah, name);
611     return;
612   }
613
614   if (strcmp(name, GNUNET_GNS_TLD) == 0)
615   {
616     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
617                 "%s is us. Returning\n", name);
618     cah->name = NULL;
619     send_get_auth_response(cah, name);
620     return;
621   }
622   
623   cah->name = GNUNET_malloc(strlen(name)
624                             - strlen(GNUNET_GNS_TLD) + 1);
625   memset(cah->name, 0,
626          strlen(name)-strlen(GNUNET_GNS_TLD) + 1);
627   memcpy(cah->name, name,
628          strlen(name)-strlen(GNUNET_GNS_TLD));
629
630   /* Start delegation resolution in our namestore */
631   gns_resolver_get_authority(zone_hash, name, &send_get_auth_response, cah);
632 }
633
634
635 /**
636  * Reply to client with the result from our lookup.
637  *
638  * @param cls the closure (our client lookup handle)
639  * @param rd_count the number of records
640  * @param rd the record data
641  */
642 static void
643 send_lookup_response(void* cls,
644                      uint32_t rd_count,
645                      const struct GNUNET_NAMESTORE_RecordData *rd)
646 {
647   struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls;
648   struct GNUNET_GNS_ClientLookupResultMessage *rmsg;
649   size_t len;
650   
651   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %d results\n",
652               "LOOKUP_RESULT", rd_count);
653   
654   len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
655   rmsg = GNUNET_malloc(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
656   
657   rmsg->id = clh->unique_id;
658   rmsg->rd_count = htonl(rd_count);
659   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
660   rmsg->header.size = 
661     htons(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
662
663   GNUNET_NAMESTORE_records_serialize (rd_count, rd, len, (char*)&rmsg[1]);
664   
665   GNUNET_SERVER_notification_context_unicast (nc, clh->client,
666                                 (const struct GNUNET_MessageHeader *) rmsg,
667                                 GNUNET_NO);
668   GNUNET_SERVER_receive_done (clh->client, GNUNET_OK);
669   
670   GNUNET_free(rmsg);
671   GNUNET_free(clh->name);
672   GNUNET_free(clh);
673
674 }
675
676
677 /**
678  * Handle lookup requests from client
679  *
680  * @param cls the closure
681  * @param client the client
682  * @param message the message
683  */
684 static void
685 handle_lookup(void *cls,
686               struct GNUNET_SERVER_Client * client,
687               const struct GNUNET_MessageHeader * message)
688 {
689   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "LOOKUP");
690
691   size_t msg_size = 0;
692   size_t namelen;
693   char* name;
694   struct ClientLookupHandle *clh;
695
696   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientLookupMessage))
697   {
698     GNUNET_break_op (0);
699     GNUNET_SERVER_receive_done (client, GNUNET_OK);
700     return;
701   }
702
703   GNUNET_SERVER_notification_context_add (nc, client);
704
705   struct GNUNET_GNS_ClientLookupMessage *sh_msg =
706     (struct GNUNET_GNS_ClientLookupMessage *) message;
707   
708   msg_size = ntohs(message->size);
709
710   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
711   {
712     GNUNET_break_op (0);
713     GNUNET_SERVER_receive_done (client, GNUNET_OK);
714     return;
715   }
716   
717   name = (char*)&sh_msg[1];
718   namelen = strlen(name)+1;
719   clh = GNUNET_malloc(sizeof(struct ClientLookupHandle));
720   clh->client = client;
721   clh->name = GNUNET_malloc(namelen);
722   strcpy(clh->name, name);
723   clh->unique_id = sh_msg->id;
724   clh->type = ntohl(sh_msg->type);
725   
726   if (GNUNET_YES == auto_import_pkey)
727   {
728     gns_resolver_lookup_record(zone_hash, clh->type, name,
729                                zone_key,
730                                default_lookup_timeout,
731                                &send_lookup_response, clh);
732   }
733   else
734   {
735     gns_resolver_lookup_record(zone_hash, clh->type, name,
736                                NULL,
737                                default_lookup_timeout,
738                                &send_lookup_response, clh);
739   }
740 }
741
742
743
744 /**
745  * Process GNS requests.
746  *
747  * @param cls closure)
748  * @param server the initialized server
749  * @param c configuration to use
750  */
751 static void
752 run (void *cls, struct GNUNET_SERVER_Handle *server,
753      const struct GNUNET_CONFIGURATION_Handle *c)
754 {
755   
756   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n");
757   
758   char* keyfile;
759   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
760   unsigned long long max_parallel_bg_queries = 0;
761   unsigned long long default_lookup_timeout_secs = 0;
762
763   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
764     {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0},
765     {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0},
766     {&handle_get_authority, NULL, GNUNET_MESSAGE_TYPE_GNS_GET_AUTH, 0}
767   };
768
769   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "gns",
770                                              "ZONEKEY", &keyfile))
771   {
772     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
773                 "No private key for root zone specified!\n");
774     GNUNET_SCHEDULER_shutdown(0);
775     return;
776   }
777
778   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
779              "Using keyfile %s for root zone.\n", keyfile);
780
781   zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
782   GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
783
784   GNUNET_CRYPTO_short_hash(&pkey,
785                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
786                      &zone_hash);
787   GNUNET_free(keyfile);
788   
789   /**
790    * handle to our local namestore
791    */
792   namestore_handle = GNUNET_NAMESTORE_connect(c);
793
794   if (NULL == namestore_handle)
795   {
796     //FIXME do error handling;
797     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
798                "Failed to connect to the namestore!\n");
799     GNUNET_SCHEDULER_shutdown(0);
800     return;
801   }
802   
803   /**
804    * handle to the dht
805    */
806   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
807
808   if (NULL == dht_handle)
809   {
810     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
811   }
812
813   if (GNUNET_YES ==
814       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
815                                             "AUTO_IMPORT_PKEY"))
816   {
817     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
818                "Automatic PKEY import is enabled.\n");
819     auto_import_pkey = GNUNET_YES;
820
821   }
822
823   if (GNUNET_OK ==
824       GNUNET_CONFIGURATION_get_value_number(c, "gns",
825                                             "MAX_PARALLEL_BACKGROUND_QUERIES",
826                                             &max_parallel_bg_queries))
827   {
828     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
829                "Number of allowed parallel background queries: %d\n",
830                max_parallel_bg_queries);
831   }
832
833   if (GNUNET_OK ==
834       GNUNET_CONFIGURATION_get_value_number(c, "gns",
835                                             "DEFAULT_LOOKUP_TIMEOUT",
836                                             &default_lookup_timeout_secs))
837   {
838     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
839                "Default lookup timeout: %ds\n", default_lookup_timeout_secs);
840     default_lookup_timeout = GNUNET_TIME_relative_multiply(
841                                             GNUNET_TIME_UNIT_SECONDS,
842                                             default_lookup_timeout_secs);
843   }
844   
845   if (gns_resolver_init(namestore_handle, dht_handle, zone_hash,
846                         max_parallel_bg_queries)
847       == GNUNET_SYSERR)
848   {
849     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
850                "Unable to initialize resolver!\n");
851     GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
852     return;
853   }
854
855   if (GNUNET_YES ==
856       GNUNET_CONFIGURATION_get_value_yesno (c, "gns", "HIJACK_DNS"))
857   {
858     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
859                "DNS hijacking enabled... connecting to service.\n");
860
861     if (gns_interceptor_init(zone_hash, zone_key, c) == GNUNET_SYSERR)
862     {
863       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
864                "Failed to enable the dns interceptor!\n");
865     }
866   }
867   
868   //put_some_records(); //FIXME for testing
869   
870   /**
871    * Schedule periodic put
872    * for our records
873    * We have roughly an hour for all records;
874    */
875   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
876                                                       1);
877   zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
878
879   GNUNET_SERVER_add_handlers (server, handlers);
880   
881   //FIXME
882   //GNUNET_SERVER_disconnect_notify (server,
883   //                                 &client_disconnect_notification,
884   //                                 NULL);
885
886   nc = GNUNET_SERVER_notification_context_create (server, 1);
887
888   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
889                                 NULL);
890 }
891
892
893 /**
894  * The main function for the GNS service.
895  *
896  * @param argc number of arguments from the command line
897  * @param argv command line arguments
898  * @return 0 ok, 1 on error
899  */
900 int
901 main (int argc, char *const *argv)
902 {
903   int ret;
904
905   ret =
906       (GNUNET_OK ==
907        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
908                            NULL)) ? 0 : 1;
909   return ret;
910 }
911
912 /* end of gnunet-service-gns.c */