mirror of
https://github.com/curl/curl.git
synced 2026-04-11 12:01:42 +08:00
Backtrack on previous change that aimed to solve the wrong `share.h` being included. It turns out it did not fix this issue. At the same time it introduced relative header filenames and the need to include the same headers differently depending on the source files' location, reducing readability and editability. Replace this method by re-adding curl's lib source directory to the header path and addressing headers by the their full, relative name to that base directory. Aligning with this method already used in src and tests. With these advantages: - makes includes easier to read, recognize, grep, sort, write, and copy between sources, - syncs the way these headers are included across curl components, - avoids the ambiguity between system `schannel.h`, `rustls.h` vs. local headers using the same names in `lib/vtls`, - silences clang-tidy `readability-duplicate-include` checker, which detects the above issue, Ref: https://clang.llvm.org/extra/clang-tidy/checks/readability/duplicate-include.html - possibly silences TIOBE coding standard warnings: `6.10.2.a: Don't use relative paths in #include statements.` - long shot: it works well with concatenated test sources, for clang-tidy-friendly custom unity builds. Ref: #20667 Slight downside: it's not enforced. If there happens to be a collision between a local `lib/*.h` header and a system one, the solution is to rename (possibly with its `.c` counterpart) into the `curl_` namespace. This is also the method used by curl in the past. Also: - curlx/inet_pton: reduce scope of an include. - toolx/tool_time: apply this to an include, and update VS project files accordingly. Also dropping unnecessary lib/curlx header path. - clang-tidy: enable `readability-duplicate-include`. Follow-up to3887069c66#19676 Follow-up to625f2c1644#16991 #16949 Closes #20623
223 lines
6.1 KiB
C
223 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 "curlx/inet_ntop.h"
|
|
#include "curlx/snprintf.h"
|
|
#include "curlx/strcopy.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 snprintf() does not overflow the buffer. */
|
|
SNPRINTF(tmp, sizeof(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;
|
|
}
|
|
curlx_strcopy(dst, size, tmp, len);
|
|
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 16-bit 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++ = ':';
|
|
|
|
/* 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;
|
|
}
|
|
|
|
curlx_strcopy(dst, size, tmp, tp - 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 */
|