GNUnet  0.10.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, "util-resolver-api", syscall)
35 
39 #define MAX_HOSTNAME 1024
40 
41 
45 static const char *loopback[] = {
46  "localhost",
47  "ip6-localnet",
48  NULL
49 };
50 
51 
56 
61 static struct GNUNET_MQ_Handle *mq;
62 
67 
72 
76 static uint32_t last_request_id;
77 
82 
87 
93 
94 
105 
110 
116 
122 
126  void *cls;
127 
132 
138 
142  int af;
143 
147  uint32_t id;
148 
156 
161 
166 
171 
175  size_t data_len;
176 };
177 
178 
186 static int
188 {
189  char *hostname;
190  struct sockaddr_in v4;
191  struct sockaddr_in6 v6;
192 
193  if (GNUNET_OK ==
194  GNUNET_CONFIGURATION_have_value(resolver_cfg,
195  "resolver",
196  "UNIXPATH"))
197  return GNUNET_OK;
198  memset(&v4, 0, sizeof(v4));
199  v4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
200  v4.sin_family = AF_INET;
201 #if HAVE_SOCKADDR_IN_SIN_LEN
202  v4.sin_len = sizeof(v4);
203 #endif
204  memset(&v6, 0, sizeof(v6));
205  v6.sin6_family = AF_INET6;
206 #if HAVE_SOCKADDR_IN_SIN_LEN
207  v6.sin6_len = sizeof(v6);
208 #endif
209  if (GNUNET_OK !=
211  "resolver",
212  "HOSTNAME",
213  &hostname))
214  {
216  _("Missing `%s' for `%s' in configuration, DNS resolution will be unavailable.\n"),
217  "HOSTNAME",
218  "resolver");
219  return GNUNET_SYSERR;
220  }
221  if ((1 == inet_pton(AF_INET, hostname, &v4)) ||
222  (1 == inet_pton(AF_INET6, hostname, &v6)))
223  {
224  GNUNET_free(hostname);
225  return GNUNET_OK;
226  }
227  for (unsigned int i = 0;
228  NULL != loopback[i];
229  i++)
230  if (0 == strcasecmp(loopback[i],
231  hostname))
232  {
233  GNUNET_free(hostname);
234  return GNUNET_OK;
235  }
237  _("Missing `%s' or numeric IP address for `%s' of `%s' in configuration, DNS resolution will be unavailable.\n"),
238  "localhost",
239  "HOSTNAME",
240  "resolver");
241  GNUNET_free(hostname);
242  return GNUNET_SYSERR;
243 }
244 
245 
251 void
253 {
254  GNUNET_assert(NULL != cfg);
256  resolver_cfg = cfg;
257 }
258 
259 
263 void
265 {
267 
268  while (NULL != (rh = req_head))
269  {
272  req_tail,
273  rh);
274  GNUNET_free(rh);
275  }
276  if (NULL != mq)
277  {
279  "Disconnecting from DNS service\n");
280  GNUNET_MQ_destroy(mq);
281  mq = NULL;
282  }
283  if (NULL != r_task)
284  {
285  GNUNET_SCHEDULER_cancel(r_task);
286  r_task = NULL;
287  }
288  if (NULL != s_task)
289  {
290  GNUNET_SCHEDULER_cancel(s_task);
291  s_task = NULL;
292  }
293 }
294 
295 
299 static void
301 {
302  (void)cls;
303  s_task = NULL;
306 }
307 
308 
312 static void
314 {
315  for (struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
316  NULL != rh;
317  rh = rh->next)
318  if (GNUNET_SYSERR != rh->was_transmitted)
319  return;
320  if (NULL != r_task)
321  {
322  GNUNET_SCHEDULER_cancel(r_task);
323  r_task = NULL;
324  }
325  if (NULL != s_task)
326  return;
328  &shutdown_task,
329  NULL);
330 }
331 
332 
341 static char *
343  const void *ip,
344  socklen_t ip_len)
345 {
346  char buf[INET6_ADDRSTRLEN];
347 
348  switch (af)
349  {
350  case AF_INET:
351  if (ip_len != sizeof(struct in_addr))
352  return NULL;
353  if (NULL ==
354  inet_ntop(AF_INET,
355  ip,
356  buf,
357  sizeof(buf)))
358  {
360  "inet_ntop");
361  return NULL;
362  }
363  break;
364 
365  case AF_INET6:
366  if (ip_len != sizeof(struct in6_addr))
367  return NULL;
368  if (NULL ==
369  inet_ntop(AF_INET6,
370  ip,
371  buf,
372  sizeof(buf)))
373  {
375  "inet_ntop");
376  return NULL;
377  }
378  break;
379 
380  default:
381  GNUNET_break(0);
382  return NULL;
383  }
384  return GNUNET_strdup(buf);
385 }
386 
387 
391 static void
392 reconnect(void);
393 
394 
403 static void
405  enum GNUNET_MQ_Error error)
406 {
407  (void)cls;
408  GNUNET_MQ_destroy(mq);
409  mq = NULL;
411  "MQ error %d, reconnecting\n",
412  error);
413  reconnect();
414 }
415 
416 
420 static void
422 {
424  struct GNUNET_MQ_Envelope *env;
426 
427  if (NULL == mq)
428  {
429  reconnect();
430  return;
431  }
432  if (NULL == rh)
433  {
434  /* nothing to do, release socket really soon if there is nothing
435  * else happening... */
436  if (NULL == s_task)
437  s_task =
439  &shutdown_task,
440  NULL);
441  return;
442  }
443  if (GNUNET_NO != rh->was_transmitted)
444  return; /* waiting for reply */
445  env = GNUNET_MQ_msg_extra(msg,
446  rh->data_len,
448  msg->direction = htonl(rh->direction);
449  msg->af = htonl(rh->af);
450  msg->client_id = rh->id;
451  GNUNET_memcpy(&msg[1],
452  &rh[1],
453  rh->data_len);
455  "Transmitting DNS resolution request (ID %u) to DNS service\n",
456  rh->id);
457  GNUNET_MQ_send(mq,
458  env);
460 }
461 
462 
469 static int
471  const struct GNUNET_RESOLVER_ResponseMessage *msg)
472 {
473  (void)cls;
474  (void)msg;
475 
476  /* implemented in #handle_response() for now */
477  return GNUNET_OK;
478 }
479 
480 
489 static void
491  const struct GNUNET_RESOLVER_ResponseMessage *msg)
492 {
494  uint16_t size;
495  char *nret;
496  uint32_t client_request_id = msg->client_id;
497 
498  for (; rh != NULL; rh = rh->next)
499  {
500  if (rh->id == client_request_id)
501  break;
502  }
503 
504  (void)cls;
505  if (NULL == rh)
506  {
507  /* Resolver service sent extra replies to query (after terminator)? Bad! */
508  GNUNET_break(0);
509  GNUNET_MQ_destroy(mq);
510  mq = NULL;
511  reconnect();
512  return;
513  }
514  size = ntohs(msg->header.size);
515  if (size == sizeof(struct GNUNET_RESOLVER_ResponseMessage))
516  {
518  "Received empty response from DNS service\n");
519  /* message contains not data, just header; end of replies */
520  /* check if request was canceled */
521  if (GNUNET_SYSERR != rh->was_transmitted)
522  {
523  /* no reverse lookup was successful, return IP as string */
524  if (NULL != rh->name_callback)
525  {
526  if (GNUNET_NO == rh->received_response)
527  {
528  nret = no_resolve(rh->af,
529  &rh[1],
530  rh->data_len);
531  rh->name_callback(rh->cls, nret);
532  GNUNET_free(nret);
533  }
534  /* finally, make termination call */
535  if (GNUNET_SYSERR != rh->was_transmitted)
536  rh->name_callback(rh->cls,
537  NULL);
538  }
539  if ((NULL != rh->addr_callback) &&
541  rh->addr_callback(rh->cls,
542  NULL,
543  0);
544  }
548  return;
549  }
550  /* return reverse lookup results to caller */
551  if (NULL != rh->name_callback)
552  {
553  const char *hostname;
554 
555  hostname = (const char *)&msg[1];
556  if (hostname[size - sizeof(struct GNUNET_RESOLVER_ResponseMessage) - 1] != '\0')
557  {
558  GNUNET_break(0);
559  if (GNUNET_SYSERR != rh->was_transmitted)
560  rh->name_callback(rh->cls,
561  NULL);
564  GNUNET_MQ_destroy(mq);
565  mq = NULL;
566  reconnect();
567  return;
568  }
570  "Resolver returns `%s' for IP `%s'.\n",
571  hostname,
572  GNUNET_a2s((const void *)&rh[1],
573  rh->data_len));
574  if (rh->was_transmitted != GNUNET_SYSERR)
575  rh->name_callback(rh->cls,
576  hostname);
577  rh->received_response = GNUNET_YES;
578  }
579  /* return lookup results to caller */
580  if (NULL != rh->addr_callback)
581  {
582  struct sockaddr_in v4;
583  struct sockaddr_in6 v6;
584  const struct sockaddr *sa;
585  socklen_t salen;
586  const void *ip;
587  size_t ip_len;
588 
589  ip = &msg[1];
590  ip_len = size - sizeof(struct GNUNET_RESOLVER_ResponseMessage);
591  if (ip_len == sizeof(struct in_addr))
592  {
593  memset(&v4, 0, sizeof(v4));
594  v4.sin_family = AF_INET;
595  v4.sin_addr = *(struct in_addr*)ip;
596 #if HAVE_SOCKADDR_IN_SIN_LEN
597  v4.sin_len = sizeof(v4);
598 #endif
599  salen = sizeof(v4);
600  sa = (const struct sockaddr *)&v4;
601  }
602  else if (ip_len == sizeof(struct in6_addr))
603  {
604  memset(&v6, 0, sizeof(v6));
605  v6.sin6_family = AF_INET6;
606  v6.sin6_addr = *(struct in6_addr*)ip;
607 #if HAVE_SOCKADDR_IN_SIN_LEN
608  v6.sin6_len = sizeof(v6);
609 #endif
610  salen = sizeof(v6);
611  sa = (const struct sockaddr *)&v6;
612  }
613  else
614  {
615  GNUNET_break(0);
616  if (GNUNET_SYSERR != rh->was_transmitted)
617  rh->addr_callback(rh->cls,
618  NULL,
619  0);
622  GNUNET_MQ_destroy(mq);
623  mq = NULL;
624  reconnect();
625  return;
626  }
628  "Received IP from DNS service\n");
629  if (GNUNET_SYSERR != rh->was_transmitted)
630  rh->addr_callback(rh->cls,
631  sa,
632  salen);
633  }
634 }
635 
636 
644 static void
646 {
647  struct GNUNET_RESOLVER_RequestHandle *rh = cls;
648  struct sockaddr_in v4;
649  struct sockaddr_in6 v6;
650  const char *hostname;
651 
652  rh->task = NULL;
653  memset(&v4, 0, sizeof(v4));
654  v4.sin_family = AF_INET;
655 #if HAVE_SOCKADDR_IN_SIN_LEN
656  v4.sin_len = sizeof(v4);
657 #endif
658  memset(&v6, 0, sizeof(v6));
659  v6.sin6_family = AF_INET6;
660 #if HAVE_SOCKADDR_IN_SIN_LEN
661  v6.sin6_len = sizeof(v6);
662 #endif
663  hostname = (const char *)&rh[1];
664  if (((rh->af == AF_UNSPEC) ||
665  (rh->af == AF_INET)) &&
666  (1 == inet_pton(AF_INET,
667  hostname,
668  &v4.sin_addr)))
669  {
670  rh->addr_callback(rh->cls,
671  (const struct sockaddr *)&v4,
672  sizeof(v4));
673  if ((rh->af == AF_UNSPEC) &&
674  (GNUNET_SYSERR != rh->was_transmitted) &&
675  (1 == inet_pton(AF_INET6,
676  hostname,
677  &v6.sin6_addr)))
678  {
679  /* this can happen on some systems IF "hostname" is "localhost" */
680  rh->addr_callback(rh->cls,
681  (const struct sockaddr *)&v6,
682  sizeof(v6));
683  }
684  if (GNUNET_SYSERR != rh->was_transmitted)
685  rh->addr_callback(rh->cls,
686  NULL,
687  0);
688  GNUNET_free(rh);
689  return;
690  }
691  if (((rh->af == AF_UNSPEC) ||
692  (rh->af == AF_INET6)) &&
693  (1 == inet_pton(AF_INET6,
694  hostname,
695  &v6.sin6_addr)))
696  {
697  rh->addr_callback(rh->cls,
698  (const struct sockaddr *)&v6,
699  sizeof(v6));
700  if (GNUNET_SYSERR != rh->was_transmitted)
701  rh->addr_callback(rh->cls,
702  NULL,
703  0);
704  GNUNET_free(rh);
705  return;
706  }
707  /* why are we here? this task should not have been scheduled! */
708  GNUNET_assert(0);
709  GNUNET_free(rh);
710 }
711 
712 
720 static void
722 {
723  struct GNUNET_RESOLVER_RequestHandle *rh = cls;
724  struct sockaddr_in v4;
725  struct sockaddr_in6 v6;
726 
727  rh->task = NULL;
728  memset(&v4, 0, sizeof(v4));
729  v4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
730  v4.sin_family = AF_INET;
731 #if HAVE_SOCKADDR_IN_SIN_LEN
732  v4.sin_len = sizeof(v4);
733 #endif
734  memset(&v6, 0, sizeof(v6));
735  v6.sin6_family = AF_INET6;
736 #if HAVE_SOCKADDR_IN_SIN_LEN
737  v6.sin6_len = sizeof(v6);
738 #endif
739  v6.sin6_addr = in6addr_loopback;
740  switch (rh->af)
741  {
742  case AF_INET:
743  rh->addr_callback(rh->cls,
744  (const struct sockaddr *)&v4,
745  sizeof(v4));
746  break;
747 
748  case AF_INET6:
749  rh->addr_callback(rh->cls,
750  (const struct sockaddr *)&v6,
751  sizeof(v6));
752  break;
753 
754  case AF_UNSPEC:
755  rh->addr_callback(rh->cls,
756  (const struct sockaddr *)&v6,
757  sizeof(v6));
758  rh->addr_callback(rh->cls,
759  (const struct sockaddr *)&v4,
760  sizeof(v4));
761 
762  break;
763 
764  default:
765  GNUNET_break(0);
766  break;
767  }
768  if (GNUNET_SYSERR != rh->was_transmitted)
769  rh->addr_callback(rh->cls,
770  NULL,
771  0);
773  "Finished resolving hostname `%s'.\n",
774  (const char *)&rh[1]);
775  GNUNET_free(rh);
776 }
777 
778 
784 static void
786 {
787  struct GNUNET_MQ_MessageHandler handlers[] = {
791  NULL),
793  };
794 
795  (void)cls;
796  r_task = NULL;
797  if (NULL == req_head)
798  return; /* no work pending */
800  "Trying to connect to DNS service\n");
801  mq = GNUNET_CLIENT_connect(resolver_cfg,
802  "resolver",
803  handlers,
805  NULL);
806  if (NULL == mq)
807  {
809  "Failed to connect, will try again later\n");
810  reconnect();
811  return;
812  }
814 }
815 
816 
820 static void
822 {
824 
825  if (NULL != r_task)
826  return;
827  GNUNET_assert(NULL == mq);
828  if (NULL != (rh = req_head))
829  {
830  switch (rh->was_transmitted)
831  {
832  case GNUNET_NO:
833  /* nothing more to do */
834  break;
835 
836  case GNUNET_YES:
837  /* disconnected, transmit again! */
839  break;
840 
841  case GNUNET_SYSERR:
842  /* request was cancelled, remove entirely */
844  req_tail,
845  rh);
846  GNUNET_free(rh);
848  break;
849 
850  default:
851  GNUNET_assert(0);
852  break;
853  }
854  }
856  "Will try to connect to DNS service in %s\n",
858  GNUNET_YES));
859  GNUNET_assert(NULL != resolver_cfg);
862  NULL);
864 }
865 
866 
872 static void
874 {
875  struct GNUNET_RESOLVER_RequestHandle *rh = cls;
876 
877  rh->task = NULL;
878  if (GNUNET_NO == rh->direction)
879  {
881  _("Timeout trying to resolve hostname `%s'.\n"),
882  (const char *)&rh[1]);
883  if (NULL != rh->addr_callback)
884  rh->addr_callback(rh->cls,
885  NULL,
886  0);
887  }
888  else
889  {
890 #if !defined(GNUNET_CULL_LOGGING)
891  char buf[INET6_ADDRSTRLEN];
892 
894  _("Timeout trying to resolve IP address `%s'.\n"),
895  inet_ntop(rh->af,
896  (const void *)&rh[1],
897  buf,
898  sizeof(buf)));
899 #endif
900  if (GNUNET_NO == rh->received_response)
901  {
902  char *nret;
903 
904  nret = no_resolve(rh->af,
905  &rh[1],
906  rh->data_len);
907  if (NULL != rh->name_callback)
908  rh->name_callback(rh->cls, nret);
909  GNUNET_free(nret);
910  }
911  /* finally, make termination call */
912  if (NULL != rh->name_callback)
913  rh->name_callback(rh->cls,
914  NULL);
915  }
919 }
920 
921 
934  int af,
937  void *callback_cls)
938 {
940  size_t slen;
941  struct in_addr v4;
942  struct in6_addr v6;
943 
944  slen = strlen(hostname) + 1;
945  if (slen + sizeof(struct GNUNET_RESOLVER_GetMessage) >=
947  {
948  GNUNET_break(0);
949  return NULL;
950  }
952  "Trying to resolve hostname `%s'.\n",
953  hostname);
954  rh = GNUNET_malloc(sizeof(struct GNUNET_RESOLVER_RequestHandle) + slen);
955  rh->af = af;
956  rh->id = ++last_request_id;
957  rh->addr_callback = callback;
958  rh->cls = callback_cls;
959  GNUNET_memcpy(&rh[1],
960  hostname,
961  slen);
962  rh->data_len = slen;
964  rh->direction = GNUNET_NO;
965  /* first, check if this is a numeric address */
966  if (((1 == inet_pton(AF_INET,
967  hostname,
968  &v4)) &&
969  ((af == AF_INET) ||
970  (af == AF_UNSPEC))) ||
971  ((1 == inet_pton(AF_INET6,
972  hostname,
973  &v6)) &&
974  ((af == AF_INET6) ||
975  (af == AF_UNSPEC))))
976  {
978  rh);
979  return rh;
980  }
981  /* then, check if this is a loopback address */
982  for (unsigned int i = 0;
983  NULL != loopback[i];
984  i++)
985  if (0 == strcasecmp(loopback[i],
986  hostname))
987  {
989  rh);
990  return rh;
991  }
992  if (GNUNET_OK != check_config())
993  {
994  GNUNET_free(rh);
995  return NULL;
996  }
997  rh->task = GNUNET_SCHEDULER_add_delayed(timeout,
999  rh);
1001  req_tail,
1002  rh);
1003  rh->was_queued = GNUNET_YES;
1004  if (NULL != s_task)
1005  {
1006  GNUNET_SCHEDULER_cancel(s_task);
1007  s_task = NULL;
1008  }
1009  process_requests();
1010  return rh;
1011 }
1012 
1013 
1022 static void
1024 {
1025  struct GNUNET_RESOLVER_RequestHandle *rh = cls;
1026  char *result;
1027 
1028  rh->task = NULL;
1029  result = no_resolve(rh->af,
1030  &rh[1],
1031  rh->data_len);
1033  "Resolver returns `%s'.\n",
1034  result);
1035  if (NULL != result)
1036  {
1037  rh->name_callback(rh->cls,
1038  result);
1039  GNUNET_free(result);
1040  }
1041  rh->name_callback(rh->cls,
1042  NULL);
1043  if (NULL != rh->task)
1044  {
1046  rh->task = NULL;
1047  }
1048  GNUNET_free(rh);
1049 }
1050 
1051 
1065 GNUNET_RESOLVER_hostname_get(const struct sockaddr *sa,
1066  socklen_t salen,
1067  int do_resolve,
1070  void *cls)
1071 {
1072  struct GNUNET_RESOLVER_RequestHandle *rh;
1073  size_t ip_len;
1074  const void *ip;
1075 
1076  if (GNUNET_OK != check_config())
1077  {
1079  _("Resolver not configured correctly.\n"));
1080  return NULL;
1081  }
1082 
1083  switch (sa->sa_family)
1084  {
1085  case AF_INET:
1086  GNUNET_assert(salen == sizeof(struct sockaddr_in));
1087  ip_len = sizeof(struct in_addr);
1088  ip = &((const struct sockaddr_in*)sa)->sin_addr;
1089  break;
1090 
1091  case AF_INET6:
1092  GNUNET_assert(salen == sizeof(struct sockaddr_in6));
1093  ip_len = sizeof(struct in6_addr);
1094  ip = &((const struct sockaddr_in6*)sa)->sin6_addr;
1095  break;
1096 
1097  default:
1098  GNUNET_break(0);
1099  return NULL;
1100  }
1101  rh = GNUNET_malloc(sizeof(struct GNUNET_RESOLVER_RequestHandle) + salen);
1102  rh->name_callback = callback;
1103  rh->cls = cls;
1104  rh->af = sa->sa_family;
1105  rh->id = ++last_request_id;
1107  GNUNET_memcpy(&rh[1],
1108  ip,
1109  ip_len);
1110  rh->data_len = ip_len;
1111  rh->direction = GNUNET_YES;
1113  if (GNUNET_NO == do_resolve)
1114  {
1116  rh);
1117  return rh;
1118  }
1119  rh->task = GNUNET_SCHEDULER_add_delayed(timeout,
1121  rh);
1123  req_tail,
1124  rh);
1125  rh->was_queued = GNUNET_YES;
1126  if (NULL != s_task)
1127  {
1128  GNUNET_SCHEDULER_cancel(s_task);
1129  s_task = NULL;
1130  }
1131  process_requests();
1132  return rh;
1133 }
1134 
1135 
1141 char *
1143 {
1145 
1146  if (0 != gethostname(hostname,
1147  sizeof(hostname) - 1))
1148  {
1150  "gethostname");
1151  return NULL;
1152  }
1154  "Resolving our FQDN `%s'\n",
1155  hostname);
1156 #if HAVE_GETADDRINFO
1157  {
1158  struct addrinfo *ai;
1159  int ret;
1160  char *rval;
1161 
1162  if (0 != (ret = getaddrinfo(hostname,
1163  NULL,
1164  NULL,
1165  &ai)))
1166  {
1168  _("Could not resolve our FQDN: %s\n"),
1169  gai_strerror(ret));
1170  return NULL;
1171  }
1172  if (NULL != ai->ai_canonname)
1173  rval = GNUNET_strdup(ai->ai_canonname);
1174  else
1175  rval = GNUNET_strdup(hostname);
1176  freeaddrinfo(ai);
1177  return rval;
1178  }
1179 #elif HAVE_GETHOSTBYNAME2
1180  {
1181  struct hostent *host;
1182 
1183  host = gethostbyname2(hostname,
1184  AF_INET);
1185  if (NULL == host)
1186  host = gethostbyname2(hostname,
1187  AF_INET6);
1188  if (NULL == host)
1189  {
1191  _("Could not resolve our FQDN: %s\n"),
1192  hstrerror(h_errno));
1193  return NULL;
1194  }
1195  return GNUNET_strdup(host->h_name);
1196  }
1197 #elif HAVE_GETHOSTBYNAME
1198  {
1199  struct hostent *host;
1200 
1201  host = gethostbyname(hostname);
1202  if (NULL == host)
1203  {
1205  _("Could not resolve our FQDN: %s\n"),
1206  hstrerror(h_errno));
1207  return NULL;
1208  }
1209  return GNUNET_strdup(host->h_name);
1210  }
1211 #else
1212  /* fallback: just hope name is already FQDN */
1213  return GNUNET_strdup(hostname);
1214 #endif
1215 }
1216 
1217 
1231  void *cls)
1232 {
1234 
1235  if (0 != gethostname(hostname, sizeof(hostname) - 1))
1236  {
1238  "gethostname");
1239  return NULL;
1240  }
1242  "Resolving our hostname `%s'\n",
1243  hostname);
1244  return GNUNET_RESOLVER_ip_get(hostname,
1245  af,
1246  timeout,
1247  callback,
1248  cls);
1249 }
1250 
1251 
1260 void
1262 {
1263  if (GNUNET_NO == rh->direction)
1265  "Asked to cancel request to resolve hostname `%s'.\n",
1266  (const char *)&rh[1]);
1267  if (NULL != rh->task)
1268  {
1269  GNUNET_SCHEDULER_cancel(rh->task);
1270  rh->task = NULL;
1271  }
1272  if (GNUNET_NO == rh->was_transmitted)
1273  {
1274  if (GNUNET_YES == rh->was_queued)
1275  GNUNET_CONTAINER_DLL_remove(req_head,
1276  req_tail,
1277  rh);
1278  GNUNET_free(rh);
1279  check_disconnect();
1280  return;
1281  }
1282  GNUNET_assert(GNUNET_YES == rh->was_transmitted);
1283  rh->was_transmitted = GNUNET_SYSERR; /* mark as cancelled */
1284  check_disconnect();
1285 }
1286 
1287 
1288 /* 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:86
int32_t direction
GNUNET_YES to get hostname from IP, GNUNET_NO to get IP from hostname.
Definition: resolver.h:53
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 struct GNUNET_TIME_Relative backoff
How long should we wait to reconnect?
Definition: resolver_api.c:81
static struct GNUNET_RESOLVER_RequestHandle * req_tail
Tail of DLL of requests.
Definition: resolver_api.c:71
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:900
static void reconnect_task(void *cls)
Now try to reconnect to the resolver service.
Definition: resolver_api.c:785
GNUNET_RESOLVER_AddressCallback addr_callback
Callback if this is an name resolution request, otherwise NULL.
Definition: resolver_api.c:115
GNUNET_MQ_Error
Error codes for the queue.
struct GNUNET_RESOLVER_RequestHandle * prev
Previous entry in DLL of requests.
Definition: resolver_api.c:109
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:645
static const struct GNUNET_CONFIGURATION_Handle * resolver_cfg
Configuration.
Definition: resolver_api.c:55
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#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:933
#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:404
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.
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
static void process_requests()
Process pending requests to the resolver.
Definition: resolver_api.c:421
uint32_t client_id
identifies the request this message responds to.
Definition: resolver.h:81
#define LOG_STRERROR(kind, syscall)
Definition: resolver_api.c:34
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE.
Definition: resolver.h:75
#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:121
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:1237
static const char * loopback[]
Possible hostnames for "loopback".
Definition: resolver_api.c:45
#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:76
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:1264
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:686
int af
Desired address family.
Definition: resolver_api.c:142
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:131
#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:104
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.
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-arm.c:104
int was_transmitted
Has this request been transmitted to the service? GNUNET_YES if transmitted GNUNET_YES if not transmi...
Definition: resolver_api.c:155
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:66
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:137
Handle to a request given to the resolver.
Definition: resolver_api.c:100
static void shutdown_task(void *cls)
Task executed on system shutdown.
Definition: resolver_api.c:300
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:160
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:92
#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:84
int32_t af
Address family to use (AF_INET, AF_INET6 or AF_UNSPEC).
Definition: resolver.h:58
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:61
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:721
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:187
configuration data
Definition: configuration.c:83
#define GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST
Request DNS resolution.
void GNUNET_RESOLVER_disconnect()
Destroy the connection to the resolver service.
Definition: resolver_api.c:264
uint32_t client_id
identifies the request and is contained in the response message.
Definition: resolver.h:64
static struct GNUNET_RESOLVER_RequestHandle * req_head
Head of DLL of requests.
Definition: resolver_api.c:66
Entry in list of pending tasks.
Definition: scheduler.c:131
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:490
static struct MHD_Response * response
Our canonical response.
void * cls
Closure for the callbacks.
Definition: resolver_api.c:126
static void check_disconnect()
Consider disconnecting if we have no further requests pending.
Definition: resolver_api.c:313
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:821
#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:342
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:351
size_t data_len
Length of the data that follows this struct.
Definition: resolver_api.c:175
Request for the resolver.
Definition: resolver.h:43
uint32_t id
Identifies the request.
Definition: resolver_api.c:147
#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:165
int received_response
GNUNET_YES if a response was received
Definition: resolver_api.c:170
void GNUNET_RESOLVER_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Create the connection to the resolver service.
Definition: resolver_api.c:252
#define GNUNET_malloc(size)
Wrapper around malloc.
static void handle_lookup_timeout(void *cls)
A DNS resolution timed out.
Definition: resolver_api.c:873
#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:470
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:956
static void reconnect(void)
Adjust exponential back-off and reconnect to the service.
Definition: resolver_api.c:821