+/* 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));
+
+ 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)
+{
+ SilcNetResolveContext r = silc_calloc(1, sizeof(*r));
+
+ r->completion = completion;
+ r->context = context;
+ r->schedule = schedule;
+ r->input = silc_strdup(addr);
+
+ silc_thread_create(silc_net_gethostbyaddr_thread, r, FALSE);
+}
+
+#ifndef SILC_SYMBIAN
+