GNUnet  0.11.x
resolver_api.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2009-2018 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your 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  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
30 #include "resolver.h"
31 
32 #define LOG(kind, ...) GNUNET_log_from (kind, "util-resolver-api", __VA_ARGS__)
33 
34 #define LOG_STRERROR(kind, syscall) GNUNET_log_from_strerror (kind, \
35  "util-resolver-api", \
36  syscall)
37 
41 #define MAX_HOSTNAME 1024
42 
43 
47 static const char *loopback[] = {
48  "localhost",
49  "ip6-localnet",
50  NULL
51 };
52 
53 
58 
63 static struct GNUNET_MQ_Handle *mq;
64 
69 
74 
78 static uint32_t last_request_id;
79 
84 
89 
95 
96 
103 {
108 
113 
119 
125 
129  void *cls;
130 
135 
141 
145  int af;
146 
150  uint32_t id;
151 
159 
164 
169 
174 
178  size_t data_len;
179 };
180 
181 
189 static int
191 {
192  char *hostname;
193  struct sockaddr_in v4;
194  struct sockaddr_in6 v6;
195 
196  if (GNUNET_OK ==
197  GNUNET_CONFIGURATION_have_value (resolver_cfg,
198  "resolver",
199  "UNIXPATH"))
200  return GNUNET_OK;
201  memset (&v4, 0, sizeof(v4));
202  v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
203  v4.sin_family = AF_INET;
204 #if HAVE_SOCKADDR_IN_SIN_LEN
205  v4.sin_len = sizeof(v4);
206 #endif
207  memset (&v6, 0, sizeof(v6));
208  v6.sin6_family = AF_INET6;
209 #if HAVE_SOCKADDR_IN_SIN_LEN
210  v6.sin6_len = sizeof(v6);
211 #endif
212  if (GNUNET_OK !=
214  "resolver",
215  "HOSTNAME",
216  &hostname))
217  {
219  _ (
220  "Missing `%s' for `%s' in configuration, DNS resolution will be unavailable.\n"),
221  "HOSTNAME",
222  "resolver");
223  return GNUNET_SYSERR;
224  }
225  if ((1 == inet_pton (AF_INET, hostname, &v4)) ||
226  (1 == inet_pton (AF_INET6, hostname, &v6)))
227  {
228  GNUNET_free (hostname);
229  return GNUNET_OK;
230  }
231  for (unsigned int i = 0;
232  NULL != loopback[i];
233  i++)
234  if (0 == strcasecmp (loopback[i],
235  hostname))
236  {
237  GNUNET_free (hostname);
238  return GNUNET_OK;
239  }
241  _ (
242  "Missing `%s' or numeric IP address for `%s' of `%s' in configuration, DNS resolution will be unavailable.\n"),
243  "localhost",
244  "HOSTNAME",
245  "resolver");
246  GNUNET_free (hostname);
247  return GNUNET_SYSERR;
248 }
249 
250 
256 void
258 {
259  GNUNET_assert (NULL != cfg);
261  resolver_cfg = cfg;
262 }
263 
264 
268 void
270 {
272 
273  while (NULL != (rh = req_head))
274  {
276  GNUNET_CONTAINER_DLL_remove (req_head,
277  req_tail,
278  rh);
279  GNUNET_free (rh);
280  }
281  if (NULL != mq)
282  {
284  "Disconnecting from DNS service\n");
285  GNUNET_MQ_destroy (mq);
286  mq = NULL;
287  }
288  if (NULL != r_task)
289  {
290  GNUNET_SCHEDULER_cancel (r_task);
291  r_task = NULL;
292  }
293  if (NULL != s_task)
294  {
295  GNUNET_SCHEDULER_cancel (s_task);
296  s_task = NULL;
297  }
298 }
299 
300 
304 static void
306 {
307  (void) cls;
308  s_task = NULL;
311 }
312 
313 
317 static void
319 {
320  for (struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
321  NULL != rh;
322  rh = rh->next)
323  if (GNUNET_SYSERR != rh->was_transmitted)
324  return;
325  if (NULL != r_task)
326  {
327  GNUNET_SCHEDULER_cancel (r_task);
328  r_task = NULL;
329  }
330  if (NULL != s_task)
331  return;
333  &shutdown_task,
334  NULL);
335 }
336 
337 
346 static char *
348  const void *ip,
349  socklen_t ip_len)
350 {
351  char buf[INET6_ADDRSTRLEN];
352 
353  switch (af)
354  {
355  case AF_INET:
356  if (ip_len != sizeof(struct in_addr))
357  return NULL;
358  if (NULL ==
359  inet_ntop (AF_INET,
360  ip,
361  buf,
362  sizeof(buf)))
363  {
365  "inet_ntop");
366  return NULL;
367  }
368  break;
369 
370  case AF_INET6:
371  if (ip_len != sizeof(struct in6_addr))
372  return NULL;
373  if (NULL ==
374  inet_ntop (AF_INET6,
375  ip,
376  buf,
377  sizeof(buf)))
378  {
380  "inet_ntop");
381  return NULL;
382  }
383  break;
384 
385  default:
386  GNUNET_break (0);
387  return NULL;
388  }
389  return GNUNET_strdup (buf);
390 }
391 
392 
396 static void
397 reconnect (void);
398 
399 
408 static void
410  enum GNUNET_MQ_Error error)
411 {
412  (void) cls;
413  GNUNET_MQ_destroy (mq);
414  mq = NULL;
416  "MQ error %d, reconnecting\n",
417  error);
418  reconnect ();
419 }
420 
421 
425 static void
427 {
429  struct GNUNET_MQ_Envelope *env;
431 
432  if (NULL == mq)
433  {
434  reconnect ();
435  return;
436  }
437  if (NULL == rh)
438  {
439  /* nothing to do, release socket really soon if there is nothing
440  * else happening... */
441  if (NULL == s_task)
442  s_task =
444  &shutdown_task,
445  NULL);
446  return;
447  }
448  if (GNUNET_NO != rh->was_transmitted)
449  return; /* waiting for reply */
450  env = GNUNET_MQ_msg_extra (msg,
451  rh->data_len,
453  msg->direction = htonl (rh->direction);
454  msg->af = htonl (rh->af);
455  msg->client_id = rh->id;
456  GNUNET_memcpy (&msg[1],
457  &rh[1],
458  rh->data_len);
460  "Transmitting DNS resolution request (ID %u) to DNS service\n",
461  rh->id);
462  GNUNET_MQ_send (mq,
463  env);
465 }
466 
467 
474 static int
476  const struct GNUNET_RESOLVER_ResponseMessage *msg)
477 {
478  (void) cls;
479  (void) msg;
480 
481  /* implemented in #handle_response() for now */
482  return GNUNET_OK;
483 }
484 
485 
494 static void
496  const struct GNUNET_RESOLVER_ResponseMessage *msg)
497 {
499  uint16_t size;
500  char *nret;
501  uint32_t client_request_id = msg->client_id;
502 
503  for (; rh != NULL; rh = rh->next)
504  {
505  if (rh->id == client_request_id)
506  break;
507  }
508 
509  (void) cls;
510  if (NULL == rh)
511  {
512  /* Resolver service sent extra replies to query (after terminator)? Bad! */
513  GNUNET_break (0);
514  GNUNET_MQ_destroy (mq);
515  mq = NULL;
516  reconnect ();
517  return;
518  }
519  size = ntohs (msg->header.size);
520  if (size == sizeof(struct GNUNET_RESOLVER_ResponseMessage))
521  {
523  "Received empty response from DNS service\n");
524  /* message contains not data, just header; end of replies */
525  /* check if request was canceled */
526  if (GNUNET_SYSERR != rh->was_transmitted)
527  {
528  /* no reverse lookup was successful, return IP as string */
529  if (NULL != rh->name_callback)
530  {
531  if (GNUNET_NO == rh->received_response)
532  {
533  nret = no_resolve (rh->af,
534  &rh[1],
535  rh->data_len);
536  rh->name_callback (rh->cls, nret);
537  GNUNET_free (nret);
538  }
539  /* finally, make termination call */
540  if (GNUNET_SYSERR != rh->was_transmitted)
541  rh->name_callback (rh->cls,
542  NULL);
543  }
544  if ((NULL != rh->addr_callback) &&
546  rh->addr_callback (rh->cls,
547  NULL,
548  0);
549  }
552  process_requests ();
553  return;
554  }
555  /* return reverse lookup results to caller */
556  if (NULL != rh->name_callback)
557  {
558  const char *hostname;
559 
560  hostname = (const char *) &msg[1];
561  if (hostname[size - sizeof(struct GNUNET_RESOLVER_ResponseMessage) - 1] !=
562  '\0')
563  {
564  GNUNET_break (0);
565  if (GNUNET_SYSERR != rh->was_transmitted)
566  rh->name_callback (rh->cls,
567  NULL);
570  GNUNET_MQ_destroy (mq);
571  mq = NULL;
572  reconnect ();
573  return;
574  }
576  "Resolver returns `%s' for IP `%s'.\n",
577  hostname,
578  GNUNET_a2s ((const void *) &rh[1],
579  rh->data_len));
580  if (rh->was_transmitted != GNUNET_SYSERR)
581  rh->name_callback (rh->cls,
582  hostname);
583  rh->received_response = GNUNET_YES;
584  }
585  /* return lookup results to caller */
586  if (NULL != rh->addr_callback)
587  {
588  struct sockaddr_in v4;
589  struct sockaddr_in6 v6;
590  const struct sockaddr *sa;
591  socklen_t salen;
592  const void *ip;
593  size_t ip_len;
594 
595  ip = &msg[1];
596  ip_len = size - sizeof(struct GNUNET_RESOLVER_ResponseMessage);
597  if (ip_len == sizeof(struct in_addr))
598  {
599  memset (&v4, 0, sizeof(v4));
600  v4.sin_family = AF_INET;
601  v4.sin_addr = *(struct in_addr*) ip;
602 #if HAVE_SOCKADDR_IN_SIN_LEN
603  v4.sin_len = sizeof(v4);
604 #endif
605  salen = sizeof(v4);
606  sa = (const struct sockaddr *) &v4;
607  }
608  else if (ip_len == sizeof(struct in6_addr))
609  {
610  memset (&v6, 0, sizeof(v6));
611  v6.sin6_family = AF_INET6;
612  v6.sin6_addr = *(struct in6_addr*) ip;
613 #if HAVE_SOCKADDR_IN_SIN_LEN
614  v6.sin6_len = sizeof(v6);
615 #endif
616  salen = sizeof(v6);
617  sa = (const struct sockaddr *) &v6;
618  }
619  else
620  {
621  GNUNET_break (0);
622  if (GNUNET_SYSERR != rh->was_transmitted)
623  rh->addr_callback (rh->cls,
624  NULL,
625  0);
628  GNUNET_MQ_destroy (mq);
629  mq = NULL;
630  reconnect ();
631  return;
632  }
634  "Received IP from DNS service\n");
635  if (GNUNET_SYSERR != rh->was_transmitted)
636  rh->addr_callback (rh->cls,
637  sa,
638  salen);
639  }
640 }
641 
642 
650 static void
652 {
653  struct GNUNET_RESOLVER_RequestHandle *rh = cls;
654  struct sockaddr_in v4;
655  struct sockaddr_in6 v6;
656  const char *hostname;
657 
658  rh->task = NULL;
659  memset (&v4, 0, sizeof(v4));
660  v4.sin_family = AF_INET;
661 #if HAVE_SOCKADDR_IN_SIN_LEN
662  v4.sin_len = sizeof(v4);
663 #endif
664  memset (&v6, 0, sizeof(v6));
665  v6.sin6_family = AF_INET6;
666 #if HAVE_SOCKADDR_IN_SIN_LEN
667  v6.sin6_len = sizeof(v6);
668 #endif
669  hostname = (const char *) &rh[1];
670  if (((rh->af == AF_UNSPEC) ||
671  (rh->af == AF_INET)) &&
672  (1 == inet_pton (AF_INET,
673  hostname,
674  &v4.sin_addr)))
675  {
676  rh->addr_callback (rh->cls,
677  (const struct sockaddr *) &v4,
678  sizeof(v4));
679  if ((rh->af == AF_UNSPEC) &&
680  (GNUNET_SYSERR != rh->was_transmitted) &&
681  (1 == inet_pton (AF_INET6,
682  hostname,
683  &v6.sin6_addr)))
684  {
685  /* this can happen on some systems IF "hostname" is "localhost" */
686  rh->addr_callback (rh->cls,
687  (const struct sockaddr *) &v6,
688  sizeof(v6));
689  }
690  if (GNUNET_SYSERR != rh->was_transmitted)
691  rh->addr_callback (rh->cls,
692  NULL,
693  0);
694  GNUNET_free (rh);
695  return;
696  }
697  if (((rh->af == AF_UNSPEC) ||
698  (rh->af == AF_INET6)) &&
699  (1 == inet_pton (AF_INET6,
700  hostname,
701  &v6.sin6_addr)))
702  {
703  rh->addr_callback (rh->cls,
704  (const struct sockaddr *) &v6,
705  sizeof(v6));
706  if (GNUNET_SYSERR != rh->was_transmitted)
707  rh->addr_callback (rh->cls,
708  NULL,
709  0);
710  GNUNET_free (rh);
711  return;
712  }
713  /* why are we here? this task should not have been scheduled! */
714  GNUNET_assert (0);
715  GNUNET_free (rh);
716 }
717 
718 
726 static void
728 {
729  struct GNUNET_RESOLVER_RequestHandle *rh = cls;
730  struct sockaddr_in v4;
731  struct sockaddr_in6 v6;
732 
733  rh->task = NULL;
734  memset (&v4, 0, sizeof(v4));
735  v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
736  v4.sin_family = AF_INET;
737 #if HAVE_SOCKADDR_IN_SIN_LEN
738  v4.sin_len = sizeof(v4);
739 #endif
740  memset (&v6, 0, sizeof(v6));
741  v6.sin6_family = AF_INET6;
742 #if HAVE_SOCKADDR_IN_SIN_LEN
743  v6.sin6_len = sizeof(v6);
744 #endif
745  v6.sin6_addr = in6addr_loopback;
746  switch (rh->af)
747  {
748  case AF_INET:
749  rh->addr_callback (rh->cls,
750  (const struct sockaddr *) &v4,
751  sizeof(v4));
752  break;
753 
754  case AF_INET6:
755  rh->addr_callback (rh->cls,
756  (const struct sockaddr *) &v6,
757  sizeof(v6));
758  break;
759 
760  case AF_UNSPEC:
761  rh->addr_callback (rh->cls,
762  (const struct sockaddr *) &v6,
763  sizeof(v6));
764  rh->addr_callback (rh->cls,
765  (const struct sockaddr *) &v4,
766  sizeof(v4));
767 
768  break;
769 
770  default:
771  GNUNET_break (0);
772  break;
773  }
774  if (GNUNET_SYSERR != rh->was_transmitted)
775  rh->addr_callback (rh->cls,
776  NULL,
777  0);
779  "Finished resolving hostname `%s'.\n",
780  (const char *) &rh[1]);
781  GNUNET_free (rh);
782 }
783 
784 
790 static void
792 {
793  struct GNUNET_MQ_MessageHandler handlers[] = {
797  NULL),
799  };
800 
801  (void) cls;
802  r_task = NULL;
803  if (NULL == req_head)
804  return; /* no work pending */
806  "Trying to connect to DNS service\n");
807  mq = GNUNET_CLIENT_connect (resolver_cfg,
808  "resolver",
809  handlers,
811  NULL);
812  if (NULL == mq)
813  {
815  "Failed to connect, will try again later\n");
816  reconnect ();
817  return;
818  }
819  process_requests ();
820 }
821 
822 
826 static void
828 {
830 
831  if (NULL != r_task)
832  return;
833  GNUNET_assert (NULL == mq);
834  if (NULL != (rh = req_head))
835  {
836  switch (rh->was_transmitted)
837  {
838  case GNUNET_NO:
839  /* nothing more to do */
840  break;
841 
842  case GNUNET_YES:
843  /* disconnected, transmit again! */
845  break;
846 
847  case GNUNET_SYSERR:
848  /* request was cancelled, remove entirely */
849  GNUNET_CONTAINER_DLL_remove (req_head,
850  req_tail,
851  rh);
852  GNUNET_free (rh);
853  check_disconnect ();
854  break;
855 
856  default:
857  GNUNET_assert (0);
858  break;
859  }
860  }
862  "Will try to connect to DNS service in %s\n",
864  GNUNET_YES));
865  GNUNET_assert (NULL != resolver_cfg);
868  NULL);
870 }
871 
872 
878 static void
880 {
881  struct GNUNET_RESOLVER_RequestHandle *rh = cls;
882 
883  rh->task = NULL;
884  if (GNUNET_NO == rh->direction)
885  {
887  _ ("Timeout trying to resolve hostname `%s'.\n"),
888  (const char *) &rh[1]);
889  if (NULL != rh->addr_callback)
890  rh->addr_callback (rh->cls,
891  NULL,
892  0);
893  }
894  else
895  {
896 #if ! defined(GNUNET_CULL_LOGGING)
897  char buf[INET6_ADDRSTRLEN];
898 
900  _ ("Timeout trying to resolve IP address `%s'.\n"),
901  inet_ntop (rh->af,
902  (const void *) &rh[1],
903  buf,
904  sizeof(buf)));
905 #endif
906  if (GNUNET_NO == rh->received_response)
907  {
908  char *nret;
909 
910  nret = no_resolve (rh->af,
911  &rh[1],
912  rh->data_len);
913  if (NULL != rh->name_callback)
914  rh->name_callback (rh->cls, nret);
915  GNUNET_free (nret);
916  }
917  /* finally, make termination call */
918  if (NULL != rh->name_callback)
919  rh->name_callback (rh->cls,
920  NULL);
921  }
924  process_requests ();
925 }
926 
927 
940  int af,
943  void *callback_cls)
944 {
946  size_t slen;
947  struct in_addr v4;
948  struct in6_addr v6;
949 
950  slen = strlen (hostname) + 1;
951  if (slen + sizeof(struct GNUNET_RESOLVER_GetMessage) >=
953  {
954  GNUNET_break (0);
955  return NULL;
956  }
958  "Trying to resolve hostname `%s'.\n",
959  hostname);
960  rh = GNUNET_malloc (sizeof(struct GNUNET_RESOLVER_RequestHandle) + slen);
961  rh->af = af;
962  rh->id = ++last_request_id;
963  rh->addr_callback = callback;
964  rh->cls = callback_cls;
965  GNUNET_memcpy (&rh[1],
966  hostname,
967  slen);
968  rh->data_len = slen;
970  rh->direction = GNUNET_NO;
971  /* first, check if this is a numeric address */
972  if (((1 == inet_pton (AF_INET,
973  hostname,
974  &v4)) &&
975  ((af == AF_INET) ||
976  (af == AF_UNSPEC))) ||
977  ((1 == inet_pton (AF_INET6,
978  hostname,
979  &v6)) &&
980  ((af == AF_INET6) ||
981  (af == AF_UNSPEC))))
982  {
984  rh);
985  return rh;
986  }
987  /* then, check if this is a loopback address */
988  for (unsigned int i = 0;
989  NULL != loopback[i];
990  i++)
991  if (0 == strcasecmp (loopback[i],
992  hostname))
993  {
995  rh);
996  return rh;
997  }
998  if (GNUNET_OK != check_config ())
999  {
1000  GNUNET_free (rh);
1001  return NULL;
1002  }
1003  rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
1005  rh);
1007  req_tail,
1008  rh);
1009  rh->was_queued = GNUNET_YES;
1010  if (NULL != s_task)
1011  {
1012  GNUNET_SCHEDULER_cancel (s_task);
1013  s_task = NULL;
1014  }
1015  process_requests ();
1016  return rh;
1017 }
1018 
1019 
1028 static void
1030 {
1031  struct GNUNET_RESOLVER_RequestHandle *rh = cls;
1032  char *result;
1033 
1034  rh->task = NULL;
1035  result = no_resolve (rh->af,
1036  &rh[1],
1037  rh->data_len);
1039  "Resolver returns `%s'.\n",
1040  result);
1041  if (NULL != result)
1042  {
1043  rh->name_callback (rh->cls,
1044  result);
1045  GNUNET_free (result);
1046  }
1047  rh->name_callback (rh->cls,
1048  NULL);
1049  if (NULL != rh->task)
1050  {
1052  rh->task = NULL;
1053  }
1054  GNUNET_free (rh);
1055 }
1056 
1057 
1071 GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa,
1072  socklen_t salen,
1073  int do_resolve,
1076  void *cls)
1077 {
1078  struct GNUNET_RESOLVER_RequestHandle *rh;
1079  size_t ip_len;
1080  const void *ip;
1081 
1082  if (GNUNET_OK != check_config ())
1083  {
1085  _ ("Resolver not configured correctly.\n"));
1086  return NULL;
1087  }
1088 
1089  switch (sa->sa_family)
1090  {
1091  case AF_INET:
1092  GNUNET_assert (salen == sizeof(struct sockaddr_in));
1093  ip_len = sizeof(struct in_addr);
1094  ip = &((const struct sockaddr_in*) sa)->sin_addr;
1095  break;
1096 
1097  case AF_INET6:
1098  GNUNET_assert (salen == sizeof(struct sockaddr_in6));
1099  ip_len = sizeof(struct in6_addr);
1100  ip = &((const struct sockaddr_in6*) sa)->sin6_addr;
1101  break;
1102 
1103  default:
1104  GNUNET_break (0);
1105  return NULL;
1106  }
1107  rh = GNUNET_malloc (sizeof(struct GNUNET_RESOLVER_RequestHandle) + salen);
1108  rh->name_callback = callback;
1109  rh->cls = cls;
1110  rh->af = sa->sa_family;
1111  rh->id = ++last_request_id;
1112  rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1113  GNUNET_memcpy (&rh[1],
1114  ip,
1115  ip_len);
1116  rh->data_len = ip_len;
1117  rh->direction = GNUNET_YES;
1119  if (GNUNET_NO == do_resolve)
1120  {
1122  rh);
1123  return rh;
1124  }
1125  rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
1127  rh);
1129  req_tail,
1130  rh);
1131  rh->was_queued = GNUNET_YES;
1132  if (NULL != s_task)
1133  {
1134  GNUNET_SCHEDULER_cancel (s_task);
1135  s_task = NULL;
1136  }
1137  process_requests ();
1138  return rh;
1139 }
1140 
1141 
1147 char *
1149 {
1151 
1152  if (0 != gethostname (hostname,
1153  sizeof(hostname) - 1))
1154  {
1156  "gethostname");
1157  return NULL;
1158  }
1160  "Resolving our FQDN `%s'\n",
1161  hostname);
1162 #if HAVE_GETADDRINFO
1163  {
1164  struct addrinfo *ai;
1165  int ret;
1166  char *rval;
1167 
1168  if (0 != (ret = getaddrinfo (hostname,
1169  NULL,
1170  NULL,
1171  &ai)))
1172  {
1174  _ ("Could not resolve our FQDN: %s\n"),
1175  gai_strerror (ret));
1176  return NULL;
1177  }
1178  if (NULL != ai->ai_canonname)
1179  rval = GNUNET_strdup (ai->ai_canonname);
1180  else
1181  rval = GNUNET_strdup (hostname);
1182  freeaddrinfo (ai);
1183  return rval;
1184  }
1185 #elif HAVE_GETHOSTBYNAME2
1186  {
1187  struct hostent *host;
1188 
1189  host = gethostbyname2 (hostname,
1190  AF_INET);
1191  if (NULL == host)
1192  host = gethostbyname2 (hostname,
1193  AF_INET6);
1194  if (NULL == host)
1195  {
1197  _ ("Could not resolve our FQDN: %s\n"),
1198  hstrerror (h_errno));
1199  return NULL;
1200  }
1201  return GNUNET_strdup (host->h_name);
1202  }
1203 #elif HAVE_GETHOSTBYNAME
1204  {
1205  struct hostent *host;
1206 
1207  host = gethostbyname (hostname);
1208  if (NULL == host)
1209  {
1211  _ ("Could not resolve our FQDN: %s\n"),
1212  hstrerror (h_errno));
1213  return NULL;
1214  }
1215  return GNUNET_strdup (host->h_name);
1216  }
1217 #else
1218  /* fallback: just hope name is already FQDN */
1219  return GNUNET_strdup (hostname);
1220 #endif
1221 }
1222 
1223 
1237  void *cls)
1238 {
1240 
1241  if (0 != gethostname (hostname, sizeof(hostname) - 1))
1242  {
1244  "gethostname");
1245  return NULL;
1246  }
1248  "Resolving our hostname `%s'\n",
1249  hostname);
1250  return GNUNET_RESOLVER_ip_get (hostname,
1251  af,
1252  timeout,
1253  callback,
1254  cls);
1255 }
1256 
1257 
1266 void
1268 {
1269  if (GNUNET_NO == rh->direction)
1271  "Asked to cancel request to resolve hostname `%s'.\n",
1272  (const char *) &rh[1]);
1273  if (NULL != rh->task)
1274  {
1275  GNUNET_SCHEDULER_cancel (rh->task);
1276  rh->task = NULL;
1277  }
1278  if (GNUNET_NO == rh->was_transmitted)
1279  {
1280  if (GNUNET_YES == rh->was_queued)
1281  GNUNET_CONTAINER_DLL_remove (req_head,
1282  req_tail,
1283  rh);
1284  GNUNET_free (rh);
1285  check_disconnect ();
1286  return;
1287  }
1288  GNUNET_assert (GNUNET_YES == rh->was_transmitted);
1289  rh->was_transmitted = GNUNET_SYSERR; /* mark as cancelled */
1290  check_disconnect ();
1291 }
1292 
1293 
1294 /* end of resolver_api.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static struct GNUNET_SCHEDULER_Task * r_task
Task for reconnecting.
Definition: resolver_api.c:88
int32_t direction
GNUNET_YES to get hostname from IP, GNUNET_NO to get IP from hostname.
Definition: resolver.h:54
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
void GNUNET_RESOLVER_request_cancel(struct GNUNET_RESOLVER_RequestHandle *rh)
Cancel a request that is still pending with the resolver.
static const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration we are using.
Definition: gnunet-abd.c:36
static struct GNUNET_TIME_Relative backoff
How long should we wait to reconnect?
Definition: resolver_api.c:83
static struct GNUNET_RESOLVER_RequestHandle * req_tail
Tail of DLL of requests.
Definition: resolver_api.c:73
struct GNUNET_MQ_Handle * GNUNET_CLIENT_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *service_name, const struct GNUNET_MQ_MessageHandler *handlers, GNUNET_MQ_ErrorHandler error_handler, void *error_handler_cls)
Create a message queue to connect to a GNUnet service.
Definition: client.c:1057
static void reconnect_task(void *cls)
Now try to reconnect to the resolver service.
Definition: resolver_api.c:791
GNUNET_RESOLVER_AddressCallback addr_callback
Callback if this is an name resolution request, otherwise NULL.
Definition: resolver_api.c:118
GNUNET_MQ_Error
Error codes for the queue.
struct GNUNET_RESOLVER_RequestHandle * prev
Previous entry in DLL of requests.
Definition: resolver_api.c:112
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition: time.c:246
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static void numeric_resolution(void *cls)
We&#39;ve been asked to lookup the address for a hostname and were given a valid numeric string...
Definition: resolver_api.c:651
static const struct GNUNET_CONFIGURATION_Handle * resolver_cfg
Configuration.
Definition: resolver_api.c:57
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
#define GNUNET_NO
Definition: gnunet_common.h:78
struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_ip_get(const char *hostname, int af, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_AddressCallback callback, void *callback_cls)
Convert a string to one or more IP addresses.
Definition: resolver_api.c:939
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
static void mq_error_handler(void *cls, enum GNUNET_MQ_Error error)
Generic error handler, called with the appropriate error code and the same closure specified at the c...
Definition: resolver_api.c:409
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_hostname_get(const struct sockaddr *sa, socklen_t salen, int do_resolve, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_HostnameCallback callback, void *cls)
Get an IP address as a string.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
static void process_requests()
Process pending requests to the resolver.
Definition: resolver_api.c:426
uint32_t client_id
identifies the request this message responds to.
Definition: resolver.h:83
#define LOG_STRERROR(kind, syscall)
Definition: resolver_api.c:34
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE.
Definition: resolver.h:77
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
#define LOG(kind,...)
Definition: resolver_api.c:32
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
GNUNET_RESOLVER_HostnameCallback name_callback
Callback if this is a reverse lookup request, otherwise NULL.
Definition: resolver_api.c:124
static void numeric_reverse(void *cls)
We&#39;ve been asked to convert an address to a string without a reverse lookup, either because the clien...
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct...
Definition: gnunet_mq_lib.h:52
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1253
static const char * loopback[]
Possible hostnames for "loopback".
Definition: resolver_api.c:47
#define GNUNET_OS_get_hostname_max_length()
Get maximum string length returned by gethostname()
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
static uint32_t last_request_id
ID of the last request we sent to the service.
Definition: resolver_api.c:78
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1280
int GNUNET_CONFIGURATION_have_value(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Test if we have a value for a particular option.
char * GNUNET_RESOLVER_local_fqdn_get()
Get local fully qualified af name.
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition: strings.c:687
int af
Desired address family.
Definition: resolver_api.c:145
void(* GNUNET_RESOLVER_AddressCallback)(void *cls, const struct sockaddr *addr, socklen_t addrlen)
Function called by the resolver for each address obtained from DNS.
static char buf[2048]
static int result
Global testing status.
const char * GNUNET_a2s(const struct sockaddr *addr, socklen_t addrlen)
Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string (for printing debug messages)...
#define GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE
Response to a DNS resolution request.
struct GNUNET_TIME_Absolute timeout
When should this request time out?
Definition: resolver_api.c:134
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
Message handler for a specific message type.
struct GNUNET_RESOLVER_RequestHandle * next
Next entry in DLL of requests.
Definition: resolver_api.c:107
int GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
int was_transmitted
Has this request been transmitted to the service? GNUNET_YES if transmitted GNUNET_YES if not transmi...
Definition: resolver_api.c:158
struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_hostname_resolve(int af, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_AddressCallback callback, void *cls)
Looking our own hostname.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
static unsigned int size
Size of the "table".
Definition: peer.c:67
static struct GNUNET_TRANSPORT_AddressIdentifier * ai
Handle to the operation that publishes our address.
struct GNUNET_SCHEDULER_Task * task
Task handle for making reply callbacks in numeric lookups asynchronous, and for timeout handling...
Definition: resolver_api.c:140
Handle to a request given to the resolver.
Definition: resolver_api.c:102
static void shutdown_task(void *cls)
Task executed on system shutdown.
Definition: resolver_api.c:305
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
#define GNUNET_TIME_STD_BACKOFF(r)
Perform our standard exponential back-off calculation, starting at 1 ms and then going by a factor of...
int was_queued
Did we add this request to the queue?
Definition: resolver_api.c:163
void(* GNUNET_RESOLVER_HostnameCallback)(void *cls, const char *hostname)
Function called by the resolver for each hostname obtained from DNS.
static struct GNUNET_SCHEDULER_Task * s_task
Task ID of shutdown task; only present while we have a connection to the resolver service...
Definition: resolver_api.c:94
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message...
Handle to a message queue.
Definition: mq.c:85
int32_t af
Address family to use (AF_INET, AF_INET6 or AF_UNSPEC).
Definition: resolver.h:59
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown...
Definition: resolver_api.c:63
static void loopback_resolution(void *cls)
We&#39;ve been asked to lookup the address for a hostname and were given a variant of "loopback"...
Definition: resolver_api.c:727
static char * hostname
Our hostname; we give this to all the peers we start.
static int check_config()
Check that the resolver service runs on localhost (or equivalent).
Definition: resolver_api.c:190
configuration data
Definition: configuration.c:85
#define GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST
Request DNS resolution.
void GNUNET_RESOLVER_disconnect()
Destroy the connection to the resolver service.
Definition: resolver_api.c:269
uint32_t client_id
identifies the request and is contained in the response message.
Definition: resolver.h:65
static struct GNUNET_RESOLVER_RequestHandle * req_head
Head of DLL of requests.
Definition: resolver_api.c:68
Entry in list of pending tasks.
Definition: scheduler.c:134
static void handle_response(void *cls, const struct GNUNET_RESOLVER_ResponseMessage *msg)
Check validity of response with a hostname for a DNS lookup.
Definition: resolver_api.c:495
static struct MHD_Response * response
Our canonical response.
void * cls
Closure for the callbacks.
Definition: resolver_api.c:129
static void check_disconnect()
Consider disconnecting if we have no further requests pending.
Definition: resolver_api.c:318
Time for absolute times used by GNUnet, in microseconds.
void GNUNET_MQ_destroy(struct GNUNET_MQ_Handle *mq)
Destroy the message queue.
Definition: mq.c:824
#define GNUNET_YES
Definition: gnunet_common.h:77
static char * no_resolve(int af, const void *ip, socklen_t ip_len)
Convert IP address to string without DNS resolution.
Definition: resolver_api.c:347
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition: mq.c:353
size_t data_len
Length of the data that follows this struct.
Definition: resolver_api.c:178
Request for the resolver.
Definition: resolver.h:43
uint32_t id
Identifies the request.
Definition: resolver_api.c:150
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
int direction
Desired direction (IP to name or name to IP)
Definition: resolver_api.c:168
int received_response
GNUNET_YES if a response was received
Definition: resolver_api.c:173
void GNUNET_RESOLVER_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Create the connection to the resolver service.
Definition: resolver_api.c:257
#define GNUNET_malloc(size)
Wrapper around malloc.
static void handle_lookup_timeout(void *cls)
A DNS resolution timed out.
Definition: resolver_api.c:879
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
static int check_response(void *cls, const struct GNUNET_RESOLVER_ResponseMessage *msg)
Check validity of response with a hostname for a DNS lookup.
Definition: resolver_api.c:475
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
static void reconnect(void)
Adjust exponential back-off and reconnect to the service.
Definition: resolver_api.c:827