curl/lib/curlx/inet_ntop.c
Viktor Szakats 554dfa5568
build: drop Windows CE / CeGCC support
Windows CE support was limited to successful builds with ming32ce
(a toolchain that hasn't seen an update since 2009, using an ancient gcc
version and "old mingw"-style SDK headers, that curl deprecated earlier).
Builds with MSVC were broken for a long time. mingw32ce builds were never
actually tested and runtime and unlikely to work due to missing stubs.
Windows CE toolchains also miss to comply with C89. Paired with lack of
demand and support for the platform, curl deprecated it earlier.

This patch removes support from the codebase to ease maintaining Windows
codepaths.

Follow-up to f98c0ba834 #17924
Follow-up to 8491e6574c #17379
Follow-up to 2a292c3984 #15975

Closes #17927
2025-11-15 15:35:23 +01:00

222 lines
6.1 KiB
C

/*
* Copyright (C) 1996-2022 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* SPDX-License-Identifier: ISC
*/
#include "../curl_setup.h"
#ifndef HAVE_INET_NTOP
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include "inet_ntop.h"
#define IN6ADDRSZ 16
/* #define INADDRSZ 4 */
#define INT16SZ 2
/*
* If USE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
* sure we have _some_ value for AF_INET6 without polluting our fake value
* everywhere.
*/
#if !defined(USE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif
/*
* Format an IPv4 address, more or less like inet_ntop().
*
* Returns `dst' (as a const)
* Note:
* - uses no static variables
* - takes an unsigned char* not an in_addr as input
*/
static char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
{
char tmp[sizeof("255.255.255.255")];
size_t len;
DEBUGASSERT(size >= 16);
/* this sprintf() does not overflow the buffer. Avoids snprintf to work more
widely. Avoids the msnprintf family to work as a curlx function. */
(void)(sprintf)(tmp, "%d.%d.%d.%d",
((int)((unsigned char)src[0])) & 0xff,
((int)((unsigned char)src[1])) & 0xff,
((int)((unsigned char)src[2])) & 0xff,
((int)((unsigned char)src[3])) & 0xff);
len = strlen(tmp);
if(len == 0 || len >= size) {
#ifdef USE_WINSOCK
errno = WSAEINVAL;
#else
errno = ENOSPC;
#endif
return NULL;
}
strcpy(dst, tmp);
return dst;
}
/*
* Convert IPv6 binary address into presentation (printable) format.
*/
static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
{
/*
* Note that int32_t and int16_t need only be "at least" large enough
* to contain a value of the specified size. On some systems, like
* Crays, there is no such thing as an integer variable with 16 bits.
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
char *tp;
struct {
int base;
int len;
} best, cur;
unsigned int words[IN6ADDRSZ / INT16SZ];
int i;
/* Preprocess:
* Copy the input (bytewise) array into a wordwise array.
* Find the longest run of 0x00's in src[] for :: shorthanding.
*/
memset(words, '\0', sizeof(words));
for(i = 0; i < IN6ADDRSZ; i++)
words[i/2] |= ((unsigned int)src[i] << ((1 - (i % 2)) << 3));
best.base = -1;
cur.base = -1;
best.len = 0;
cur.len = 0;
for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
if(words[i] == 0) {
if(cur.base == -1) {
cur.base = i; cur.len = 1;
}
else
cur.len++;
}
else if(cur.base != -1) {
if(best.base == -1 || cur.len > best.len)
best = cur;
cur.base = -1;
}
}
if((cur.base != -1) && (best.base == -1 || cur.len > best.len))
best = cur;
if(best.base != -1 && best.len < 2)
best.base = -1;
/* Format the result. */
tp = tmp;
for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
/* Are we inside the best run of 0x00's? */
if(best.base != -1 && i >= best.base && i < (best.base + best.len)) {
if(i == best.base)
*tp++ = ':';
continue;
}
/* Are we following an initial run of 0x00s or any real hex?
*/
if(i)
*tp++ = ':';
/* Is this address an encapsulated IPv4?
*/
if(i == 6 && best.base == 0 &&
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) {
return NULL;
}
tp += strlen(tp);
break;
}
else {
/* Lower-case digits. Cannot use the set from mprintf.c since this
needs to work as a curlx function */
static const unsigned char ldigits[] = "0123456789abcdef";
unsigned int w = words[i];
/* output lowercase 16bit hex number but ignore leading zeroes */
if(w & 0xf000)
*tp++ = ldigits[(w & 0xf000) >> 12];
if(w & 0xff00)
*tp++ = ldigits[(w & 0x0f00) >> 8];
if(w & 0xfff0)
*tp++ = ldigits[(w & 0x00f0) >> 4];
*tp++ = ldigits[(w & 0x000f)];
}
}
/* Was it a trailing run of 0x00's?
*/
if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
*tp++ = ':';
*tp++ = '\0';
/* Check for overflow, copy, and we are done.
*/
if((size_t)(tp - tmp) > size) {
#ifdef USE_WINSOCK
errno = WSAEINVAL;
#else
errno = ENOSPC;
#endif
return NULL;
}
strcpy(dst, tmp);
return dst;
}
/*
* Convert a network format address to presentation format.
*
* Returns pointer to presentation format address (`buf').
* Returns NULL on error and errno set with the specific
* error, EAFNOSUPPORT or ENOSPC.
*
* On Windows we store the error in the thread errno, not in the Winsock error
* code. This is to avoid losing the actual last Winsock error. When this
* function returns NULL, check errno not SOCKERRNO.
*/
char *curlx_inet_ntop(int af, const void *src, char *buf, size_t size)
{
switch(af) {
case AF_INET:
return inet_ntop4((const unsigned char *)src, buf, size);
case AF_INET6:
return inet_ntop6((const unsigned char *)src, buf, size);
default:
errno = SOCKEAFNOSUPPORT;
return NULL;
}
}
#endif /* HAVE_INET_NTOP */