blob: 2a7ff008a3c552b3b4050031d2e7c3d3561a5f66 [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2013-2017 Nest Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file implements the human-readable string formatting and
* parsing methods from class <tt>Inet::IPAddress</tt>.
*
*/
#include <algorithm>
#include <limits>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <inet/IPAddress.h>
#include <lib/support/CodeUtils.h>
#if CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
#include <arpa/inet.h>
#endif
namespace chip {
namespace Inet {
char * IPAddress::ToString(char * buf, uint32_t bufSize) const
{
#if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
#if INET_CONFIG_ENABLE_IPV4
if (IsIPv4())
{
ip4_addr_t ip4_addr = ToIPv4();
ip4addr_ntoa_r(&ip4_addr, buf, (int) bufSize);
}
else
#endif // INET_CONFIG_ENABLE_IPV4
{
ip6_addr_t ip6_addr = ToIPv6();
ip6addr_ntoa_r(&ip6_addr, buf, (int) bufSize);
}
#elif CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
// socklen_t is sometimes signed, sometimes not, so the only safe way to do
// this is to promote everything to an unsigned type that's known to be big
// enough for everything, then cast back to uint32_t after taking the min.
bufSize = static_cast<uint32_t>(
std::min(static_cast<uintmax_t>(std::numeric_limits<socklen_t>::max()), static_cast<uintmax_t>(bufSize)));
#if INET_CONFIG_ENABLE_IPV4
if (IsIPv4())
{
const void * addr = &Addr[3];
const char * s = inet_ntop(AF_INET, addr, buf, static_cast<socklen_t>(bufSize));
// This cast is safe because |s| points into |buf| which is not const.
buf = const_cast<char *>(s);
}
else
#endif // INET_CONFIG_ENABLE_IPV4
{
const void * addr = &Addr[0];
const char * s = inet_ntop(AF_INET6, addr, buf, static_cast<socklen_t>(bufSize));
// This cast is safe because |s| points into |buf| which is not const.
buf = const_cast<char *>(s);
}
#elif CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
otIp6Address addr = ToIPv6();
otIp6AddressToString(&addr, buf, static_cast<uint16_t>(bufSize));
#endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
return buf;
}
bool IPAddress::FromString(const char * str, IPAddress & output)
{
#if INET_CONFIG_ENABLE_IPV4
if (strchr(str, ':') == nullptr)
{
#if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
ip4_addr_t ipv4Addr;
if (!ip4addr_aton(str, &ipv4Addr))
return false;
#elif CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
struct in_addr ipv4Addr;
if (inet_pton(AF_INET, str, &ipv4Addr) < 1)
return false;
#endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
output = IPAddress(ipv4Addr);
}
else
#endif // INET_CONFIG_ENABLE_IPV4
{
#if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
ip6_addr_t ipv6Addr;
if (!ip6addr_aton(str, &ipv6Addr))
return false;
#elif CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
struct in6_addr ipv6Addr;
if (inet_pton(AF_INET6, str, &ipv6Addr) < 1)
return false;
#elif CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
otIp6Address ipv6Addr;
if (OT_ERROR_NONE != otIp6AddressFromString(str, &ipv6Addr))
return false;
#endif
output = IPAddress(ipv6Addr);
}
return true;
}
bool IPAddress::FromString(const char * str, size_t strLen, IPAddress & output)
{
bool res = false;
if (strLen < INET6_ADDRSTRLEN)
{
char hostNameBuf[INET6_ADDRSTRLEN];
memcpy(hostNameBuf, str, strLen);
hostNameBuf[strLen] = 0;
res = IPAddress::FromString(hostNameBuf, output);
}
return res;
}
bool IPAddress::FromString(const char * str, IPAddress & addrOutput, class InterfaceId & ifaceOutput)
{
char * addrStr = const_cast<char *>(str);
char * addrPart = nullptr;
char * scopePart = nullptr;
char * strtokContext = nullptr;
addrPart = strtok_r(addrStr, "%", &strtokContext);
if (addrPart != nullptr)
{
scopePart = strtok_r(nullptr, "%", &strtokContext);
}
if (addrPart == nullptr || scopePart == nullptr)
{
ifaceOutput = Inet::InterfaceId();
return Inet::IPAddress::FromString(addrStr, addrOutput);
}
CHIP_ERROR err = Inet::InterfaceId::InterfaceNameToId(scopePart, ifaceOutput);
if (err != CHIP_NO_ERROR)
{
return false;
}
return Inet::IPAddress::FromString(addrPart, addrOutput);
}
} // namespace Inet
} // namespace chip