827 lines
24 KiB
C
827 lines
24 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_getinfo2.c,v $ $Revision: 1.27.10.7 $
|
|
* $Source: /home/interpeak/CVSRoot/ipcom/port/src/ipcom_getinfo2.c,v $
|
|
* $Author: hchu0 $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Markus Carlstedt <markus@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipcom_config.h"
|
|
|
|
#if defined(IPDNSC)
|
|
#define IPCOM_USE_DNS
|
|
#endif
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include "ipcom_type.h"
|
|
#include "ipcom_cstyle.h"
|
|
#include "ipcom_clib.h"
|
|
#include "ipcom_sock.h"
|
|
#include "ipcom_sock2.h"
|
|
#include "ipcom_sock6.h"
|
|
#include "ipcom_inet.h"
|
|
|
|
#ifdef IPCOM_USE_DNS
|
|
#include <ipdnsc.h>
|
|
#endif
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#if !defined(IP_PORT_VXWORKS) || defined(_WRS_KERNEL)
|
|
#define IPCOM_USE_GETINFO
|
|
#endif
|
|
|
|
#if defined(IPCOM_USE_DNS) && defined(IP_PORT_OSE5)
|
|
#define ipcom_getnameinfo2 ipcom_getnameinfo3
|
|
#define ipcom_getaddrinfo2 ipcom_getaddrinfo3
|
|
#define ipcom_freeaddrinfo2 ipcom_freeaddrinfo3
|
|
#endif
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#if defined(IP_PORT_VXWORKS) && IP_PORT_VXWORKS >= 65
|
|
IP_EXTERN struct Ip_hostent *ipcom_gethostbynamelocal(const char *name,
|
|
int family,
|
|
Ip_u32 *ifindex,
|
|
struct Ip_hostent *result,
|
|
char *buf, int buflen);
|
|
IP_EXTERN struct Ip_hostent *ipcom_gethostbyaddrlocal(const char *addr,
|
|
int len, int family,
|
|
struct Ip_hostent *result,
|
|
char *buf, int buflen);
|
|
#endif
|
|
|
|
#ifdef IPCOM_USE_DNS
|
|
IP_EXTERN int ipcom_dns_init_ok;
|
|
IP_EXTERN Ipdnsc_api ipcom_dns;
|
|
#endif
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPCOM_USE_GETINFO
|
|
IP_PUBLIC int
|
|
ipcom_getnameinfo2(IP_CONST struct Ip_sockaddr *sa, Ip_socklen_t salen,
|
|
char *host, Ip_size_t hostlen,
|
|
char *serv, Ip_size_t servlen,
|
|
int flags);
|
|
|
|
IP_PUBLIC int
|
|
ipcom_getaddrinfo2(IP_CONST char *hostname,
|
|
IP_CONST char *servname,
|
|
IP_CONST struct Ip_addrinfo *hints,
|
|
struct Ip_addrinfo **res);
|
|
#endif /* IPCOM_USE_GETINFO */
|
|
|
|
IP_PUBLIC void
|
|
ipcom_freeaddrinfo2(struct Ip_addrinfo *ai);
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPCOM_USE_GETINFO
|
|
IP_STATIC struct Ip_addrinfo *
|
|
ipcom_getaddrinfo_alloc(void)
|
|
{
|
|
struct Ip_addrinfo *ai;
|
|
|
|
/* Allocate the ai structure */
|
|
ai = ipcom_malloc(sizeof(*ai));
|
|
if (ai == IP_NULL)
|
|
return IP_NULL;
|
|
ipcom_memset(ai, 0, sizeof(*ai));
|
|
|
|
/* Allocate the sockaddr structure */
|
|
ai->ai_addr = ipcom_malloc(sizeof(union Ip_sockaddr_union));
|
|
if (ai->ai_addr == IP_NULL)
|
|
{
|
|
ipcom_free(ai);
|
|
return IP_NULL;
|
|
}
|
|
ipcom_memset(ai->ai_addr, 0, sizeof(union Ip_sockaddr_union));
|
|
|
|
return ai;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_getnameinfo2
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_getnameinfo2(IP_CONST struct Ip_sockaddr *sa, Ip_socklen_t salen,
|
|
char *host, Ip_size_t hostlen,
|
|
char *serv, Ip_size_t servlen,
|
|
int flags)
|
|
{
|
|
union Ip_sockaddr_union *su;
|
|
struct Ip_servent *se;
|
|
char numserv[8];
|
|
int family = 0;
|
|
Ip_u16 port_n = 0;
|
|
char *addr_n = IP_NULL;
|
|
void *real_addr_n = IP_NULL;
|
|
#ifdef IPCOM_USE_INET6
|
|
Ip_u32 ipv4addr;
|
|
char numaddr[IP_INET6_ADDRSTRLEN];
|
|
#else
|
|
char numaddr[IP_INET_ADDRSTRLEN];
|
|
#endif
|
|
char zone[16];
|
|
struct Ip_hostent *he;
|
|
int h_errno;
|
|
#ifdef IPCOM_USE_DNS
|
|
Ip_bool hes = IP_FALSE;
|
|
#endif
|
|
#if !defined(IPCOM_USE_DNS) || (defined(IP_PORT_VXWORKS) && (IP_PORT_VXWORKS >= 65))
|
|
char buffer[300];
|
|
struct Ip_hostent result;
|
|
#endif
|
|
|
|
/* Check arguments */
|
|
if (sa == IP_NULL || IPCOM_SA_LEN_GET(sa) > salen)
|
|
return IP_EAI_FAIL;
|
|
if ((serv == IP_NULL || servlen == 0) && (host == IP_NULL || hostlen == 0))
|
|
return IP_EAI_FAIL;
|
|
|
|
su = (union Ip_sockaddr_union *)sa;
|
|
#ifdef IPCOM_USE_INET
|
|
if (sa->sa_family == IP_AF_INET)
|
|
{
|
|
family = IP_AF_INET;
|
|
port_n = su->sin.sin_port;
|
|
addr_n = (char *)(&su->sin.sin_addr);
|
|
real_addr_n = addr_n;
|
|
}
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
if (sa->sa_family == IP_AF_INET6)
|
|
{
|
|
family = IP_AF_INET6;
|
|
port_n = su->sin6.sin6_port;
|
|
addr_n = (char *)(&su->sin6.sin6_addr);
|
|
real_addr_n = addr_n;
|
|
if (IP_IN6_IS_ADDR_V4COMPAT(&su->sin6.sin6_addr) ||
|
|
IP_IN6_IS_ADDR_V4MAPPED(&su->sin6.sin6_addr))
|
|
{
|
|
family = IP_AF_INET;
|
|
ipv4addr = su->sin6.sin6_addr.in6.addr32[3];
|
|
addr_n = (char *)&ipv4addr;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (real_addr_n == IP_NULL)
|
|
/* Invalid family */
|
|
return IP_EAI_FAIL;
|
|
|
|
/* Translate the socket address to a node name */
|
|
if (host != IP_NULL && hostlen != 0)
|
|
{
|
|
if (!(flags & IP_NI_NUMERICHOST))
|
|
{
|
|
#ifdef IPCOM_USE_DNS
|
|
#if defined(IP_PORT_VXWORKS) && (IP_PORT_VXWORKS >= 65)
|
|
he = ipcom_gethostbyaddrlocal(addr_n,
|
|
#ifdef IPCOM_USE_INET6
|
|
family == IP_AF_INET ? 4 : 16,
|
|
#else
|
|
4,
|
|
#endif
|
|
family,
|
|
&result, buffer, sizeof(buffer));
|
|
if (he)
|
|
hes = IP_TRUE;
|
|
else
|
|
#endif
|
|
if (ipcom_dns_init_ok == 0)
|
|
he = IP_NULL;
|
|
else
|
|
he = ipcom_dns.getipnodebyaddr(addr_n,
|
|
#ifdef IPCOM_USE_INET6
|
|
family == IP_AF_INET ? 4 : 16,
|
|
#else
|
|
4,
|
|
#endif
|
|
family, &h_errno);
|
|
#else
|
|
#ifdef IPCOM_USE_INET6
|
|
if (family != IP_AF_INET)
|
|
he = IP_NULL;
|
|
else
|
|
#endif
|
|
he = ipcom_gethostbyaddr_r(addr_n, 4, IP_AF_INET, &result, buffer, sizeof(buffer), &h_errno);
|
|
#endif /* IPCOM_USE_DNS */
|
|
|
|
if (he != IP_NULL)
|
|
{
|
|
if (ipcom_strlen(he->h_name) + 1 > hostlen)
|
|
{
|
|
#ifdef IPCOM_USE_DNS
|
|
if (hes == IP_FALSE)
|
|
ipcom_dns.freehostent(he);
|
|
#endif
|
|
return IP_EAI_MEMORY;
|
|
}
|
|
ipcom_strcpy(host, he->h_name);
|
|
#ifdef IPCOM_USE_DNS
|
|
if (hes == IP_FALSE)
|
|
ipcom_dns.freehostent(he);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
/* Try numeric */
|
|
flags |= IP_NI_NUMERICHOST;
|
|
}
|
|
}
|
|
|
|
if (flags & IP_NI_NUMERICHOST)
|
|
{
|
|
if (flags & IP_NI_NAMEREQD)
|
|
return IP_EAI_NONAME;
|
|
|
|
if (ipcom_inet_ntop(sa->sa_family, real_addr_n, numaddr, sizeof(numaddr)) == IP_NULL)
|
|
return IP_EAI_SYSTEM;
|
|
#ifdef IPCOM_USE_INET6
|
|
if (sa->sa_family == IP_AF_INET6
|
|
&& ((struct Ip_sockaddr_in6 *)sa)->sin6_scope_id != 0)
|
|
{
|
|
zone[0] = '%';
|
|
ipcom_sprintf(&zone[1], "%u", ((struct Ip_sockaddr_in6 *)sa)->sin6_scope_id);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
/* ipv4 or unscoped ipv6 */
|
|
zone[0] = '\0';
|
|
}
|
|
if (ipcom_strlen(numaddr) + ipcom_strlen(zone) + 1 > hostlen)
|
|
return IP_EAI_MEMORY;
|
|
ipcom_strcpy(host, numaddr);
|
|
ipcom_strcat(host, zone);
|
|
}
|
|
}
|
|
|
|
/* Translate the socket address to a service */
|
|
if (serv != IP_NULL && servlen != 0)
|
|
{
|
|
if (flags & IP_NI_NUMERICSERV)
|
|
se = IP_NULL;
|
|
else
|
|
se = ipcom_getservbyport((int)port_n, (flags & IP_NI_DGRAM) ? "udp" : "tcp");
|
|
|
|
if (se)
|
|
{
|
|
if (ipcom_strlen(se->s_name) + 1 > servlen)
|
|
return IP_EAI_MEMORY;
|
|
ipcom_strcpy(serv, se->s_name);
|
|
}
|
|
else
|
|
{
|
|
ipcom_snprintf(numserv, sizeof(numserv), "%u", ip_ntohs(port_n));
|
|
if (ipcom_strlen(numserv) + 1 > servlen)
|
|
return IP_EAI_MEMORY;
|
|
ipcom_strcpy(serv, numserv);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_getaddrinfo2
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
/*lint -efunc(429,ipcom_getaddrinfo2) */
|
|
/*lint -efunc(429,ipcom_getsockaddrbyaddr) */
|
|
IP_PUBLIC int
|
|
ipcom_getaddrinfo2(IP_CONST char *hostname,
|
|
IP_CONST char *servname,
|
|
IP_CONST struct Ip_addrinfo *hints,
|
|
struct Ip_addrinfo **res)
|
|
{
|
|
struct Ip_addrinfo *ai = IP_NULL;
|
|
struct Ip_addrinfo *tmp;
|
|
int family = 0, flags = 0, socktype = 0, protocol = 0, ret;
|
|
struct Ip_addrinfo lhints;
|
|
int h_errno;
|
|
#if !defined(IPCOM_USE_DNS) || (defined(IP_PORT_VXWORKS) && (IP_PORT_VXWORKS >= 65))
|
|
char buffer[300];
|
|
struct Ip_hostent result;
|
|
#endif
|
|
|
|
IP_CONST char* pHost = hostname;
|
|
if(pHost != IP_NULL)
|
|
while(*pHost == ' ') pHost ++;
|
|
|
|
/* Check arguments */
|
|
if (pHost == IP_NULL && servname == IP_NULL)
|
|
{
|
|
ret = IP_EAI_NONAME;
|
|
goto fail;
|
|
}
|
|
if (hints != IP_NULL)
|
|
{
|
|
if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next)
|
|
{
|
|
ret = IP_EAI_NONAME;
|
|
goto fail;
|
|
}
|
|
if (hints->ai_flags & ~(IP_AI_PASSIVE | IP_AI_CANONNAME | IP_AI_NUMERICHOST | IP_AI_NUMERICSERV
|
|
| IP_AI_V4MAPPED | IP_AI_ALL | IP_AI_ADDRCONFIG))
|
|
{
|
|
ret = IP_EAI_BADFLAGS;
|
|
goto fail;
|
|
}
|
|
if (hints->ai_family != IP_AF_UNSPEC
|
|
&& hints->ai_family != IP_AF_INET
|
|
&& hints->ai_family != IP_AF_INET6)
|
|
{
|
|
ret = IP_EAI_FAMILY;
|
|
goto fail;
|
|
}
|
|
if (hints->ai_socktype != 0
|
|
&& hints->ai_socktype != IP_SOCK_STREAM
|
|
&& hints->ai_socktype != IP_SOCK_DGRAM
|
|
&& hints->ai_socktype != IP_SOCK_RAW)
|
|
{
|
|
ret = IP_EAI_SOCKTYPE;
|
|
goto fail;
|
|
}
|
|
|
|
/* intentional codes */
|
|
/* coverity[copy_paste_error] */
|
|
if (hints->ai_socktype != IP_SOCK_RAW
|
|
&& hints->ai_protocol != 0
|
|
&& hints->ai_protocol != IP_IPPROTO_UDP
|
|
#ifdef IPSCTP
|
|
&& hints->ai_protocol != IP_IPPROTO_SCTP
|
|
#endif
|
|
&& hints->ai_protocol != IP_IPPROTO_TCP)
|
|
{
|
|
ret = IP_EAI_NONAME;
|
|
goto fail;
|
|
}
|
|
|
|
if ((hints->ai_socktype == IP_SOCK_STREAM && hints->ai_protocol == IP_IPPROTO_UDP)
|
|
|| (hints->ai_socktype == IP_SOCK_DGRAM && hints->ai_protocol == IP_IPPROTO_TCP))
|
|
{
|
|
ret = IP_EAI_NONAME;
|
|
goto fail;
|
|
}
|
|
|
|
if (hints->ai_socktype == IP_SOCK_RAW && servname != IP_NULL)
|
|
{
|
|
ret = IP_EAI_SERVICE;
|
|
goto fail;
|
|
}
|
|
|
|
flags = hints->ai_flags;
|
|
family = hints->ai_family;
|
|
socktype = hints->ai_socktype;
|
|
protocol = hints->ai_protocol;
|
|
}
|
|
|
|
if (family == IP_AF_UNSPEC)
|
|
{
|
|
int ret1;
|
|
|
|
if (hints == IP_NULL)
|
|
ipcom_memset(&lhints, 0, sizeof(lhints));
|
|
else
|
|
ipcom_memcpy(&lhints, hints, sizeof(lhints));
|
|
lhints.ai_family = IP_AF_INET6;
|
|
ret = ipcom_getaddrinfo2(pHost, servname, &lhints, res);
|
|
lhints.ai_family = IP_AF_INET;
|
|
tmp = *res;
|
|
if (*res != IP_NULL)
|
|
while(tmp->ai_next != IP_NULL)
|
|
tmp = tmp->ai_next;
|
|
ret1 = ipcom_getaddrinfo2(pHost, servname, &lhints, *res == IP_NULL ? res : &tmp->ai_next);
|
|
return ret == 0 || ret1 == 0 ? 0 : ret;
|
|
}
|
|
|
|
/* Allocate initial addrinfo structure */
|
|
ai = ipcom_getaddrinfo_alloc();
|
|
if (ai == IP_NULL)
|
|
{
|
|
ret = IP_EAI_MEMORY;
|
|
goto fail;
|
|
}
|
|
|
|
/* Explore hostname */
|
|
if (pHost == IP_NULL)
|
|
{
|
|
char *addr;
|
|
|
|
if (flags & IP_AI_PASSIVE)
|
|
addr = family == IP_AF_INET ? "0.0.0.0" : "::";
|
|
else
|
|
addr = family == IP_AF_INET ? "127.0.0.1" : "::1";
|
|
if (ipcom_getsockaddrbyaddr(family, addr, ai->ai_addr))
|
|
{
|
|
ret = IP_EAI_NONAME;
|
|
goto fail;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int literal_v4 = 0, literal_v6 = 0;
|
|
Ip_u32 ipaddr[4];
|
|
struct Ip_hostent *he;
|
|
#if defined(IP_PORT_VXWORKS) && IP_PORT_VXWORKS >= 65
|
|
Ip_u32 ifindex = 0;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
/* The extra 12 bytes is for a numeric %ifindex scope id string */
|
|
char hostaddr[IP_INET6_ADDRSTRLEN+16];
|
|
#else
|
|
char hostaddr[16];
|
|
#endif
|
|
#ifdef IPCOM_USE_DNS
|
|
Ip_bool hes = IP_FALSE;
|
|
int dns_flags = 0;
|
|
#endif
|
|
|
|
ipcom_memset(ipaddr, 0, sizeof(ipaddr));
|
|
#ifdef IPCOM_USE_INET
|
|
if (family == IP_AF_INET)
|
|
literal_v4 = ipcom_inet_pton(family, (char *) pHost, ipaddr);
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
if (literal_v4 == 0 && family == IP_AF_INET6)
|
|
literal_v6 = ipcom_inet_pton(family, pHost, ipaddr);
|
|
#endif
|
|
if ((literal_v4 == 0) && (literal_v6 == 0))
|
|
{
|
|
if (flags & IP_AI_NUMERICHOST)
|
|
{
|
|
ret = IP_EAI_NONAME;
|
|
goto fail;
|
|
}
|
|
else
|
|
{
|
|
#ifdef IPCOM_USE_DNS
|
|
if (family == IP_AF_INET6)
|
|
{
|
|
dns_flags |= flags & IP_AI_V4MAPPED ? IPDNSC_AI_V4MAPPED : 0;
|
|
dns_flags |= (flags & IP_AI_V4MAPPED) && (flags & IP_AI_ALL) ? IPDNSC_AI_ALL : 0;
|
|
dns_flags |= flags & IP_AI_ADDRCONFIG ? IPDNSC_AI_ADDRCONFIG : 0;
|
|
}
|
|
#if defined(IP_PORT_VXWORKS) && IP_PORT_VXWORKS >= 65
|
|
he = ipcom_gethostbynamelocal(pHost, family, &ifindex, &result, buffer, sizeof(buffer));
|
|
if (he)
|
|
hes = IP_TRUE;
|
|
else
|
|
#endif
|
|
if (ipcom_dns_init_ok == 0)
|
|
he = IP_NULL;
|
|
else
|
|
he = ipcom_dns.getipnodebyname(pHost, family, dns_flags, &h_errno);
|
|
#else
|
|
if (family == IP_AF_INET)
|
|
he = ipcom_gethostbyname_r(pHost, &result, buffer, sizeof(buffer), &h_errno);
|
|
else
|
|
he = IP_NULL;
|
|
#endif /* IPCOM_USE_DNS */
|
|
if (he == IP_NULL)
|
|
{
|
|
ret = IP_EAI_NONAME;
|
|
goto fail;
|
|
}
|
|
else
|
|
{
|
|
int i = 0;
|
|
union Ip_sockaddr_union sa;
|
|
struct Ip_addrinfo *prev = IP_NULL;
|
|
|
|
while (he->h_addr_list[i] != IP_NULL)
|
|
{
|
|
if (ipcom_inet_ntop(he->h_addrtype, he->h_addr_list[i], hostaddr, sizeof(hostaddr)) == IP_NULL
|
|
#if defined(IP_PORT_VXWORKS) && IP_PORT_VXWORKS >= 65
|
|
|| (ifindex != 0 && (ipcom_sprintf(ipcom_strchr(hostaddr, '\0'), "%%%u", ifindex) <= 0))
|
|
#endif
|
|
|| ipcom_getsockaddrbyaddr(he->h_addrtype, hostaddr, &sa.sa) != 0)
|
|
{
|
|
#ifdef IPCOM_USE_DNS
|
|
if (hes == IP_FALSE)
|
|
ipcom_dns.freehostent(he);
|
|
#endif
|
|
ret = IP_EAI_NONAME;
|
|
goto fail;
|
|
}
|
|
|
|
if (i == 0)
|
|
tmp = ai;
|
|
else
|
|
{
|
|
/* Allocate additional addrinfo structure for optional alias address */
|
|
tmp = ipcom_getaddrinfo_alloc();
|
|
if (tmp == IP_NULL)
|
|
{
|
|
#ifdef IPCOM_USE_DNS
|
|
if (hes == IP_FALSE)
|
|
ipcom_dns.freehostent(he);
|
|
#endif
|
|
ret = IP_EAI_MEMORY;
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
/* Copy socket address */
|
|
ipcom_memcpy(tmp->ai_addr, &sa, sizeof(union Ip_sockaddr_union));
|
|
|
|
/* Get the name */
|
|
if (flags & IP_AI_CANONNAME)
|
|
{
|
|
tmp->ai_canonname = ipcom_strdup(he->h_name);
|
|
if (tmp->ai_canonname == IP_NULL)
|
|
{
|
|
#ifdef IPCOM_USE_DNS
|
|
if (hes == IP_FALSE)
|
|
ipcom_dns.freehostent(he);
|
|
#endif
|
|
ret = IP_EAI_MEMORY;
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
if (prev != IP_NULL)
|
|
prev->ai_next = tmp;
|
|
prev = tmp;
|
|
i++;
|
|
}
|
|
#ifdef IPCOM_USE_DNS
|
|
if (hes == IP_FALSE)
|
|
ipcom_dns.freehostent(he);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
if (literal_v4 == 1)
|
|
family = IP_AF_INET;
|
|
else
|
|
#endif
|
|
family = IP_AF_INET6;
|
|
|
|
if (!(flags & IP_AI_NUMERICHOST) && (flags & IP_AI_CANONNAME))
|
|
{
|
|
#ifdef IPCOM_USE_DNS
|
|
#if defined(IP_PORT_VXWORKS) && (IP_PORT_VXWORKS >= 65)
|
|
he = ipcom_gethostbyaddrlocal((const char *)ipaddr,
|
|
family == IP_AF_INET ? 4 : 16,
|
|
family,
|
|
&result, buffer, sizeof(buffer));
|
|
if (he)
|
|
hes = IP_TRUE;
|
|
else
|
|
#endif
|
|
if (ipcom_dns_init_ok == 0)
|
|
he = IP_NULL;
|
|
else
|
|
he = ipcom_dns.getipnodebyaddr(ipaddr,
|
|
family == IP_AF_INET ? 4 : 16,
|
|
family, &h_errno);
|
|
#else
|
|
if (family == IP_AF_INET)
|
|
he = ipcom_gethostbyaddr_r((char *)ipaddr, 4, IP_AF_INET, &result, buffer, sizeof(buffer), &h_errno);
|
|
else
|
|
he = IP_NULL;
|
|
#endif /* IPCOM_USE_DNS */
|
|
if (he != IP_NULL)
|
|
{
|
|
ai->ai_canonname = ipcom_strdup(he->h_name);
|
|
#ifdef IPCOM_USE_DNS
|
|
if (hes == IP_FALSE)
|
|
ipcom_dns.freehostent(he);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
ai->ai_canonname = ipcom_strdup(pHost);
|
|
}
|
|
|
|
if (ai->ai_canonname == IP_NULL)
|
|
{
|
|
ret = IP_EAI_MEMORY;
|
|
goto fail;
|
|
}
|
|
}
|
|
if (ipcom_getsockaddrbyaddr(family, pHost, ai->ai_addr))
|
|
{
|
|
ret = IP_EAI_NONAME;
|
|
goto fail;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Explore servname */
|
|
if (servname != IP_NULL)
|
|
{
|
|
long val;
|
|
char *proto = IP_NULL;
|
|
char *suff;
|
|
struct Ip_servent *se = IP_NULL;
|
|
Ip_in_port_t port_n;
|
|
int i = 0, numericserv = 0;
|
|
|
|
if (flags & IP_AI_NUMERICSERV)
|
|
{
|
|
/* Allow only numeric service specification */
|
|
numericserv = 1;
|
|
while (servname[i] != '\0')
|
|
{
|
|
if (servname[i] < '0' || servname[i] > '9')
|
|
{
|
|
ret = IP_EAI_NONAME;
|
|
goto fail;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (socktype == IP_SOCK_DGRAM || protocol == IP_IPPROTO_UDP)
|
|
proto = "udp";
|
|
#ifdef IPSCTP
|
|
else if (socktype == IP_SOCK_STREAM && protocol == IP_IPPROTO_SCTP)
|
|
proto = "sctp";
|
|
#endif
|
|
else if (socktype == IP_SOCK_STREAM || protocol == IP_IPPROTO_TCP)
|
|
proto = "tcp";
|
|
if (numericserv == 0)
|
|
se = ipcom_getservbyname((char *)servname, proto);
|
|
if (se == IP_NULL)
|
|
{
|
|
val = ipcom_strtol((char *)servname, &suff, 10);
|
|
if (val < 0 || val > 0xffff || *suff != '\0' || suff == servname)
|
|
{
|
|
ret = IP_EAI_SERVICE;
|
|
goto fail;
|
|
}
|
|
else
|
|
{
|
|
if (proto == IP_NULL)
|
|
proto = "udp";
|
|
port_n = (Ip_in_port_t)ip_htons((short)val);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
proto = se->s_proto;
|
|
port_n = (Ip_in_port_t)se->s_port;
|
|
}
|
|
|
|
socktype = (ipcom_strcmp(proto, "tcp") == 0 || ipcom_strcmp(proto, "sctp") == 0) ?
|
|
IP_SOCK_STREAM : IP_SOCK_DGRAM;
|
|
#ifdef IPSCTP
|
|
if (protocol != IP_IPPROTO_SCTP)
|
|
#endif
|
|
protocol = socktype == IP_SOCK_STREAM ? IP_IPPROTO_TCP : IP_IPPROTO_UDP;
|
|
tmp = ai;
|
|
while (tmp != IP_NULL)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
if (family == IP_AF_INET)
|
|
((union Ip_sockaddr_union *)tmp->ai_addr)->sin.sin_port = port_n;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
if (family == IP_AF_INET6)
|
|
((union Ip_sockaddr_union *)tmp->ai_addr)->sin6.sin6_port = port_n;
|
|
#endif
|
|
tmp = tmp->ai_next;
|
|
}
|
|
}
|
|
|
|
tmp = ai;
|
|
while (tmp != IP_NULL)
|
|
{
|
|
tmp->ai_flags = 0;
|
|
tmp->ai_family = family;
|
|
tmp->ai_socktype = socktype;
|
|
tmp->ai_protocol = protocol;
|
|
tmp->ai_addrlen = IPCOM_SA_LEN_GET(tmp->ai_addr);
|
|
tmp = tmp->ai_next;
|
|
}
|
|
|
|
*res = ai;
|
|
ip_assert(*res != IP_NULL && (*res)->ai_addr != IP_NULL);
|
|
return 0;
|
|
|
|
fail:
|
|
if (ai != IP_NULL)
|
|
ipcom_freeaddrinfo2(ai);
|
|
*res = IP_NULL;
|
|
return ret;
|
|
}
|
|
#endif /* IPCOM_USE_GETINFO */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_freeaddrinfo2
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC void
|
|
ipcom_freeaddrinfo2(struct Ip_addrinfo *ai)
|
|
{
|
|
struct Ip_addrinfo *next;
|
|
|
|
while (ai != IP_NULL)
|
|
{
|
|
next = ai->ai_next;
|
|
if (ai->ai_canonname != IP_NULL)
|
|
ipcom_free(ai->ai_canonname);
|
|
if (ai->ai_addr != IP_NULL)
|
|
ipcom_free(ai->ai_addr);
|
|
ipcom_free(ai);
|
|
ai = next;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|