-fix
[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 (strcmp(name+strlen(name)-strlen(GNUNET_GNS_TLD),
487              GNUNET_GNS_TLD) != 0)
488   {
489     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
490                 "%s is not our domain. Returning\n", name);
491     csh->name = NULL;
492     send_shorten_response(csh, name);
493     return;
494   }
495   
496   csh->name = GNUNET_malloc(strlen(name)
497                             - strlen(GNUNET_GNS_TLD) + 1);
498   memset(csh->name, 0,
499          strlen(name)-strlen(GNUNET_GNS_TLD) + 1);
500   memcpy(csh->name, name,
501          strlen(name)-strlen(GNUNET_GNS_TLD));
502
503   /* Start shortening */
504   gns_resolver_shorten_name(zone_hash, name, &send_shorten_response, csh);
505 }
506
507
508 /**
509  * Send get authority response back to client
510  * 
511  * @param cls the closure containing a client get auth handle
512  * @param name the shortened name result or NULL if cannot be shortened
513  */
514 static void
515 send_get_auth_response(void *cls, const char* name)
516 {
517   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n",
518               "GET_AUTH_RESULT", name);
519   struct GNUNET_GNS_ClientGetAuthResultMessage *rmsg;
520   struct ClientGetAuthHandle *cah = (struct ClientGetAuthHandle *)cls;
521   
522   if (name == NULL)
523   {
524     name = "";
525   }
526
527   rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage)
528                        + strlen(name) + 1);
529   
530   rmsg->id = cah->unique_id;
531   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT);
532   rmsg->header.size = 
533     htons(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage) +
534           strlen(name) + 1);
535
536   strcpy((char*)&rmsg[1], name);
537
538   GNUNET_SERVER_notification_context_unicast (nc, cah->client,
539                               (const struct GNUNET_MessageHeader *) rmsg,
540                               GNUNET_NO);
541   GNUNET_SERVER_receive_done (cah->client, GNUNET_OK);
542   
543   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up handles...\n");
544
545   GNUNET_free(rmsg);
546   GNUNET_free_non_null(cah->name);
547   GNUNET_free(cah);
548
549   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done.\n");
550
551 }
552
553
554 /**
555  * Handle a get authority message from the api
556  *
557  * @param cls the closure
558  * @param client the client
559  * @param message the message
560  */
561 static void handle_get_authority(void *cls,
562                            struct GNUNET_SERVER_Client * client,
563                            const struct GNUNET_MessageHeader * message)
564 {
565   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "GET_AUTH");
566
567   size_t msg_size = 0;
568   struct ClientGetAuthHandle *cah;
569   const char* name;
570
571   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientGetAuthMessage))
572   {
573     GNUNET_break_op (0);
574     GNUNET_SERVER_receive_done (client, GNUNET_OK);
575     return;
576   }
577
578   GNUNET_SERVER_notification_context_add (nc, client);
579
580   struct GNUNET_GNS_ClientGetAuthMessage *sh_msg =
581     (struct GNUNET_GNS_ClientGetAuthMessage *) message;
582   
583   msg_size = ntohs(message->size);
584
585   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
586   {
587     GNUNET_break_op (0);
588     GNUNET_SERVER_receive_done (client, GNUNET_OK);
589     return;
590   }
591   
592   name = (char*)&sh_msg[1];
593
594   cah = GNUNET_malloc(sizeof(struct ClientGetAuthHandle));
595   cah->client = client;
596   cah->unique_id = sh_msg->id;
597
598   if (strlen(name) < strlen(GNUNET_GNS_TLD))
599   {
600     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
601                 "%s is too short. Returning\n", name);
602     cah->name = NULL;
603     send_get_auth_response(cah, name);
604     return;
605   }
606
607   if (strcmp(name+strlen(name)-strlen(GNUNET_GNS_TLD),
608              GNUNET_GNS_TLD) != 0)
609   {
610     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
611                 "%s is not our domain. Returning\n", name);
612     cah->name = NULL;
613     send_get_auth_response(cah, name);
614     return;
615   }
616
617   if (strcmp(name, GNUNET_GNS_TLD) == 0)
618   {
619     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
620                 "%s is us. Returning\n", name);
621     cah->name = NULL;
622     send_get_auth_response(cah, name);
623     return;
624   }
625   
626   cah->name = GNUNET_malloc(strlen(name)
627                             - strlen(GNUNET_GNS_TLD) + 1);
628   memset(cah->name, 0,
629          strlen(name)-strlen(GNUNET_GNS_TLD) + 1);
630   memcpy(cah->name, name,
631          strlen(name)-strlen(GNUNET_GNS_TLD));
632
633   /* Start delegation resolution in our namestore */
634   gns_resolver_get_authority(zone_hash, name, &send_get_auth_response, cah);
635 }
636
637
638 /**
639  * Reply to client with the result from our lookup.
640  *
641  * @param cls the closure (our client lookup handle)
642  * @param rd_count the number of records
643  * @param rd the record data
644  */
645 static void
646 send_lookup_response(void* cls,
647                      uint32_t rd_count,
648                      const struct GNUNET_NAMESTORE_RecordData *rd)
649 {
650   struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls;
651   struct GNUNET_GNS_ClientLookupResultMessage *rmsg;
652   size_t len;
653   
654   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %d results\n",
655               "LOOKUP_RESULT", rd_count);
656   
657   len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
658   rmsg = GNUNET_malloc(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
659   
660   rmsg->id = clh->unique_id;
661   rmsg->rd_count = htonl(rd_count);
662   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
663   rmsg->header.size = 
664     htons(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
665
666   GNUNET_NAMESTORE_records_serialize (rd_count, rd, len, (char*)&rmsg[1]);
667   
668   GNUNET_SERVER_notification_context_unicast (nc, clh->client,
669                                 (const struct GNUNET_MessageHeader *) rmsg,
670                                 GNUNET_NO);
671   GNUNET_SERVER_receive_done (clh->client, GNUNET_OK);
672   
673   GNUNET_free(rmsg);
674   GNUNET_free(clh->name);
675   GNUNET_free(clh);
676
677 }
678
679
680 /**
681  * Handle lookup requests from client
682  *
683  * @param cls the closure
684  * @param client the client
685  * @param message the message
686  */
687 static void
688 handle_lookup(void *cls,
689               struct GNUNET_SERVER_Client * client,
690               const struct GNUNET_MessageHeader * message)
691 {
692   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "LOOKUP");
693
694   size_t msg_size = 0;
695   size_t namelen;
696   char* name;
697   struct ClientLookupHandle *clh;
698
699   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientLookupMessage))
700   {
701     GNUNET_break_op (0);
702     GNUNET_SERVER_receive_done (client, GNUNET_OK);
703     return;
704   }
705
706   GNUNET_SERVER_notification_context_add (nc, client);
707
708   struct GNUNET_GNS_ClientLookupMessage *sh_msg =
709     (struct GNUNET_GNS_ClientLookupMessage *) message;
710   
711   msg_size = ntohs(message->size);
712
713   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
714   {
715     GNUNET_break_op (0);
716     GNUNET_SERVER_receive_done (client, GNUNET_OK);
717     return;
718   }
719   
720   name = (char*)&sh_msg[1];
721   namelen = strlen(name)+1;
722   clh = GNUNET_malloc(sizeof(struct ClientLookupHandle));
723   clh->client = client;
724   clh->name = GNUNET_malloc(namelen);
725   strcpy(clh->name, name);
726   clh->unique_id = sh_msg->id;
727   clh->type = ntohl(sh_msg->type);
728   
729   if (GNUNET_YES == auto_import_pkey)
730   {
731     gns_resolver_lookup_record(zone_hash, clh->type, name,
732                                zone_key,
733                                default_lookup_timeout,
734                                &send_lookup_response, clh);
735   }
736   else
737   {
738     gns_resolver_lookup_record(zone_hash, clh->type, name,
739                                NULL,
740                                default_lookup_timeout,
741                                &send_lookup_response, clh);
742   }
743 }
744
745
746
747 /**
748  * Process GNS requests.
749  *
750  * @param cls closure)
751  * @param server the initialized server
752  * @param c configuration to use
753  */
754 static void
755 run (void *cls, struct GNUNET_SERVER_Handle *server,
756      const struct GNUNET_CONFIGURATION_Handle *c)
757 {
758   
759   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n");
760   
761   char* keyfile;
762   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
763   unsigned long long max_parallel_bg_queries = 0;
764   unsigned long long default_lookup_timeout_secs = 0;
765
766   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
767     {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0},
768     {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0},
769     {&handle_get_authority, NULL, GNUNET_MESSAGE_TYPE_GNS_GET_AUTH, 0}
770   };
771
772   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "gns",
773                                              "ZONEKEY", &keyfile))
774   {
775     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
776                 "No private key for root zone specified!\n");
777     GNUNET_SCHEDULER_shutdown(0);
778     return;
779   }
780
781   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
782              "Using keyfile %s for root zone.\n", keyfile);
783
784   zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
785   GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
786
787   GNUNET_CRYPTO_short_hash(&pkey,
788                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
789                      &zone_hash);
790   GNUNET_free(keyfile);
791   
792   /**
793    * handle to our local namestore
794    */
795   namestore_handle = GNUNET_NAMESTORE_connect(c);
796
797   if (NULL == namestore_handle)
798   {
799     //FIXME do error handling;
800     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
801                "Failed to connect to the namestore!\n");
802     GNUNET_SCHEDULER_shutdown(0);
803     return;
804   }
805   
806   /**
807    * handle to the dht
808    */
809   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
810
811   if (NULL == dht_handle)
812   {
813     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
814   }
815
816   if (GNUNET_YES ==
817       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
818                                             "AUTO_IMPORT_PKEY"))
819   {
820     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
821                "Automatic PKEY import is enabled.\n");
822     auto_import_pkey = GNUNET_YES;
823
824   }
825
826   if (GNUNET_OK ==
827       GNUNET_CONFIGURATION_get_value_number(c, "gns",
828                                             "MAX_PARALLEL_BACKGROUND_QUERIES",
829                                             &max_parallel_bg_queries))
830   {
831     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
832                "Number of allowed parallel background queries: %d\n",
833                max_parallel_bg_queries);
834   }
835
836   if (GNUNET_OK ==
837       GNUNET_CONFIGURATION_get_value_number(c, "gns",
838                                             "DEFAULT_LOOKUP_TIMEOUT",
839                                             &default_lookup_timeout_secs))
840   {
841     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
842                "Default lookup timeout: %ds\n", default_lookup_timeout_secs);
843     default_lookup_timeout = GNUNET_TIME_relative_multiply(
844                                             GNUNET_TIME_UNIT_SECONDS,
845                                             default_lookup_timeout_secs);
846   }
847   
848   if (gns_resolver_init(namestore_handle, dht_handle, zone_hash,
849                         max_parallel_bg_queries)
850       == GNUNET_SYSERR)
851   {
852     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
853                "Unable to initialize resolver!\n");
854     GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
855     return;
856   }
857
858   if (GNUNET_YES ==
859       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
860                                             "HIJACK_DNS"))
861   {
862     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
863                "DNS hijacking enabled... connecting to service.\n");
864
865     if (gns_interceptor_init(zone_hash, zone_key, c) == GNUNET_SYSERR)
866     {
867       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
868                "Failed to enable the dns interceptor!\n");
869     }
870   }
871   
872   //put_some_records(); //FIXME for testing
873   
874   /**
875    * Schedule periodic put
876    * for our records
877    * We have roughly an hour for all records;
878    */
879   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
880                                                       1);
881   zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
882
883   GNUNET_SERVER_add_handlers (server, handlers);
884   
885   //FIXME
886   //GNUNET_SERVER_disconnect_notify (server,
887   //                                 &client_disconnect_notification,
888   //                                 NULL);
889
890   nc = GNUNET_SERVER_notification_context_create (server, 1);
891
892   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
893                                 NULL);
894 }
895
896
897 /**
898  * The main function for the GNS service.
899  *
900  * @param argc number of arguments from the command line
901  * @param argv command line arguments
902  * @return 0 ok, 1 on error
903  */
904 int
905 main (int argc, char *const *argv)
906 {
907   int ret;
908
909   ret =
910       (GNUNET_OK ==
911        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
912                            NULL)) ? 0 : 1;
913   return ret;
914 }
915
916 /* end of gnunet-service-gns.c */