+SilcBool silc_net_is_ip(const char *addr)
+{
+ if (silc_net_is_ip4(addr))
+ return TRUE;
+ return silc_net_is_ip6(addr);
+}
+
+/* Internal context for async resolving */
+typedef struct {
+ SilcNetResolveCallback completion;
+ void *context;
+ SilcBool prefer_ipv6;
+ SilcSchedule schedule;
+ char *input;
+ char *result;
+} *SilcNetResolveContext;
+
+SILC_TASK_CALLBACK(silc_net_resolve_completion)
+{
+ SilcNetResolveContext r = (SilcNetResolveContext)context;
+
+ /* Call the completion callback */
+ if (r->completion)
+ (*r->completion)(r->result, r->context);
+
+ silc_free(r->input);
+ silc_free(r->result);
+ silc_free(r);
+}
+
+/* Thread function to resolve the address for hostname. */
+
+static void *silc_net_gethostbyname_thread(void *context)
+{
+ SilcNetResolveContext r = (SilcNetResolveContext)context;
+ SilcSchedule schedule = r->schedule;
+ char tmp[64];
+
+ if (silc_net_gethostbyname(r->input, r->prefer_ipv6, tmp, sizeof(tmp)))
+ r->result = silc_strdup(tmp);
+
+ silc_schedule_task_add(schedule, 0, silc_net_resolve_completion, r, 0, 1,
+ SILC_TASK_TIMEOUT);
+ silc_schedule_wakeup(schedule);
+ return NULL;
+}
+
+/* Thread function to resolve the hostname for address. */
+
+static void *silc_net_gethostbyaddr_thread(void *context)
+{
+ SilcNetResolveContext r = (SilcNetResolveContext)context;
+ SilcSchedule schedule = r->schedule;
+ char tmp[256];
+
+ if (silc_net_gethostbyaddr(r->input, tmp, sizeof(tmp)))
+ r->result = silc_strdup(tmp);
+
+ silc_schedule_task_add(schedule, 0, silc_net_resolve_completion, r, 0, 1,
+ SILC_TASK_TIMEOUT);
+ silc_schedule_wakeup(schedule);
+ return NULL;
+}
+
+/* Resolves IP address for hostname. */
+
+SilcBool silc_net_gethostbyname(const char *name,
+ SilcBool prefer_ipv6, char *address,
+ SilcUInt32 address_len)
+{
+#ifdef HAVE_IPV6
+ struct addrinfo hints, *ai, *tmp, *ip4 = NULL, *ip6 = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo(name, NULL, &hints, &ai))
+ return FALSE;
+
+ for (tmp = ai; tmp; tmp = tmp->ai_next) {
+ if (tmp->ai_family == AF_INET6) {
+ ip6 = tmp;
+ if (ip4)
+ break;
+ continue;
+ }
+ if (tmp->ai_family == AF_INET) {
+ ip4 = tmp;
+ if (ip6)
+ break;
+ continue;
+ }
+ }
+
+ tmp = (prefer_ipv6 ? (ip6 ? ip6 : ip4) : (ip4 ? ip4 : ip6));
+ if (!tmp) {
+ freeaddrinfo(ai);
+ return FALSE;
+ }
+
+ if (getnameinfo(tmp->ai_addr, tmp->ai_addrlen, address,
+ address_len, NULL, 0, NI_NUMERICHOST)) {
+ freeaddrinfo(ai);
+ return FALSE;
+ }
+
+ freeaddrinfo(ai);
+#else
+ struct hostent *hp;
+ struct in_addr ip;
+ char *tmp;
+
+ if (silc_net_is_ip4(name)) {
+ memset(address, 0, address_len);
+ if (address_len < strlen(name))
+ return FALSE;
+ strncpy(address, name, strlen(name));
+ return TRUE;
+ }
+
+ hp = gethostbyname(name);
+ if (!hp)
+ return FALSE;
+
+ memcpy(&ip.s_addr, hp->h_addr_list[0], 4);
+ tmp = inet_ntoa(ip);
+ if (!tmp)
+ return FALSE;
+ if (address_len < strlen(tmp))
+ return FALSE;
+ memset(address, 0, address_len);
+ strncpy(address, tmp, strlen(tmp));
+#endif
+
+ return TRUE;
+}
+
+/* Resolves IP address for hostname async. */
+
+void silc_net_gethostbyname_async(const char *name,
+ SilcBool prefer_ipv6,
+ SilcSchedule schedule,
+ SilcNetResolveCallback completion,
+ void *context)
+{
+ SilcNetResolveContext r = silc_calloc(1, sizeof(*r));
+
+ if (!schedule) {
+ schedule = silc_schedule_get_global();
+ SILC_VERIFY(schedule);
+ }
+
+ r->completion = completion;
+ r->context = context;
+ r->prefer_ipv6 = prefer_ipv6;
+ r->schedule = schedule;
+ r->input = silc_strdup(name);
+
+ silc_thread_create(silc_net_gethostbyname_thread, r, FALSE);
+}
+
+/* Resolves hostname by IP address. */
+
+SilcBool silc_net_gethostbyaddr(const char *addr, char *name,
+ SilcUInt32 name_len)
+{
+#ifdef HAVE_IPV6
+ struct addrinfo req, *ai;
+
+ memset(&req, 0, sizeof(req));
+ req.ai_socktype = SOCK_STREAM;
+ req.ai_flags = AI_CANONNAME;
+
+ if (getaddrinfo(addr, NULL, &req, &ai))
+ return FALSE;
+ if (getnameinfo(ai->ai_addr, ai->ai_addrlen, name, name_len, NULL, 0, 0)) {
+ freeaddrinfo(ai);
+ return FALSE;
+ }
+ freeaddrinfo(ai);
+#else
+ struct hostent *hp;
+ unsigned char a[4];
+
+ if (!silc_net_addr2bin(addr, a, sizeof(a)))
+ return FALSE;
+
+ hp = gethostbyaddr(a, 4, AF_INET);
+ if (!hp)
+ return FALSE;
+ if (name_len < strlen(hp->h_name))
+ return FALSE;
+ memset(name, 0, name_len);
+ strncpy(name, hp->h_name, strlen(hp->h_name));
+#endif
+
+ return TRUE;
+}
+
+/* Resolves hostname by IP address async. */
+
+void silc_net_gethostbyaddr_async(const char *addr,
+ SilcSchedule schedule,
+ SilcNetResolveCallback completion,
+ void *context)