in demo_example/asio/asio/detail/impl/socket_ops.ipp [2524:2778]
int inet_pton(int af, const char* src, void* dest,
unsigned long* scope_id, asio::error_code& ec)
{
clear_last_error();
#if defined(ASIO_WINDOWS_RUNTIME)
using namespace std; // For sscanf.
unsigned char* bytes = static_cast<unsigned char*>(dest);
if (af == ASIO_OS_DEF(AF_INET))
{
unsigned int b0, b1, b2, b3;
if (sscanf_s(src, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) != 4)
{
ec = asio::error::invalid_argument;
return -1;
}
if (b0 > 255 || b1 > 255 || b2 > 255 || b3 > 255)
{
ec = asio::error::invalid_argument;
return -1;
}
bytes[0] = static_cast<unsigned char>(b0);
bytes[1] = static_cast<unsigned char>(b1);
bytes[2] = static_cast<unsigned char>(b2);
bytes[3] = static_cast<unsigned char>(b3);
ec.assign(0, ec.category());
return 1;
}
else if (af == ASIO_OS_DEF(AF_INET6))
{
unsigned char* bytes = static_cast<unsigned char*>(dest);
std::memset(bytes, 0, 16);
unsigned char back_bytes[16] = { 0 };
int num_front_bytes = 0, num_back_bytes = 0;
const char* p = src;
enum { fword, fcolon, bword, scope, done } state = fword;
unsigned long current_word = 0;
while (state != done)
{
if (current_word > 0xFFFF)
{
ec = asio::error::invalid_argument;
return -1;
}
switch (state)
{
case fword:
if (*p >= '0' && *p <= '9')
current_word = current_word * 16 + *p++ - '0';
else if (*p >= 'a' && *p <= 'f')
current_word = current_word * 16 + *p++ - 'a' + 10;
else if (*p >= 'A' && *p <= 'F')
current_word = current_word * 16 + *p++ - 'A' + 10;
else
{
if (num_front_bytes == 16)
{
ec = asio::error::invalid_argument;
return -1;
}
bytes[num_front_bytes++] = (current_word >> 8) & 0xFF;
bytes[num_front_bytes++] = current_word & 0xFF;
current_word = 0;
if (*p == ':')
state = fcolon, ++p;
else if (*p == '%')
state = scope, ++p;
else if (*p == 0)
state = done;
else
{
ec = asio::error::invalid_argument;
return -1;
}
}
break;
case fcolon:
if (*p == ':')
state = bword, ++p;
else
state = fword;
break;
case bword:
if (*p >= '0' && *p <= '9')
current_word = current_word * 16 + *p++ - '0';
else if (*p >= 'a' && *p <= 'f')
current_word = current_word * 16 + *p++ - 'a' + 10;
else if (*p >= 'A' && *p <= 'F')
current_word = current_word * 16 + *p++ - 'A' + 10;
else
{
if (num_front_bytes + num_back_bytes == 16)
{
ec = asio::error::invalid_argument;
return -1;
}
back_bytes[num_back_bytes++] = (current_word >> 8) & 0xFF;
back_bytes[num_back_bytes++] = current_word & 0xFF;
current_word = 0;
if (*p == ':')
state = bword, ++p;
else if (*p == '%')
state = scope, ++p;
else if (*p == 0)
state = done;
else
{
ec = asio::error::invalid_argument;
return -1;
}
}
break;
case scope:
if (*p >= '0' && *p <= '9')
current_word = current_word * 10 + *p++ - '0';
else if (*p == 0)
*scope_id = current_word, state = done;
else
{
ec = asio::error::invalid_argument;
return -1;
}
break;
default:
break;
}
}
for (int i = 0; i < num_back_bytes; ++i)
bytes[16 - num_back_bytes + i] = back_bytes[i];
ec.assign(0, ec.category());
return 1;
}
else
{
ec = asio::error::address_family_not_supported;
return -1;
}
#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
using namespace std; // For memcpy and strcmp.
if (af != ASIO_OS_DEF(AF_INET) && af != ASIO_OS_DEF(AF_INET6))
{
ec = asio::error::address_family_not_supported;
return -1;
}
union
{
socket_addr_type base;
sockaddr_storage_type storage;
sockaddr_in4_type v4;
sockaddr_in6_type v6;
} address;
int address_length = sizeof(sockaddr_storage_type);
#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800))
int num_wide_chars = static_cast<int>(strlen(src)) + 1;
LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
int result = ::WSAStringToAddressW(wide_buffer,
af, 0, &address.base, &address_length);
get_last_error(ec, true);
#else
int result = ::WSAStringToAddressA(const_cast<char*>(src),
af, 0, &address.base, &address_length);
get_last_error(ec, true);
#endif
if (af == ASIO_OS_DEF(AF_INET))
{
if (result != socket_error_retval)
{
memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
ec.assign(0, ec.category());
}
else if (strcmp(src, "255.255.255.255") == 0)
{
static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
ec.assign(0, ec.category());
}
}
else // AF_INET6
{
if (result != socket_error_retval)
{
memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));
if (scope_id)
*scope_id = address.v6.sin6_scope_id;
ec.assign(0, ec.category());
}
}
// Windows may not set an error code on failure.
if (result == socket_error_retval && !ec)
ec = asio::error::invalid_argument;
if (result != socket_error_retval)
ec.assign(0, ec.category());
return result == socket_error_retval ? -1 : 1;
#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
using namespace std; // For strchr, memcpy and atoi.
// On some platforms, inet_pton fails if an address string contains a scope
// id. Detect and remove the scope id before passing the string to inet_pton.
const bool is_v6 = (af == ASIO_OS_DEF(AF_INET6));
const char* if_name = is_v6 ? strchr(src, '%') : 0;
char src_buf[max_addr_v6_str_len + 1];
const char* src_ptr = src;
if (if_name != 0)
{
if (if_name - src > max_addr_v6_str_len)
{
ec = asio::error::invalid_argument;
return 0;
}
memcpy(src_buf, src, if_name - src);
src_buf[if_name - src] = 0;
src_ptr = src_buf;
}
int result = ::inet_pton(af, src_ptr, dest);
get_last_error(ec, true);
if (result <= 0 && !ec)
ec = asio::error::invalid_argument;
if (result > 0 && is_v6 && scope_id)
{
using namespace std; // For strchr and atoi.
*scope_id = 0;
if (if_name != 0)
{
in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe)
&& ((ipv6_address->s6_addr[1] & 0xc0) == 0x80));
bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff)
&& ((ipv6_address->s6_addr[1] & 0x0f) == 0x02));
if (is_link_local || is_multicast_link_local)
*scope_id = if_nametoindex(if_name + 1);
if (*scope_id == 0)
*scope_id = atoi(if_name + 1);
}
}
return result;
#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
}