blob: da49ea6d91894741b6e784a0dda2bb94506448ab [file] [log] [blame]
/*
* Copyright (c) 2017-2018, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*****************************************************************************/
/* Include files */
/*****************************************************************************/
#include <unistd.h> /* needed? */
#include <string.h>
#include <stdlib.h>
#include <ti/net/slnetutils.h>
#include <ti/net/slnetif.h>
#include <ti/net/slneterr.h>
/*****************************************************************************/
/* Macro declarations */
/*****************************************************************************/
#define SLNETUTIL_NORMALIZE_NEEDED 0
#if SLNETUTIL_NORMALIZE_NEEDED
#define SLNETUTIL_NORMALIZE_RET_VAL(retVal,err) ((retVal < 0)?(retVal = err):(retVal))
#else
#define SLNETUTIL_NORMALIZE_RET_VAL(retVal,err)
#endif
/* Size needed for getaddrinfo mem allocation */
#define SLNETUTIL_ADDRINFO_ALLOCSZ ((sizeof(SlNetUtil_addrInfo_t)) + \
(sizeof(SlNetSock_AddrIn6_t)))
/* Cap number of mem allocations in case of large number of results from DNS */
#define SLNETUTIL_ADDRINFO_MAX_DNS_NODES 10
#define SLNETUTIL_DNSBUFSIZE ((SLNETUTIL_ADDRINFO_MAX_DNS_NODES) * \
(sizeof(uint32_t)))
#define LL_PREFIX 0xFE80
/*****************************************************************************/
/* Structure/Enum declarations */
/*****************************************************************************/
/*****************************************************************************/
/* Function prototypes */
/*****************************************************************************/
static int32_t SlNetUtil_UTOA(uint16_t value, char * string, uint16_t base);
static int32_t SlNetUtil_bin2StrIpV4(SlNetSock_InAddr_t *binaryAddr, char *strAddr, uint16_t strAddrLen);
static int32_t SlNetUtil_bin2StrIpV6(SlNetSock_In6Addr_t *binaryAddr, char *strAddr, uint16_t strAddrLen);
static int32_t SlNetUtil_strTok(char **string, char *returnstring, const char *delimiter);
static int32_t SlNetUtil_str2BinIpV4(char *strAddr, SlNetSock_InAddr_t *binaryAddr);
static int32_t SlNetUtil_str2BinIpV6(char *strAddr, SlNetSock_In6Addr_t *binaryAddr);
/* Local SlNetUtil_getAddrInfo utility functions */
static SlNetUtil_addrInfo_t *setAddrInfo(uint16_t ifID, SlNetSock_Addr_t *addr,
int family, const char *service, const SlNetUtil_addrInfo_t *hints);
static SlNetUtil_addrInfo_t *createAddrInfo(uint16_t ifID,
SlNetSock_Addr_t *addr, int family, const char *service, int flags,
int socktype, int protocol);
static int mergeLists(SlNetUtil_addrInfo_t **curList,
SlNetUtil_addrInfo_t **newList);
//*****************************************************************************
//
// SlNetUtil_init - Initialize the slnetutil module
//
//*****************************************************************************
int32_t SlNetUtil_init(int32_t flags)
{
return 0;
}
//*****************************************************************************
// SlNetUtil_gaiStrErr
//*****************************************************************************
/*
* Error codes for gai_strerror
* The order of this array MUST match the numbering of the SLNETUTIL_EAI_CODE
* defines in <ti/net/slneterr.h>
*/
static const char *strErrorMsgs[] =
{
"Temporary failure in name resolution", /* SLNETUTIL_EAI_AGAIN */
"Bad value for ai_flags", /* SLNETUTIL_EAI_BADFLAGS */
"Non-recoverable failure in name resolution", /* SLNETUTIL_EAI_FAIL */
"ai_family not supported", /* SLNETUTIL_EAI_FAMILY */
"Memory allocation failure", /* SLNETUTIL_EAI_MEMORY */
"Node or service not known, " /* SLNETUTIL_EAI_NONAME */
"or both node and service are NULL",
"Service (port number) not supported " /* SLNETUTIL_EAI_SERVICE */
"for ai_socktype",
"ai_socktype not supported", /* SLNETUTIL_EAI_SOCKTYPE */
"System error", /* SLNETUTIL_EAI_SYSTEM */
"An argument buffer overflowed", /* SLNETUTIL_EAI_OVERFLOW */
"Address family for node not supported" /* SLNETUTIL_EAI_ADDRFAMILY */
};
const char *SlNetUtil_gaiStrErr(int32_t errorCode)
{
/*
* Error codes are negative starting with -3121 so
* ~(errorCode - SLNETUTIL_EAI_BASE) takes the one's compliment of the code
* minus the base of the error codes to convert the code into a positive
* value that matches the StrerrorMsgs array index.
*/
int msgsIndex = ~(errorCode - SLNETUTIL_EAI_BASE);
int msgsRange = sizeof(strErrorMsgs) / sizeof(strErrorMsgs[0]);
if ((msgsIndex < msgsRange) && (msgsIndex >= 0))
{
return strErrorMsgs[msgsIndex];
}
else
{
return "Unknown error";
}
}
//*****************************************************************************
//
// SlNetUtil_getHostByName - Obtain the IP Address of machine on network, by
// machine name
//
//*****************************************************************************
int32_t SlNetUtil_getHostByName(uint32_t ifBitmap, char *name, const uint16_t nameLen, uint32_t *ipAddr, uint16_t *ipAddrLen, const uint8_t family)
{
uint16_t origIpAddrLen;
SlNetIf_t *netIf;
int32_t retVal;
/* When ifBitmap is 0, that means automatic selection of all interfaces
is required, enable all bits in ifBitmap */
if (0 == ifBitmap)
{
ifBitmap = ~ifBitmap;
}
/*
* Save original value of ipAddrLen. If DNS resolution fails, ipAddrLen
* will be overwritten with zero, which is problematic for next iteration
* of the while loop.
*/
origIpAddrLen = *ipAddrLen;
/* This loop tries to run get host by name on the required interface
only if it in state enable and connected status
When multiple interfaces, in addition to the enable and connected it
will try to run the function on the interface from the highest
priority until an answer will return or until no interfaces left */
do
{
/* Search for the highest priority interface according to the
ifBitmap and the queryFlags */
netIf = SlNetIf_queryIf(ifBitmap, SLNETIF_QUERY_IF_STATE_BIT | SLNETIF_QUERY_IF_CONNECTION_STATUS_BIT);
/* Check if the function returned NULL or the requested interface
exists */
if ( (NULL == netIf) || ( NULL == (netIf->ifConf)->utilGetHostByName) )
{
/* Interface doesn't exists, return error code */
return SLNETERR_RET_CODE_INVALID_INPUT;
}
else
{
/* Disable the ifID bit from the ifBitmap after finding the netIf*/
ifBitmap &= ~(netIf->ifID);
/* Interface exists, return interface IP address */
retVal = (netIf->ifConf)->utilGetHostByName(netIf->ifContext, name, nameLen, ipAddr, ipAddrLen, family);
SLNETUTIL_NORMALIZE_RET_VAL(retVal, SLNETUTIL_ERR_UTILGETHOSTBYNAME_FAILED);
/* Check retVal for error codes */
if (retVal < SLNETERR_RET_CODE_OK)
{
/*
* utilGetHostByName failed. Restore the size of the ipAddr
* array and continue to the next ifID
*/
*ipAddrLen = origIpAddrLen;
continue;
}
else
{
/* Return success */
return netIf->ifID;
}
}
}while ( ifBitmap > 0 );
/* Interface doesn't exists, return error code */
return SLNETERR_RET_CODE_INVALID_INPUT;
}
//*****************************************************************************
// SlNetUtil_getAddrInfo
//*****************************************************************************
int32_t SlNetUtil_getAddrInfo(uint16_t ifID, const char *node,
const char *service, const struct SlNetUtil_addrInfo_t *hints,
struct SlNetUtil_addrInfo_t **res)
{
int i;
int retval = 0;
int resolved = 0;
int numNodes = 0;
char *buffer = NULL;
char *currAddr = NULL;
uint16_t numIpAddrs;
int32_t selectedIfId;
int32_t ipv4DnsError = 0;
int32_t ipv6DnsError = 0;
SlNetUtil_addrInfo_t *ai = NULL;
SlNetUtil_addrInfo_t *aiTmp = NULL;
SlNetSock_AddrIn_t sin;
SlNetSock_AddrIn6_t sin6;
/* check args passed in for errors */
if (!node && !service) {
/* Error: node and service args cannot both be NULL */
return (SLNETUTIL_EAI_NONAME);
}
if (!service) {
service = "0";
}
if (!res) {
/* Error: res cannot be NULL */
return (SLNETUTIL_EAI_NONAME);
}
if (!hints) {
/* User passed NULL hints. Create a hints for them with all 0 values */
static const SlNetUtil_addrInfo_t defHints = {
0, /* ai_flags */
SLNETSOCK_AF_UNSPEC, /* ai_family */
0, /* ai_socktype */
0, /* ai_protocol */
0, /* ai_addrlen */
NULL, /* ai_addr */
NULL, /* ai_canonname */
NULL /* ai_next */
};
hints = &defHints;
}
else {
/* Check the user's hints for invalid settings */
if (hints->ai_socktype != SLNETSOCK_SOCK_STREAM &&
hints->ai_socktype != SLNETSOCK_SOCK_DGRAM &&
hints->ai_socktype != 0) {
/* Error: invalid or unknown socktype */
return (SLNETUTIL_EAI_SOCKTYPE);
}
else if (hints->ai_protocol != SLNETSOCK_PROTO_TCP &&
hints->ai_protocol != SLNETSOCK_PROTO_UDP &&
hints->ai_protocol != 0) {
/* Error: invalid or unknown protocol */
return (SLNETUTIL_EAI_SOCKTYPE);
}
else if ((hints->ai_family != SLNETSOCK_AF_INET) &&
(hints->ai_family != SLNETSOCK_AF_INET6) &&
(hints->ai_family != SLNETSOCK_AF_UNSPEC)) {
/* Error: invalid or unknown family */
return (SLNETUTIL_EAI_FAMILY);
}
}
if (node) {
/*
* Client case. User needs an address structure to call connect() with.
*
* Determine what caller has passed to us for 'node'. Should be either:
* - an IPv4 address
* - an IPv6 address
* - or a hostname
*/
/* Test if 'node' is an IPv4 address */
retval = SlNetUtil_inetAton(node, &(sin.sin_addr));
if (retval) {
/* Ensure address family matches */
if (hints->ai_family != SLNETSOCK_AF_INET &&
hints->ai_family != SLNETSOCK_AF_UNSPEC) {
return (SLNETUTIL_EAI_ADDRFAMILY);
}
/*
* Create addrinfo struct(s) containing this IPv4 address. If ai
* is NULL, this will be caught at end of getaddrinfo
*
* Pass zero for IF ID. This is a don't care for the case of node
* being set to an IPv4 address
*/
ai = setAddrInfo(0, (SlNetSock_Addr_t *)&sin, SLNETSOCK_AF_INET,
service, hints);
}
else {
/* 'node' is either an IPv6 address or a hostname (or invalid) */
/* Test if 'node' is an IPv6 address */
retval = SlNetUtil_inetPton(SLNETSOCK_AF_INET6, node,
&(sin6.sin6_addr));
if (retval > 0) {
/* Ensure address family matches */
if (hints->ai_family != SLNETSOCK_AF_INET6 &&
hints->ai_family != SLNETSOCK_AF_UNSPEC) {
return (SLNETUTIL_EAI_ADDRFAMILY);
}
/*
* If we were given a link local address and corresponding IF,
* pass the IF number through. It must be used for the scope ID
*/
if ((SlNetUtil_ntohs(sin6.sin6_addr._S6_un._S6_u16[0]) ==
LL_PREFIX) && ifID != 0) {
selectedIfId = ifID;
}
else {
/*
* Set scope ID to zero for these cases:
* - Link local addr and ifID == 0:
* (caller responsibe for setting scope ID)
*
* - Non-local addr with ifID == 0:
* - Non-local addr with ifID == 1:
* scope ID not used and should be set to 0
*/
selectedIfId = 0;
}
/*
* Create addrinfo struct(s) containing this IPv6 address. If
* ai is NULL, this will be caught at end of getaddrinfo
*/
ai = setAddrInfo(selectedIfId, (SlNetSock_Addr_t *)&sin6,
SLNETSOCK_AF_INET6, service, hints);
}
else {
/* Test if 'node' is a host name. Use DNS to resolve it. */
/*
* Per RFC 2553, if node is not a valid numeric address string
* and AI_NUMERICHOST is set, return error (and prevent call to
* DNS).
*/
if (hints->ai_flags & SLNETUTIL_AI_NUMERICHOST) {
return (SLNETUTIL_EAI_NONAME);
}
buffer = malloc(SLNETUTIL_DNSBUFSIZE);
if (!buffer) {
/* Error: couldn't alloc DNS buffer */
return (SLNETUTIL_EAI_MEMORY);
}
/* IPv4 DNS lookup */
if (hints->ai_family == SLNETSOCK_AF_INET ||
hints->ai_family == SLNETSOCK_AF_UNSPEC) {
/*
* Set the size of the buffer to the number of 32-bit IPv4
* addresses this buffer can hold
*/
numIpAddrs = SLNETUTIL_DNSBUFSIZE / sizeof(uint32_t);
selectedIfId = SlNetUtil_getHostByName(ifID, (char *)node,
strlen(node), (uint32_t *)buffer, &numIpAddrs,
SLNETSOCK_AF_INET);
if (selectedIfId > 0) {
/*
* Process the results returned by DNS. Upon success,
* numIpAddrs contains the number of IP addresses stored
* into the buffer
*/
resolved = 1;
currAddr = buffer;
for (i = 0; i < numIpAddrs &&
numNodes < SLNETUTIL_ADDRINFO_MAX_DNS_NODES;
i++) {
sin.sin_addr.s_addr =
SlNetUtil_htonl(*((uint32_t *)currAddr));
/*
* Create addrinfo struct(s) containing this IPv4
* address. This can return a list with multiple
* nodes, depending on hints provided. Empty lists
* are handled before returning.
*
* Pass zero for IF ID. This is a don't care for
* the case of node being set to an IPv4 address.
*/
aiTmp = setAddrInfo(0, (SlNetSock_Addr_t *)&sin,
SLNETSOCK_AF_INET, service, hints);
if (aiTmp) {
/*
* Merge the results into the main list
* for each loop iteration:
*/
numNodes += mergeLists(&ai, &aiTmp);
}
/* move to the next IPv4 address */
currAddr += sizeof(uint32_t);
}
}
else {
/* save the IPv4 error code */
ipv4DnsError = selectedIfId;
}
}
/* IPv6 DNS lookup */
if (hints->ai_family == SLNETSOCK_AF_INET6 ||
hints->ai_family == SLNETSOCK_AF_UNSPEC) {
/*
* Set the size of the buffer to the number of 128-bit IPv6
* addresses this buffer can hold
*/
numIpAddrs =
SLNETUTIL_DNSBUFSIZE / sizeof(SlNetSock_In6Addr_t);
selectedIfId = SlNetUtil_getHostByName(ifID, (char *)node,
strlen(node), (uint32_t *)buffer, &numIpAddrs,
SLNETSOCK_AF_INET6);
if (selectedIfId > 0) {
/*
* Process the results returned by DNS. Upon success,
* numIpAddrs contains the number of IP addresses stored
* into the buffer
*/
resolved = 1;
currAddr = buffer;
for (i = 0; i < numIpAddrs &&
numNodes < SLNETUTIL_ADDRINFO_MAX_DNS_NODES;
i++) {
/* Copy the IPv6 address out of the buffer */
memcpy(&(sin6.sin6_addr), currAddr,
sizeof(SlNetSock_In6Addr_t));
/*
* Is this address non-local? If so, IF ID is a
* don't care
*/
if (sin6.sin6_addr._S6_un._S6_u16[0] != LL_PREFIX) {
selectedIfId = 0;
}
/* Change byte ordering to net byte order */
sin6.sin6_addr._S6_un._S6_u16[0] = SlNetUtil_htons(
sin6.sin6_addr._S6_un._S6_u16[0]);
sin6.sin6_addr._S6_un._S6_u16[1] = SlNetUtil_htons(
sin6.sin6_addr._S6_un._S6_u16[1]);
sin6.sin6_addr._S6_un._S6_u16[2] = SlNetUtil_htons(
sin6.sin6_addr._S6_un._S6_u16[2]);
sin6.sin6_addr._S6_un._S6_u16[3] = SlNetUtil_htons(
sin6.sin6_addr._S6_un._S6_u16[3]);
sin6.sin6_addr._S6_un._S6_u16[4] = SlNetUtil_htons(
sin6.sin6_addr._S6_un._S6_u16[4]);
sin6.sin6_addr._S6_un._S6_u16[5] = SlNetUtil_htons(
sin6.sin6_addr._S6_un._S6_u16[5]);
sin6.sin6_addr._S6_un._S6_u16[6] = SlNetUtil_htons(
sin6.sin6_addr._S6_un._S6_u16[6]);
sin6.sin6_addr._S6_un._S6_u16[7] = SlNetUtil_htons(
sin6.sin6_addr._S6_un._S6_u16[7]);
/*
* Create addrinfo struct(s) containing this IPv6
* address. This can return a list with multiple
* nodes, depending on hints provided. Empty lists
* are handled before returning.
*
* Pass down the appropriate IF number or zero,
* depending on whether this address is
* local or not
*/
aiTmp = setAddrInfo(selectedIfId,
(SlNetSock_Addr_t *)&sin6,
SLNETSOCK_AF_INET6, service, hints);
if (aiTmp) {
/*
* Merge the results into the main list
* for each loop iteration:
*/
numNodes += mergeLists(&ai, &aiTmp);
}
/* move to the next IPv6 address */
currAddr += sizeof(SlNetSock_In6Addr_t);
}
}
else {
/* save the IPv6 error code */
ipv6DnsError = selectedIfId;
}
}
free(buffer);
if (!resolved) {
/*
* Error: couldn't resolve host name
* Translate the SlNetSock error code to a GAI error code.
* Give the IPv4 error precedence:
*/
retval = (ipv4DnsError != 0) ? ipv4DnsError : ipv6DnsError;
switch (retval) {
case SLNETERR_NET_APP_DNS_ALLOC_ERROR:
retval = SLNETUTIL_EAI_MEMORY;
break;
case SLNETERR_NET_APP_DNS_INVALID_FAMILY_TYPE:
retval = SLNETUTIL_EAI_FAMILY;
break;
case SLNETERR_NET_APP_DNS_IPV6_REQ_BUT_IPV6_DISABLED:
retval = SLNETUTIL_EAI_SERVICE;
break;
case SLNETERR_NET_APP_DNS_PARAM_ERROR:
case SLNETERR_NET_APP_DNS_QUERY_FAILED:
default:
retval = SLNETUTIL_EAI_FAIL;
break;
}
return (retval);
}
}
}
}
else {
/* Server case. User needs an address structure to call bind() with. */
if (hints->ai_family == SLNETSOCK_AF_INET ||
hints->ai_family == SLNETSOCK_AF_UNSPEC) {
if (hints->ai_flags & SLNETUTIL_AI_PASSIVE) {
/* Per RFC 2553, accept connections on any IF */
sin.sin_addr.s_addr = SlNetUtil_htonl(SLNETSOCK_INADDR_ANY);
}
else {
/* Per RFC 2553, accept connections on loopback IF */
retval = SlNetUtil_inetPton(SLNETSOCK_AF_INET, "127.0.0.1",
&(sin.sin_addr.s_addr));
if (retval <= 0) {
return (SLNETUTIL_EAI_SYSTEM);
}
}
/*
* Create addrinfo struct(s) containing this IPv4 address. If ai
* is NULL, this will be caught at end of getaddrinfo
*
* Pass zero for IF ID. This is a don't care for
* the case of setting up a server socket.
*/
ai = setAddrInfo(0, (SlNetSock_Addr_t *)&sin,
SLNETSOCK_AF_INET, service, hints);
}
if (hints->ai_family == SLNETSOCK_AF_INET6 ||
hints->ai_family == SLNETSOCK_AF_UNSPEC) {
if (hints->ai_flags & SLNETUTIL_AI_PASSIVE) {
/*
* Per RFC 2553, accept connections on any IF
* (The IPv6 unspecified address is all zeroes)
*/
/* TODO: use in6addr_any, once available (NS-84) */
memset(&(sin6.sin6_addr), 0, sizeof(SlNetSock_In6Addr_t));
}
else {
/*
* Per RFC 2553, accept connections on loopback IF
* (The IPv6 loopback address is a 1 preceded by all zeroes)
*/
/* TODO: use in6addr_loopback, once available (NS-84) */
sin6.sin6_addr._S6_un._S6_u32[0] = 0;
sin6.sin6_addr._S6_un._S6_u32[1] = 0;
sin6.sin6_addr._S6_un._S6_u32[2] = 0;
sin6.sin6_addr._S6_un._S6_u32[3] = SlNetUtil_htonl(1);
}
/*
* Create addrinfo struct(s) containing this IPv6 address. If ai
* is NULL, this will be caught at end of getaddrinfo
*
* Pass zero for IF ID. This is a don't care for
* the case of setting up a server socket.
*/
aiTmp = setAddrInfo(0, (SlNetSock_Addr_t *)&sin6,
SLNETSOCK_AF_INET6, service, hints);
if (aiTmp) {
/*
* The current list (ai) may not be empty. Merge the new
* results (aiTmp) into the existing ai to handle this case.
*/
mergeLists(&ai, &aiTmp);
}
}
}
/* Give user our allocated and initialized addrinfo struct(s) */
*res = ai;
if (!ai) {
/* Our list is empty - memory allocations failed */
return (SLNETUTIL_EAI_MEMORY);
}
return (0);
}
//*****************************************************************************
// SlNetUtil_freeAddrInfo
//*****************************************************************************
void SlNetUtil_freeAddrInfo(struct SlNetUtil_addrInfo_t *res)
{
SlNetUtil_addrInfo_t *aiTmp;
/* Delete all nodes in linked list */
while (res) {
aiTmp = res->ai_next;
free((void *)res);
res = aiTmp;
}
}
//*****************************************************************************
// setAddrInfo
// Intermediate step to handle permutations of ai_socktype and ai_protocol
// hints fields, passed by the user. If both socktype and protocol are 0, must
// create a results struct for each socktype and protocol.
// Returns an empty list (NULL) or a list with one or more nodes.
//*****************************************************************************
static SlNetUtil_addrInfo_t *setAddrInfo(uint16_t ifID, SlNetSock_Addr_t *addr,
int family, const char *service,
const SlNetUtil_addrInfo_t *hints)
{
SlNetUtil_addrInfo_t *ai = NULL;
SlNetUtil_addrInfo_t *aiTmp = NULL;
if ((hints->ai_socktype == 0 && hints->ai_protocol == 0) ||
(hints->ai_socktype == 0 && hints->ai_protocol == SLNETSOCK_PROTO_UDP)
|| (hints->ai_socktype == SLNETSOCK_SOCK_DGRAM &&
hints->ai_protocol == 0) || (hints->ai_socktype == SLNETSOCK_SOCK_DGRAM
&& hints->ai_protocol == SLNETSOCK_PROTO_UDP)) {
ai = createAddrInfo(ifID, addr, family, service, hints->ai_flags,
SLNETSOCK_SOCK_DGRAM, SLNETSOCK_PROTO_UDP);
}
if ((hints->ai_socktype == 0 && hints->ai_protocol == 0) ||
(hints->ai_socktype == 0 && hints->ai_protocol == SLNETSOCK_PROTO_TCP)
|| (hints->ai_socktype == SLNETSOCK_SOCK_STREAM &&
hints->ai_protocol == 0) || (hints->ai_socktype == SLNETSOCK_SOCK_STREAM
&& hints->ai_protocol == SLNETSOCK_PROTO_TCP)) {
aiTmp = createAddrInfo(ifID, addr, family, service, hints->ai_flags,
SLNETSOCK_SOCK_STREAM, SLNETSOCK_PROTO_TCP);
if (aiTmp) {
/* Insert into front of list (assume UDP node was added above) */
aiTmp->ai_next = ai;
ai = aiTmp;
}
}
return (ai);
}
//*****************************************************************************
// createAddrInfo
// Create new address info structure. Returns a single node.
//*****************************************************************************
static SlNetUtil_addrInfo_t *createAddrInfo(uint16_t ifID,
SlNetSock_Addr_t *addr, int family, const char *service, int flags,
int socktype, int protocol)
{
SlNetUtil_addrInfo_t *ai = NULL;
/*
* Allocate memory for the addrinfo struct, which we must fill out and
* return to the caller. This struct also has a pointer to a generic socket
* address struct, which will point to either struct sockaddr_in, or
* struct sockaddr_in6, depending. Need to allocate enough space to hold
* that struct, too.
*/
ai = (SlNetUtil_addrInfo_t *)calloc(1, SLNETUTIL_ADDRINFO_ALLOCSZ);
if (!ai) {
/* Error: memory allocation failed */
return (NULL);
}
ai->ai_flags = flags;
ai->ai_socktype = socktype;
ai->ai_protocol = protocol;
ai->ai_canonname = NULL;
ai->ai_next = NULL;
/* Store socket addr struct after the addrinfo struct in our memory block */
ai->ai_addr = (SlNetSock_Addr_t *)(ai + 1);
if (family == SLNETSOCK_AF_INET) {
/* Fill in structure for IPv4 */
ai->ai_family = SLNETSOCK_AF_INET;
ai->ai_addrlen = sizeof(SlNetSock_AddrIn_t);
/* Write values to addrinfo's socket struct as an sockaddr_in struct */
((SlNetSock_AddrIn_t *)ai->ai_addr)->sin_family = SLNETSOCK_AF_INET;
((SlNetSock_AddrIn_t *)ai->ai_addr)->sin_port =
SlNetUtil_htons(atoi(service));
((SlNetSock_AddrIn_t *)ai->ai_addr)->sin_addr =
((SlNetSock_AddrIn_t *)addr)->sin_addr;
}
else {
/* Fill in structure for IPv6 */
ai->ai_family = SLNETSOCK_AF_INET6;
ai->ai_addrlen = sizeof(SlNetSock_AddrIn6_t);
/* Write values to addrinfo's socket struct as an sockaddr_in6 struct */
((SlNetSock_AddrIn6_t *)ai->ai_addr)->sin6_family = SLNETSOCK_AF_INET6;
((SlNetSock_AddrIn6_t *)ai->ai_addr)->sin6_port =
SlNetUtil_htons(atoi(service));
memcpy(&(((SlNetSock_AddrIn6_t *)ai->ai_addr)->sin6_addr),
&(((SlNetSock_AddrIn6_t *)addr)->sin6_addr),
sizeof(SlNetSock_In6Addr_t));
/* Scope ID should have been determined correctly by the caller */
((SlNetSock_AddrIn6_t *)ai->ai_addr)->sin6_scope_id = (uint32_t)ifID;
}
return (ai);
}
//*****************************************************************************
// mergeLists
// Combines an existing linked list of addrinfo structs (curList) and a newly
// obtained list (newList) into a single list. If the existing list is empty,
// it will be initialized to the new list. If both lists are empty, no action
// is taken.
//*****************************************************************************
static int mergeLists(SlNetUtil_addrInfo_t **curList,
SlNetUtil_addrInfo_t **newList)
{
int numNodes = 0;
SlNetUtil_addrInfo_t *tail = NULL;
/* Check params */
if (!curList || !newList || !(*newList)) {
return (numNodes);
}
/* Update node count & find end of new list */
for (tail = *newList; tail != NULL;) {
numNodes++;
if (tail->ai_next != NULL) {
/* Not the tail, keep traversing */
tail = tail->ai_next;
}
else {
/* Tail found, quit loop */
break;
}
}
/* Append current list to end of new list */
tail->ai_next = *curList;
*curList = *newList;
return (numNodes);
}
//*****************************************************************************
//
// SlNetUtil_htonl - Reorder the bytes of a 32-bit unsigned value from host
// order to network order(Big endian)
//
//*****************************************************************************
uint32_t SlNetUtil_htonl(uint32_t val)
{
uint32_t i = 1;
int8_t *p = (int8_t *)&i;
/* When the LSB of i stored in the smallest address of *p */
if (p[0] == 1) /* little endian */
{
/* Swap the places of the value */
p[0] = ((int8_t *)&val)[3];
p[1] = ((int8_t *)&val)[2];
p[2] = ((int8_t *)&val)[1];
p[3] = ((int8_t *)&val)[0];
/* return the reordered bytes */
return i;
}
else /* big endian */
{
/* return the input without any changes */
return val;
}
}
//*****************************************************************************
//
// SlNetUtil_ntohl - Reorder the bytes of a 32-bit unsigned value from network
// order(Big endian) to host order
//
//*****************************************************************************
uint32_t SlNetUtil_ntohl(uint32_t val)
{
/* return the reordered bytes */
return SlNetUtil_htonl(val);
}
//*****************************************************************************
//
// SlNetUtil_htons - Reorder the bytes of a 16-bit unsigned value from host
// order to network order(Big endian)
//
//*****************************************************************************
uint16_t SlNetUtil_htons(uint16_t val)
{
int16_t i = 1;
int8_t *p = (int8_t *)&i;
/* When the LSB of i stored in the smallest address of *p */
if (p[0] == 1) /* little endian */
{
/* Swap the places of the value */
p[0] = ((int8_t *)&val)[1];
p[1] = ((int8_t *)&val)[0];
/* return the reordered bytes */
return (uint16_t)i;
}
else /* big endian */
{
/* return the input without any changes */
return val;
}
}
//*****************************************************************************
//
// SlNetUtil_ntohs - Reorder the bytes of a 16-bit unsigned value from network
// order(Big endian) to host order
//
//*****************************************************************************
uint16_t SlNetUtil_ntohs(uint16_t val)
{
/* return the reordered bytes */
return SlNetUtil_htons(val);
}
//*****************************************************************************
//
// SlNetUtil_UTOA - converts unsigned 16 bits binary number to string with
// maximum of 4 characters + 1 NULL terminated
//
//*****************************************************************************
static int32_t SlNetUtil_UTOA(uint16_t value, char * string, uint16_t base)
{
uint16_t Index = 4;
char tempString[5] = { 0 };
char * ptempString = tempString;
char * pString = string;
/* Check if the inputs valid */
if ( (NULL == string) || ((base < 2 ) && (base > 16 )) )
{
return SLNETERR_RET_CODE_INVALID_INPUT;
}
/* If value is zero, that means that the returned string needs to be zero*/
if (0 == value)
{
*ptempString = '0';
ptempString++;
Index--;
}
/* Run until all value digits are 0 or until Index get to 0 */
for (; (value && (Index > 0)); Index--, value /= base)
{
*ptempString = "0123456789abcdef"[value % base];
ptempString++;
}
/* Invalid value input */
if (0 != value)
{
return SLNETERR_RET_CODE_INVALID_INPUT;
}
/* Reverse the string and initialize temporary array */
while (Index < 4)
{
*(pString++) = *(--ptempString);
*ptempString = '\0';
*pString = '\0';
Index++;
}
return 0;
}
//*****************************************************************************
//
// SlNetUtil_bin2StrIpV4 - converts IPv4 address in binary representation
// (network byte order) to IP address in string
// representation
//
//*****************************************************************************
static int32_t SlNetUtil_bin2StrIpV4(SlNetSock_InAddr_t *binaryAddr, char *strAddr, uint16_t strAddrLen)
{
uint8_t tempOctet;
uint32_t tempBinAddr;
int32_t octetIndex = 0;
char tempStrOctet[4] = { 0 };
/* Check if the strAddr buffer is at least in the minimum required size */
if (strAddrLen < SLNETSOCK_INET_ADDRSTRLEN)
{
/* Return error code */
return SLNETERR_RET_CODE_INVALID_INPUT;
}
/* initialize strAddr to an empty string (so we can strcat() later) */
strAddr[0] = '\0';
/* Copy the address value for further use */
memcpy(&tempBinAddr, binaryAddr, sizeof(SlNetSock_InAddr_t));
/* Run over all octets (in network byte order), starting with the
most significant octet and ending with the least significant octet */
while ( octetIndex <= 3 )
{
/* Save octet on tempOctet for further usage.
When converting from binary representation to string
representation, the MSO of the binary number is the first char
of the string, so it needs to copied to the first location of
the array */
tempOctet = ((int8_t *)&tempBinAddr)[octetIndex];
/* Initialize the octet for validation after copying the value */
((int8_t *)&tempBinAddr)[octetIndex] = 0;
/* Convert tempOctet to string */
SlNetUtil_UTOA(tempOctet, tempStrOctet, 10);
/* Appends the tempStrOctet to strAddr */
strcat(strAddr, tempStrOctet);
/* Appends the "." to strAddr for the first 3 octets */
if ( octetIndex < 3)
{
strcat(strAddr, ".");
}
/* Move to the next octet */
octetIndex ++;
}
/* Check if the address had only 4 octets, this was done by initializing
each octet that was copied and than checking if the number equal to 0 */
if ( 0 == tempBinAddr )
{
/* Return success */
return SLNETERR_RET_CODE_OK;
}
else
{
/* Return error code */
return SLNETERR_RET_CODE_INVALID_INPUT;
}
}
//*****************************************************************************
//
// SlNetUtil_bin2StrIpV6 - converts IPv6 address in binary representation to
// IP address in string representation
//
//*****************************************************************************
static int32_t SlNetUtil_bin2StrIpV6(SlNetSock_In6Addr_t *binaryAddr, char *strAddr, uint16_t strAddrLen)
{
uint16_t tempHextet;
int32_t hextetIndex = 0;
uint8_t tempBinAddr[16] = { 0 };
char tempStrHextet[5] = { 0 };
/* Check if the strAddr buffer is at least in the minimum required size */
if (strAddrLen < SLNETSOCK_INET6_ADDRSTRLEN)
{
/* Return error code */
return SLNETERR_RET_CODE_INVALID_INPUT;
}
/* initialize strAddr to an empty string (so we can strcat() later) */
strAddr[0] = '\0';
/* Copy the address value for further use */
memcpy(tempBinAddr, binaryAddr, sizeof(SlNetSock_In6Addr_t));
/* Run over all octets, from the latest hextet (the most significant
hextet) until the first one (the least significant hextet) */
while (hextetIndex < 8)
{
/* Save hextet on tempHextet for further usage.
When converting from binary representation to string
representation, the most significant hextet of the binary number
is the first char of the string, so it needs to copied to the
first location of the array */
tempHextet = (tempBinAddr[hextetIndex * 2] << 8) |
(tempBinAddr[(hextetIndex * 2) + 1]);
/* Convert tempHextet to string */
SlNetUtil_UTOA(tempHextet, tempStrHextet, 16);
/* Appends the tempStrHextet to strAddr */
strcat(strAddr, tempStrHextet);
/* Appends the ":" after each hextet (without the last one) */
if (hextetIndex < 7)
{
strcat(strAddr, ":");
}
/* Move to the next hextet */
hextetIndex++;
}
/* Return success */
return SLNETERR_RET_CODE_OK;
}
//*****************************************************************************
//
// SlNetUtil_inetNtop - converts IP address in binary representation to IP
// address in string representation
//
//*****************************************************************************
const char *SlNetUtil_inetNtop(int16_t addrFamily, const void *binaryAddr, char *strAddr, SlNetSocklen_t strAddrLen)
{
int32_t retVal;
/* Switch according to the address family */
switch(addrFamily)
{
case SLNETSOCK_AF_INET:
/* Convert from IPv4 string to numeric/binary representation */
retVal = SlNetUtil_bin2StrIpV4((SlNetSock_InAddr_t *)binaryAddr, strAddr, strAddrLen);
break;
case SLNETSOCK_AF_INET6:
/* Convert from IPv6 string to numeric/binary representation */
retVal = SlNetUtil_bin2StrIpV6((SlNetSock_In6Addr_t *)binaryAddr, strAddr, strAddrLen);
break;
default:
/* wrong address family - function error, return NULL error */
return NULL;
}
/* Check if conversion was successful */
if (retVal != SLNETERR_RET_CODE_OK)
{
/* Conversion failed, return NULL as error code */
return NULL;
}
/* Conversion success - return strAddr for success */
return strAddr;
}
//*****************************************************************************
//
// SlNetUtil_strTok - Split a string up into tokens
//
//*****************************************************************************
static int32_t SlNetUtil_strTok(char **string, char *returnstring, const char *delimiter)
{
char * retStr;
retStr = returnstring;
while ( (**string !='\0') && (**string != *delimiter) )
{
*retStr = **string;
retStr++;
(*string)++;
}
if (**string !='\0')
{
(*string)++;
}
*retStr = '\0';
return SLNETERR_RET_CODE_OK;
}
//*****************************************************************************
//
// SlNetUtil_str2BinIpV4 - converts IPv4 address in string representation to
// IP address in binary representation
//
//*****************************************************************************
static int32_t SlNetUtil_str2BinIpV4(char *strAddr, SlNetSock_InAddr_t *binaryAddr)
{
uint32_t decNumber;
char token[4];
int32_t retVal;
int32_t ipOctet = 0;
uint32_t ipv4Address = 0;
char *modifiedStr = strAddr;
/* split strAddr into tokens separated by "." */
retVal = SlNetUtil_strTok(&modifiedStr, token, ".");
if (SLNETERR_RET_CODE_OK != retVal)
{
return retVal;
}
/* run 4 times as IPv4 contain of four octets and separated by periods */
while(ipOctet < 4)
{
/* Check Whether IP is valid */
if(token != NULL)
{
/* Parses the token strAddr, interpreting its content as an integral
number of the specified base 10 */
decNumber = (int)strtoul(token, 0, 10);
/* Check if the octet holds valid number between the range 0-255 */
if (decNumber < 256)
{
/* manually place each byte in network order */
((int8_t *)&ipv4Address)[ipOctet] = (uint8_t)decNumber;
/* split strAddr into tokens separated by "." */
SlNetUtil_strTok(&modifiedStr, token, ".");
ipOctet++;
}
else
{
return SLNETERR_RET_CODE_INVALID_INPUT;
}
}
else
{
return SLNETERR_RET_CODE_INVALID_INPUT;
}
}
/* Copy the temporary variable to the input variable */
memcpy(binaryAddr, &ipv4Address, sizeof(SlNetSock_InAddr_t));
return SLNETERR_RET_CODE_OK;
}
//*****************************************************************************
//
// SlNetUtil_str2BinIpV6 - converts IPv6 address in string representation to
// IP address in binary representation
//
//*****************************************************************************
static int32_t SlNetUtil_str2BinIpV6(char *strAddr, SlNetSock_In6Addr_t *binaryAddr)
{
int32_t octetIndex = 0;
int32_t octetTailIndex;
uint8_t *pLocalStr;
uint8_t tmp[16];
int32_t zeroCompressPos = -1;
uint16_t value = 0;
uint8_t asciiCharacter = 0;
/* Copy the first address of the string */
pLocalStr = (uint8_t *)strAddr;
/* Initialize tmp parameter */
memset(tmp, 0, sizeof(tmp));
/* Check if the IP starts with "::" */
if(*pLocalStr==':')
{
/* If the IP starts with ":", check if it doesn't have the second ":"
If so, return an error */
if(*++pLocalStr!=':')
{
return SLNETERR_RET_CODE_INVALID_INPUT;
}
}
/* run over the remaining two octets */
while(*pLocalStr && (octetIndex < 16))
{
/* Check if the ASCII character is a number between "0" to "9" */
if(*pLocalStr >= '0' && *pLocalStr <= '9')
{
/* Each ASCII character can be max 4 bits, shift the number
4 bits and copy the new converted number */
value = (value << 4) | (*pLocalStr - '0');
/* Set the flag for ASCII character */
asciiCharacter = 1;
}
/* Check if the ASCII character is a hex character between "a" to "f"*/
else if(*pLocalStr >= 'a' && *pLocalStr <= 'f')
{
/* Each ASCII character can be max 4 bits, shift the number
4 bits and copy the new converted number */
value = (value << 4) | ((*pLocalStr - 'a') + 10);
/* Set the flag for ASCII character */
asciiCharacter = 1;
}
/* Check if the ASCII character is a hex character between "A" to "F"*/
else if(*pLocalStr >= 'A' && *pLocalStr <= 'F')
{
/* Each ASCII character can be max 4 bits, shift the number
4 bits and copy the new converted number */
value = (value << 4) | ((*pLocalStr - 'A') + 10);
/* Set the flag for ASCII character */
asciiCharacter = 1;
}
/* Check if the hextet (two octets) finished with ":" and still a
part of the IP */
else if((*pLocalStr == ':') && (octetIndex < 14))
{
/* Check if the hextet contain ASCII character */
if(asciiCharacter)
{
/* ASCII character exists, store the converted number in tmp
and reset the value and ascii character parameters */
tmp[octetIndex++] = (value >> 8) & 0xFF;
tmp[octetIndex++] = (value) & 0xFF;
asciiCharacter = 0;
value = 0;
}
else
{
/* ASCII character doesn't exists, compressed hextet found */
if(zeroCompressPos < 0)
{
/* first compressed hextet found, sore the octet Index */
zeroCompressPos = octetIndex;
}
else
{
/* Second compressed hextet found, return error code */
return SLNETERR_RET_CODE_INVALID_INPUT;
}
}
}
/* Continue to the next ASCII character */
pLocalStr++;
}
/* if more than 15 octets found, return error code */
if(octetIndex > 15)
{
return SLNETERR_RET_CODE_INVALID_INPUT;
}
/* if less than 14 octets found, and without any compress hextet,
return error code */
else if(asciiCharacter && (zeroCompressPos < 0) && (octetIndex < 14))
{
return SLNETERR_RET_CODE_INVALID_INPUT;
}
/* if all octets found, but still found compressed hextet,
return error code */
else if((zeroCompressPos >= 0) && octetIndex >= 14)
{
return SLNETERR_RET_CODE_INVALID_INPUT;
}
/* copy the last available hextet to the tmp array */
if((asciiCharacter) && (octetIndex <= 14))
{
/* Store the converted number in tmp and reset the value and
ascii character parameters */
tmp[octetIndex++] = (value >> 8) & 0xFF;
tmp[octetIndex++] = (value) & 0xFF;
asciiCharacter = 0;
value = 0;
}
/* compressed position found, add zeros in the compressed sections */
if(zeroCompressPos >= 0)
{
/* compressed position found, add zeros in the compressed sections */
octetIndex--;
octetTailIndex = 15;
/* Move the converted octets from the position they are located on
to the end of the array and add zero instead */
while(octetIndex >= zeroCompressPos)
{
/* Check if the indexes are still in range */
if ((octetTailIndex >= 0) && (octetIndex >= 0))
{
/* Move all the octets after the zero compress position to
the end of the array */
tmp[octetTailIndex] = tmp[octetIndex];
tmp[octetIndex] = 0;
octetTailIndex--;
octetIndex--;
}
}
}
/* Copy the temporary variable to the input variable */
memcpy(binaryAddr, tmp, sizeof(tmp));
return SLNETERR_RET_CODE_OK;
}
//*****************************************************************************
//
// SlNetUtil_inetAton - Converts a string to a network address structure
//
//*****************************************************************************
int SlNetUtil_inetAton(const char *str, SlNetSock_InAddr_t *addr)
{
uint32_t val[4];
uint32_t base;
int sect;
char c;
sect = -1;
while (*str) {
/* New section */
sect++;
/* Get the base for this number */
base = 10;
if (*str == '0')
{
if (*(str + 1) == 'x' || *(str + 1) == 'X') {
base = 16;
str += 2;
}
else {
base = 8;
str++;
}
}
/* Now decode this number */
val[sect] = 0;
for (;;) {
c = *str++;
if ((c >= '0' && c <= '9')) {
val[sect] = (val[sect] * base) + (c - '0');
}
else if (base == 16 && (c >= 'A' && c <= 'F')) {
val[sect] = (val[sect] * 16) + (c - 'A') + 10;
}
else if (base == 16 && (c >= 'a' && c <= 'f')) {
val[sect] = (val[sect] * 16) + (c - 'a') + 10;
}
else if (c == '.') {
/* validate value */
if(val[sect] > 255) {
return (0);
}
/*
* Once we have four sections, quit.
* We want to accept: "1.2.3.4.in-addr.arpa"
*/
if (sect == 3) {
goto done;
}
/* Break this section */
break;
}
else if (!c) {
goto done;
}
else if (c != ' ') {
return (0);
}
}
}
done:
/* What we do changes based on the number of sections */
switch (sect) {
case 0:
addr->s_addr = val[0];
break;
case 1:
if (val[1] > 0xffffff) {
return (0);
}
addr->s_addr = val[0] << 24;
addr->s_addr += val[1];
break;
case 2:
if (val[2] > 0xffff) {
return (0);
}
addr->s_addr = val[0] << 24;
addr->s_addr += (val[1] << 16);
addr->s_addr += val[2];
break;
case 3:
if (val[3] > 0xff) {
return (0);
}
addr->s_addr = val[0] << 24;
addr->s_addr += (val[1] << 16);
addr->s_addr += (val[2] << 8);
addr->s_addr += val[3];
break;
default:
return (0);
}
addr->s_addr = SlNetUtil_htonl(addr->s_addr);
return (1);
}
//*****************************************************************************
//
// SlNetUtil_inetPton - converts IP address in string representation to IP
// address in binary representation
//
//*****************************************************************************
int32_t SlNetUtil_inetPton(int16_t addrFamily, const char *strAddr, void *binaryAddr)
{
int32_t retVal;
/* Switch according to the address family */
switch(addrFamily)
{
case SLNETSOCK_AF_INET:
/* Convert from IPv4 string to numeric/binary representation */
retVal = SlNetUtil_str2BinIpV4((char *)strAddr, (SlNetSock_InAddr_t *)binaryAddr);
break;
case SLNETSOCK_AF_INET6:
/* Convert from IPv6 string to numeric/binary representation */
retVal = SlNetUtil_str2BinIpV6((char *)strAddr, (SlNetSock_In6Addr_t *)binaryAddr);
break;
default:
/* wrong address family - function error, return -1 error */
return SLNETERR_RET_CODE_INVALID_INPUT;
}
/* Check if conversion was successful */
if (retVal != SLNETERR_RET_CODE_OK)
{
/* Conversion failed, that means the input wasn't a
valid IP address, return 0 as error code */
return 0;
}
/* Conversion success - return 1 for success */
return 1;
}