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