-parallel background lookups
[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 name the shortened name result or NULL if cannot be shortened
391  * @param csh the handle to the shorten request
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 name the shortened name result or NULL if cannot be shortened
504  * @param cah the handle to the get authority request
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 rh the request handle of the lookup
635  * @param rd_count the number of records
636  * @param rd the record data
637  */
638 static void
639 send_lookup_response(void* cls,
640                      uint32_t rd_count,
641                      const struct GNUNET_NAMESTORE_RecordData *rd)
642 {
643   struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls;
644   struct GNUNET_GNS_ClientLookupResultMessage *rmsg;
645   size_t len;
646   
647   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %d results\n",
648               "LOOKUP_RESULT", rd_count);
649   
650   len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
651   rmsg = GNUNET_malloc(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
652   
653   rmsg->id = clh->unique_id;
654   rmsg->rd_count = htonl(rd_count);
655   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
656   rmsg->header.size = 
657     htons(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
658
659   GNUNET_NAMESTORE_records_serialize (rd_count, rd, len, (char*)&rmsg[1]);
660   
661   GNUNET_SERVER_notification_context_unicast (nc, clh->client,
662                                 (const struct GNUNET_MessageHeader *) rmsg,
663                                 GNUNET_NO);
664   GNUNET_SERVER_receive_done (clh->client, GNUNET_OK);
665   
666   GNUNET_free(rmsg);
667   GNUNET_free(clh->name);
668   GNUNET_free(clh);
669
670 }
671
672
673 /**
674  * Handle lookup requests from client
675  *
676  * @param cls the closure
677  * @param client the client
678  * @param message the message
679  */
680 static void
681 handle_lookup(void *cls,
682               struct GNUNET_SERVER_Client * client,
683               const struct GNUNET_MessageHeader * message)
684 {
685   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "LOOKUP");
686
687   size_t msg_size = 0;
688   size_t namelen;
689   char* name;
690   struct ClientLookupHandle *clh;
691
692   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientLookupMessage))
693   {
694     GNUNET_break_op (0);
695     GNUNET_SERVER_receive_done (client, GNUNET_OK);
696     return;
697   }
698
699   GNUNET_SERVER_notification_context_add (nc, client);
700
701   struct GNUNET_GNS_ClientLookupMessage *sh_msg =
702     (struct GNUNET_GNS_ClientLookupMessage *) message;
703   
704   msg_size = ntohs(message->size);
705
706   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
707   {
708     GNUNET_break_op (0);
709     GNUNET_SERVER_receive_done (client, GNUNET_OK);
710     return;
711   }
712   
713   name = (char*)&sh_msg[1];
714   namelen = strlen(name)+1;
715   clh = GNUNET_malloc(sizeof(struct ClientLookupHandle));
716   clh->client = client;
717   clh->name = GNUNET_malloc(namelen);
718   strcpy(clh->name, name);
719   clh->unique_id = sh_msg->id;
720   clh->type = ntohl(sh_msg->type);
721   
722   if (GNUNET_YES == auto_import_pkey)
723   {
724     gns_resolver_lookup_record(zone_hash, clh->type, name,
725                                zone_key,
726                                default_lookup_timeout,
727                                &send_lookup_response, clh);
728   }
729   else
730   {
731     gns_resolver_lookup_record(zone_hash, clh->type, name,
732                                NULL,
733                                default_lookup_timeout,
734                                &send_lookup_response, clh);
735   }
736 }
737
738
739
740 /**
741  * Process GNS requests.
742  *
743  * @param cls closure)
744  * @param server the initialized server
745  * @param c configuration to use
746  */
747 static void
748 run (void *cls, struct GNUNET_SERVER_Handle *server,
749      const struct GNUNET_CONFIGURATION_Handle *c)
750 {
751   
752   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n");
753   
754   char* keyfile;
755   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
756   unsigned long long max_parallel_bg_queries = 0;
757   unsigned long long default_lookup_timeout_secs = 0;
758
759   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
760     {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0},
761     {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0},
762     {&handle_get_authority, NULL, GNUNET_MESSAGE_TYPE_GNS_GET_AUTH, 0}
763   };
764
765   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "gns",
766                                              "ZONEKEY", &keyfile))
767   {
768     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
769                 "No private key for root zone specified!\n");
770     GNUNET_SCHEDULER_shutdown(0);
771     return;
772   }
773
774   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
775              "Using keyfile %s for root zone.\n", keyfile);
776
777   zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
778   GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
779
780   GNUNET_CRYPTO_short_hash(&pkey,
781                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
782                      &zone_hash);
783   GNUNET_free(keyfile);
784   
785   /**
786    * handle to our local namestore
787    */
788   namestore_handle = GNUNET_NAMESTORE_connect(c);
789
790   if (NULL == namestore_handle)
791   {
792     //FIXME do error handling;
793     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
794                "Failed to connect to the namestore!\n");
795     GNUNET_SCHEDULER_shutdown(0);
796     return;
797   }
798   
799   /**
800    * handle to the dht
801    */
802   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
803
804   if (NULL == dht_handle)
805   {
806     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
807   }
808
809   if (GNUNET_YES ==
810       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
811                                             "AUTO_IMPORT_PKEY"))
812   {
813     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
814                "Automatic PKEY import is enabled.\n");
815     auto_import_pkey = GNUNET_YES;
816
817   }
818
819   if (GNUNET_OK ==
820       GNUNET_CONFIGURATION_get_value_number(c, "gns",
821                                             "MAX_PARALLEL_BACKGROUND_QUERIES",
822                                             &max_parallel_bg_queries))
823   {
824     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
825                "Number of allowed parallel background queries: %d\n",
826                max_parallel_bg_queries);
827   }
828
829   if (GNUNET_OK ==
830       GNUNET_CONFIGURATION_get_value_number(c, "gns",
831                                             "DEFAULT_LOOKUP_TIMEOUT",
832                                             &default_lookup_timeout_secs))
833   {
834     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
835                "Default lookup timeout: %ds\n", default_lookup_timeout_secs);
836     default_lookup_timeout = GNUNET_TIME_relative_multiply(
837                                             GNUNET_TIME_UNIT_SECONDS,
838                                             default_lookup_timeout_secs);
839   }
840   
841   if (gns_resolver_init(namestore_handle, dht_handle, zone_hash,
842                         max_parallel_bg_queries)
843       == GNUNET_SYSERR)
844   {
845     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
846                "Unable to initialize resolver!\n");
847     GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
848     return;
849   }
850
851   if (GNUNET_YES ==
852       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
853                                             "HIJACK_DNS"))
854   {
855     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
856                "DNS hijacking enabled... connecting to service.\n");
857
858     if (gns_interceptor_init(zone_hash, zone_key, c) == GNUNET_SYSERR)
859     {
860       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
861                "Failed to enable the dns interceptor!\n");
862     }
863   }
864   
865   //put_some_records(); //FIXME for testing
866   
867   /**
868    * Schedule periodic put
869    * for our records
870    * We have roughly an hour for all records;
871    */
872   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
873                                                       1);
874   zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
875
876   GNUNET_SERVER_add_handlers (server, handlers);
877   
878   //FIXME
879   //GNUNET_SERVER_disconnect_notify (server,
880   //                                 &client_disconnect_notification,
881   //                                 NULL);
882
883   nc = GNUNET_SERVER_notification_context_create (server, 1);
884
885   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
886                                 NULL);
887 }
888
889
890 /**
891  * The main function for the GNS service.
892  *
893  * @param argc number of arguments from the command line
894  * @param argv command line arguments
895  * @return 0 ok, 1 on error
896  */
897 int
898 main (int argc, char *const *argv)
899 {
900   int ret;
901
902   ret =
903       (GNUNET_OK ==
904        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
905                            NULL)) ? 0 : 1;
906   return ret;
907 }
908
909 /* end of gnunet-service-gns.c */