summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure20
-rw-r--r--configure.ac2
-rw-r--r--debian/changelog9
-rw-r--r--debian/control4
-rw-r--r--debian/files1
-rw-r--r--debian/libhx-dev.symbols1
-rw-r--r--debian/libhx32.symbols5
-rw-r--r--doc/api.rst4
-rw-r--r--doc/changelog.rst92
-rw-r--r--doc/socket_functions.rst48
-rw-r--r--include/libHX/libxml_helper.h15
-rw-r--r--include/libHX/socket.h5
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.in2
-rw-r--r--src/format.c5
-rw-r--r--src/io.c22
-rw-r--r--src/libHX.map8
-rw-r--r--src/map.c2
-rw-r--r--src/proc.c2
-rw-r--r--src/rand.c2
-rw-r--r--src/socket.c257
-rw-r--r--src/tc-list.c8
-rw-r--r--src/tc-socket.c75
-rw-r--r--src/tc-string.c4
24 files changed, 504 insertions, 91 deletions
diff --git a/configure b/configure
index 7efd534..f0146dd 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for libHX 4.10.
+# Generated by GNU Autoconf 2.71 for libHX 4.14.
#
#
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -618,8 +618,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='libHX'
PACKAGE_TARNAME='libhx'
-PACKAGE_VERSION='4.10'
-PACKAGE_STRING='libHX 4.10'
+PACKAGE_VERSION='4.14'
+PACKAGE_STRING='libHX 4.14'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1375,7 +1375,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures libHX 4.10 to adapt to many kinds of systems.
+\`configure' configures libHX 4.14 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1446,7 +1446,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of libHX 4.10:";;
+ short | recursive ) echo "Configuration of libHX 4.14:";;
esac
cat <<\_ACEOF
@@ -1561,7 +1561,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-libHX configure 4.10
+libHX configure 4.14
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2195,7 +2195,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by libHX $as_me 4.10, which was
+It was created by libHX $as_me 4.14, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -3684,7 +3684,7 @@ fi
# Define the identity of the package.
PACKAGE='libhx'
- VERSION='4.10'
+ VERSION='4.14'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -18771,7 +18771,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by libHX $as_me 4.10, which was
+This file was extended by libHX $as_me 4.14, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -18839,7 +18839,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
-libHX config.status 4.10
+libHX config.status 4.14
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 10c01b7..92c72c7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([libHX], [4.10])
+AC_INIT([libHX], [4.14])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
diff --git a/debian/changelog b/debian/changelog
index 16df304..429ee49 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+libhx (4.14-1) unstable; urgency=medium
+
+ * New upstream release.
+ - Refresh symbols files.
+ * debian/control:
+ - Change Vcs-* to new URL.
+
+ -- Jörg Frings-Fürst <debian@jff.email> Sat, 15 Jul 2023 10:34:12 +0200
+
libhx (4.10-1) unstable; urgency=medium
* New upstream release.
diff --git a/debian/control b/debian/control
index 98ef1be..470c2bb 100644
--- a/debian/control
+++ b/debian/control
@@ -7,8 +7,8 @@ Standards-Version: 4.6.2.0
Section: libs
Rules-Requires-Root: no
Homepage: https://inai.de/projects/libhx/
-Vcs-Git: git://jff.email/opt/git/libhx.git
-Vcs-Browser: https://jff.email/cgit/libhx.git
+Vcs-Git: git://git.jff.email/libhx.git
+Vcs-Browser: https://git.jff.email/cgit/libhx.git
Package: libhx32
Architecture: any
diff --git a/debian/files b/debian/files
new file mode 100644
index 0000000..bd8c150
--- /dev/null
+++ b/debian/files
@@ -0,0 +1 @@
+libhx_4.14-1_source.buildinfo libs optional
diff --git a/debian/libhx-dev.symbols b/debian/libhx-dev.symbols
index 82ae111..a054c0f 100644
--- a/debian/libhx-dev.symbols
+++ b/debian/libhx-dev.symbols
@@ -2,6 +2,7 @@ libHX_rtcheck.so libhx-dev #MINVER#
* Build-Depends-Package: libhx-dev
LIBHX_3.25@LIBHX_3.25 3.25
LIBHX_3.27@LIBHX_3.27 4.7
+ LIBHX_4.11@LIBHX_4.11 4.12
LIBHX_4.2@LIBHX_4.2 4.7
LIBHX_4.3@LIBHX_4.3 4.7
LIBHX_4.9@LIBHX_4.9 4.10
diff --git a/debian/libhx32.symbols b/debian/libhx32.symbols
index 4921f2a..539b90e 100644
--- a/debian/libhx32.symbols
+++ b/debian/libhx32.symbols
@@ -1,5 +1,6 @@
libHX.so.32 libhx32 #MINVER#
* Build-Depends-Package: libhx-dev
+ HX_addrport_split@LIBHX_4.11 4.12
HX_basename@LIBHX_3.25 3.25
HX_basename_exact@LIBHX_3.25 3.25
HX_chomp@LIBHX_3.25 3.25
@@ -21,9 +22,12 @@ libHX.so.32 libhx32 #MINVER#
HX_getopt_usage@LIBHX_3.25 3.25
HX_getopt_usage_cb@LIBHX_3.25 3.25
HX_hexdump@LIBHX_3.25 3.25
+ HX_inet_connect@LIBHX_4.11 4.12
+ HX_inet_listen@LIBHX_4.11 4.12
HX_init@LIBHX_3.25 3.25
HX_ipaddr_is_local@LIBHX_4.9 4.10
HX_irand@LIBHX_3.25 3.25
+ HX_local_listen@LIBHX_4.11 4.12
HX_memmem@LIBHX_3.25 3.25
HX_mkdir@LIBHX_3.25 3.25
HX_rand@LIBHX_3.25 3.25
@@ -142,6 +146,7 @@ libHX.so.32 libhx32 #MINVER#
HXproc_wait@LIBHX_3.25 3.25
LIBHX_3.25@LIBHX_3.25 3.25
LIBHX_3.27@LIBHX_3.27 4.7
+ LIBHX_4.11@LIBHX_4.11 4.12
LIBHX_4.2@LIBHX_4.2 4.7
LIBHX_4.3@LIBHX_4.3 4.7
LIBHX_4.9@LIBHX_4.9 4.10
diff --git a/doc/api.rst b/doc/api.rst
index 5f009cc..5a3efe5 100644
--- a/doc/api.rst
+++ b/doc/api.rst
@@ -9,6 +9,10 @@ Function reference
====== ====== ====== ========================================
RMV MinVer FirstA Name
====== ====== ====== ========================================
+4.11 4.11 4.11 HX_addrport_split
+4.11 4.11 4.11 HX_inet_connect
+4.11 4.11 4.11 HX_inet_listen
+4.11 4.11 4.11 HX_local_listen
4.9 4.9 4.9 HX_sockaddr_is_local
4.9 4.9 4.9 HX_ipaddr_is_local
4.7 4.7 4.7 HXQUOTE_BASE64IMAP
diff --git a/doc/changelog.rst b/doc/changelog.rst
index 9a1590c..26c4d06 100644
--- a/doc/changelog.rst
+++ b/doc/changelog.rst
@@ -1,3 +1,37 @@
+v4.14 (2023-07-14)
+==================
+
+Fixes:
+
+* socket: make HX_addrport_split work on portless bracketed hostspec
+
+
+v4.13 (2023-06-21)
+==================
+
+Fixes:
+
+* io: do not fail HX_mkdir when a component is a symlink to a directory
+* xml_helper: fix infinite recursion in xml_getnsprop
+
+
+v4.12 (2023-02-27)
+==================
+
+Fixes:
+
+* Plug a memory leak in HX_inet_listen
+
+
+v4.11 (2023-02-26)
+==================
+
+Enhancements:
+
+* socket: add HX_addrport_split, HX_inet_connect, HX_inet_listen,
+ HX_local_listen
+
+
v4.10 (2023-01-29)
==================
@@ -116,61 +150,3 @@ Enhancements:
Fixes:
* proc: re-close pipes when ``HXproc_build_pipes`` failed
-
-
-v3.26 (2021-08-03)
-==================
-
-Fixes:
-
-* io: cure a potential infinite loop on EOF with HXio_fullread()
-* io: HXio_fullread() now returns actual bytes read rather than bytes requested
-* time: rectified HX_timeval_sub producing wrong results
-
-Changes:
-
-* nullptr checks were added to HXshconfig_free, HXformat_free, HXdeque_free and
- HXmap_free to make their behavior be in line with free(3).
-* Documentation has been switched to reStructured Text.
-
-
-v3.25 (2020-05-14)
-==================
-
-Fixes:
-
-* string: fix out-of-bounds access when calling ``HX_strlcpy(x,y,0)``
-
-Changes:
-
-* string: ``HX_split4`` renamed to ``HX_split_inplace``
-* string: ``HX_split5`` renamed to ``HX_split_fixed``
-* defs.h: removed partially implementation of ``FIELD_SIZEOF``
-* defs.h: removed custom ``offsetof`` definition; you will need to include
- ``<stddef.h>`` or ``<cstddef>`` now.
-
-
-v3.24 (2018-10-17)
-==================
-
-Fixes:
-
-* defs: avoid compiler warning when using ``HX_list_for_each`` in C++
-* opt: synchronize ``HXOPT_AUTOHELP`` C behavior to C++ mode
-
-
-v3.23 (2018-08-28)
-==================
-
-Enhancements:
-
-* opt: the option parser now recognizes long option abbreviations
-* io: use modern ``readdir`` rather than ``readdir_r``
-
-
-v3.22 (2014-08-25)
-==================
-
-Enhancements:
-
-* string: add the ``HXQUOTE_SQLBQUOTE`` quoting variant
diff --git a/doc/socket_functions.rst b/doc/socket_functions.rst
index ead0f08..5d55cf8 100644
--- a/doc/socket_functions.rst
+++ b/doc/socket_functions.rst
@@ -6,10 +6,46 @@ Socket functions
#include <libHX/socket.h>
+ int HX_addrport_split(const char *spec, char *host, size_t hsize, uint16_t *port);
+ int HX_inet_connect(const char *host, uint16_t port, unsigned int oflags);
+ int HX_inet_listen(const char *host, uint16_t port);
+ int HX_local_listen(const char *path);
int HX_socket_from_env(const struct addrinfo *ai, const char *intf);
int HX_sockaddr_is_local(const struct sockaddr *, socklen_t, unsigned int flags);
int HX_ipaddr_is_local(const char *, unsigned int flags);
+``HX_addrport_split``
+ Splits a host specification like ``[fe80::1]:80`` or ``127.0.0.1:80``
+ into a host and port part. The ``host`` parameter should point to a
+ buffer of size ``hsize``. ``port`` may be NULL. If ``spec`` did not
+ contain a port part, ``*port`` will *not* be updated, so it is wise to
+ set a default port first like in the example below. Upon success, the
+ value 2 is returned if both a host and a port were parsed (irrespective
+ of ``port`` being NULL or not). The value 1 is returned if only a host
+ portion was parsed. Upon error, a negative errno value is returned.
+
+``HX_inet_connect``
+ The function first resolves the specified host or IPv6/IPv4 address
+ (must not be enclosed in square brackets), and then attempts to connect
+ to one of the addresses. The order of evaluation is dependent upon the
+ system defaults. (It may choose whatever protocol is offered by the
+ system.) ``oflags`` is a bitset which may contain ``O_NONBLOCK``, else
+ must be 0. Upon success, a socket file descriptor is returned. Upon
+ failure, a negative errno code is returned.
+
+``HX_inet_listen``
+ The function first resolves ``host`` using ``getaddrinfo()` with
+ ``AI_PASSIVE``, then using ``HX_socket_from_env`` looks in the
+ environment for a matching socket to pick up, and otherwise uses the
+ first result from getaddrinfo to create a new socket. Upon error, a
+ negative errno value is returned.
+
+``HX_local_listen``
+ The function creates a local system-specific socket. Using
+ ``HX_socket_from_env``, it will attempt to pick up a matching socket
+ from the environment, and otherwise create a new socket. Upon error, a
+ negative errno value is returned.
+
``HX_socket_from_env``
The function looks up the current process's file descriptors for a
socket that is listening and which matches the given addrinfo and
@@ -32,3 +68,15 @@ Socket functions
Takes a text representation of an IPv6/IPv4 address and, after
transformation, calls ``HX_sockaddr_is_local``. ``flags`` and
return value behave the same as that.
+
+Examples
+--------
+
+.. code-block:: c
+
+ char host[256];
+ uint16_t port = 443;
+ /* port won't be updated */
+ HX_addrport_split("example.de", host, sizeof(host), &port);
+ /* port will be updated */
+ HX_addrport_split("example.de:80", host, sizeof(host), &port);
diff --git a/include/libHX/libxml_helper.h b/include/libHX/libxml_helper.h
index ebe5613..5a02bf0 100644
--- a/include/libHX/libxml_helper.h
+++ b/include/libHX/libxml_helper.h
@@ -7,6 +7,7 @@
# include <string.h>
#endif
#include <libxml/parser.h>
+#include <libHX/defs.h>
#ifdef __cplusplus
extern "C" {
@@ -30,6 +31,10 @@ static __inline__ int xml_strcasecmp(const xmlChar *a, const char *b)
#endif
}
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
static __inline__ char *xml_getprop(xmlNode *node, const char *attr)
{
#ifdef __cplusplus
@@ -106,7 +111,15 @@ xml_setprop(xmlNode *node, const char *name, const char *value)
}
#ifdef __cplusplus
-} /* extern "C" */
+static __inline__ const char *xml_getprop(const xmlNode *node, const char *attr)
+{
+ return xml_getprop(const_cast<xmlNode *>(node), attr);
+}
+static __inline__ char *xml_getnsprop(const xmlNode *node, const char *nsprefix,
+ const char *attr)
+{
+ return xml_getnsprop(const_cast<xmlNode *>(node), nsprefix, attr);
+}
#endif
#endif /* _LIBHX_LIBXML_HELPER_H */
diff --git a/include/libHX/socket.h b/include/libHX/socket.h
index e9db77f..e34e1c8 100644
--- a/include/libHX/socket.h
+++ b/include/libHX/socket.h
@@ -1,6 +1,7 @@
#ifndef _LIBHX_SOCKET_H
#define _LIBHX_SOCKET_H 1
+#include <stdint.h>
#ifdef _WIN32
# include <ws2tcpip.h>
#else
@@ -12,6 +13,10 @@
extern "C" {
#endif
+extern int HX_addrport_split(const char *spec, char *host, size_t hsize, uint16_t *port);
+extern int HX_inet_connect(const char *host, uint16_t port, unsigned int oflags);
+extern int HX_inet_listen(const char *host, uint16_t port);
+extern int HX_local_listen(const char *path);
extern int HX_socket_from_env(const struct addrinfo *, const char *intf);
extern int HX_sockaddr_is_local(const struct sockaddr *, socklen_t, unsigned int flags);
extern int HX_ipaddr_is_local(const char *, unsigned int flags);
diff --git a/src/Makefile.am b/src/Makefile.am
index 921e6b7..f7ff4f6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,7 +13,7 @@ libHX_la_SOURCES = deque.c dl.c format.c io.c map.c \
mc.c misc.c opt.c proc.c \
rand.c socket.c string.c time.c
libHX_la_LIBADD = ${libdl_LIBS} -lm ${libpthread_LIBS} ${librt_LIBS}
-libHX_la_LDFLAGS = -no-undefined -version-info 36:0:4
+libHX_la_LDFLAGS = -no-undefined -version-info 37:0:5
if WITH_GNU_LD
libHX_la_LDFLAGS += -Wl,--version-script=${srcdir}/libHX.map
endif
diff --git a/src/Makefile.in b/src/Makefile.in
index 8257e20..43f7444 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -780,7 +780,7 @@ libHX_la_SOURCES = deque.c dl.c format.c io.c map.c mc.c misc.c opt.c \
proc.c rand.c socket.c string.c time.c $(am__append_3)
libHX_la_LIBADD = ${libdl_LIBS} -lm ${libpthread_LIBS} ${librt_LIBS} \
$(am__append_4)
-libHX_la_LDFLAGS = -no-undefined -version-info 36:0:4 $(am__append_2)
+libHX_la_LDFLAGS = -no-undefined -version-info 37:0:5 $(am__append_2)
EXTRA_libHX_la_DEPENDENCIES = libHX.map
libHX_rtcheck_la_SOURCES = rtcheck.c
libHX_rtcheck_la_LIBADD = ${libdl_LIBS}
diff --git a/src/format.c b/src/format.c
index 25c09d6..e924c6a 100644
--- a/src/format.c
+++ b/src/format.c
@@ -7,6 +7,7 @@
* General Public License as published by the Free Software Foundation;
* either version 2.1 or (at your option) any later version.
*/
+#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
@@ -681,6 +682,7 @@ EXPORT_SYMBOL ssize_t HXformat3_aprintf(const struct HXformat_map *blk,
out:
ret = -errno;
HXmc_free(out);
+ *resultp = nullptr;
return ret;
}
@@ -716,7 +718,7 @@ EXPORT_SYMBOL int HXformat_sprintf(const struct HXformat_map *ftable,
EXPORT_SYMBOL ssize_t HXformat3_sprintf(const struct HXformat_map *ftable,
char *dest, size_t size, const char *fmt)
{
- hxmc_t *str;
+ hxmc_t *str = nullptr;
ssize_t ret;
if ((ret = HXformat_aprintf(ftable, &str, fmt)) < 0)
@@ -725,6 +727,7 @@ EXPORT_SYMBOL ssize_t HXformat3_sprintf(const struct HXformat_map *ftable,
*dest = '\0';
return 0;
}
+ assert(str != nullptr);
strncpy(dest, str, size);
size_t xl = strlen(dest);
HXmc_free(str);
diff --git a/src/io.c b/src/io.c
index 720a9c5..76c9444 100644
--- a/src/io.c
+++ b/src/io.c
@@ -11,6 +11,7 @@
# include "config.h"
#endif
#include <sys/stat.h>
+#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@@ -65,7 +66,7 @@ static int mkdir_gen(const char *d, unsigned int mode)
return 1;
if (errno != EEXIST)
return -errno;
- if (lstat(d, &sb) == 0) {
+ if (stat(d, &sb) == 0) {
#if defined(_WIN32)
if (sb.st_mode & S_IFDIR)
#else
@@ -423,6 +424,7 @@ HX_realpath_symres(struct HX_realpath_state *state, const char *path)
return -ELOOP;
#endif
+ assert(state->link_target != nullptr);
if (*state->link_target == '/') {
*state->dest = '\0';
if (HXmc_setlen(&state->dest, 0) == NULL)
@@ -594,39 +596,37 @@ EXPORT_SYMBOL int HX_rrmdir(const char *dir)
EXPORT_SYMBOL ssize_t HXio_fullread(int fd, void *vbuf, size_t size)
{
char *buf = vbuf;
- size_t done = 0;
if (size > SSIZE_MAX)
size = SSIZE_MAX;
- while (done < size) {
- ssize_t ret = read(fd, buf, size - done);
+ while (size > 0) {
+ ssize_t ret = read(fd, buf, size);
if (ret < 0)
return ret;
else if (ret == 0)
break;
- done += ret;
buf += ret;
+ size -= ret;
}
- return done;
+ return buf - static_cast(char *, vbuf);
}
EXPORT_SYMBOL ssize_t HXio_fullwrite(int fd, const void *vbuf, size_t size)
{
const char *buf = vbuf;
- size_t done = 0;
if (size > SSIZE_MAX)
size = SSIZE_MAX;
- while (done < size) {
- ssize_t ret = write(fd, buf, size - done);
+ while (size > 0) {
+ ssize_t ret = write(fd, buf, size);
if (ret < 0)
return ret;
else if (ret == 0)
break;
- done += ret;
buf += ret;
+ size -= ret;
}
- return done;
+ return buf - static_cast(const char *, vbuf);
}
#if __linux__
diff --git a/src/libHX.map b/src/libHX.map
index c4cef55..33415fa 100644
--- a/src/libHX.map
+++ b/src/libHX.map
@@ -159,3 +159,11 @@ global:
HX_ipaddr_is_local;
HX_sockaddr_is_local;
} LIBHX_4.3;
+
+LIBHX_4.11 {
+global:
+ HX_addrport_split;
+ HX_inet_connect;
+ HX_inet_listen;
+ HX_local_listen;
+} LIBHX_4.9;
diff --git a/src/map.c b/src/map.c
index 40f376c..36e4633 100644
--- a/src/map.c
+++ b/src/map.c
@@ -1145,7 +1145,7 @@ static const struct HXmap_node *HXumap_traverse(struct HXumap_trav *trav)
while (trav->head == &hmap->bk_array[trav->bk_current]) {
if (++trav->bk_current >= HXhash_primes[hmap->power])
- return false;
+ return NULL;
trav->head = hmap->bk_array[trav->bk_current].next;
}
diff --git a/src/proc.c b/src/proc.c
index 1151fff..801023b 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -69,7 +69,7 @@ static int HXproc_switch_group(const struct passwd *pw, const char *group)
return HXproc_switch_gid(pw, gr->gr_gid);
}
-EXPORT_SYMBOL int HXproc_switch_user(const char *user, const char *group)
+EXPORT_SYMBOL enum HXproc_su_status HXproc_switch_user(const char *user, const char *group)
{
const struct passwd *pw = NULL;
if (user != NULL && *user != '\0') {
diff --git a/src/rand.c b/src/rand.c
index 4a3f3ce..498d4a5 100644
--- a/src/rand.c
+++ b/src/rand.c
@@ -27,7 +27,7 @@
static unsigned int HXrand_obtain_seed(void)
{
- unsigned int s;
+ unsigned long s;
#if defined(HAVE_CLOCK_GETTIME)
struct timespec tv;
diff --git a/src/socket.c b/src/socket.c
index ced884a..0b6f674 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -17,10 +17,12 @@
#ifdef _WIN32
# include <ws2tcpip.h>
#else
+# include <fcntl.h>
# include <netdb.h>
# include <unistd.h>
# include <netinet/in.h>
# include <sys/socket.h>
+# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_UN_H
# include <sys/un.h>
@@ -46,6 +48,261 @@
# define AI_V4MAPPED 0
#endif
+/**
+ * Return the pointer to the singular colon character, any other input
+ * yields nullptr.
+ */
+static inline const char *has_exactly_one_colon(const char *s)
+{
+ s = strchr(s, ':');
+ if (s == nullptr)
+ return nullptr;
+ return strchr(s + 1, ':') == nullptr ? s : nullptr;
+}
+
+/**
+ * @spec: "[" HOST-ANY "]" [ ":" PORT ]
+ * HOST-NAME [ ":" PORT ]
+ * HOST-IPV4 [ ":" PORT ]
+ * HOST-IPV6
+ * @host: buffer for placing the extracted hostname
+ * (can overlap @spec)
+ * @hsize: buffer size for @host
+ * @port: storage space for extracted port number
+ * (can be nullptr)
+ *
+ * Returns <0 (error code) if unparsable or if the output buffer is too small.
+ * Success if on >=0.
+ */
+int HX_addrport_split(const char *spec, char *host,
+ size_t hbufsz, uint16_t *pport)
+{
+ if (*spec == '[') {
+ /* We also happen to allow IPv4 addrs and hostnames in [] */
+ ++spec;
+ const char *end = strchr(spec, ']');
+ if (end == nullptr)
+ return -EINVAL;
+ unsigned long hlen = end - spec;
+ if (hlen >= hbufsz)
+ return -E2BIG;
+ if (*++end == '\0') {
+ memmove(host, spec, hlen);
+ host[hlen] = '\0';
+ return 1;
+ }
+ if (*end++ != ':')
+ return -EINVAL;
+ char *nend = nullptr;
+ uint16_t port = strtoul(end, &nend, 10);
+ if (nend == nullptr || *nend != '\0')
+ return -EINVAL;
+ memmove(host, spec, hlen);
+ host[hlen] = '\0';
+ if (pport == nullptr)
+ return 2;
+ *pport = port;
+ return 2;
+ }
+ const char *onecolon = has_exactly_one_colon(spec);
+ if (onecolon != nullptr) {
+ unsigned long hlen = onecolon - spec;
+ if (hlen >= hbufsz)
+ return -E2BIG;
+ char *nend = nullptr;
+ uint16_t port = strtoul(onecolon + 1, &nend, 10);
+ if (nend == nullptr || *nend != '\0')
+ return -EINVAL;
+ memmove(host, spec, hlen);
+ host[hlen] = '\0';
+ if (pport == nullptr)
+ return 2;
+ *pport = port;
+ return 2;
+ }
+ size_t hlen = strlen(spec);
+ if (hlen >= SIZE_MAX || ++hlen >= hbufsz)
+ return -E2BIG;
+ memmove(host, spec, hlen);
+ return 1;
+}
+
+static int HX_inet_lookup(const char *host, uint16_t port, unsigned int xflags,
+ struct addrinfo **res)
+{
+ struct addrinfo hints = {};
+#if defined(AI_V4MAPPED)
+ hints.ai_flags = AI_V4MAPPED | xflags;
+#else
+ hints.ai_flags = xflags;
+#endif
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+
+ char portbuf[HXSIZEOF_Z32];
+ snprintf(portbuf, sizeof(portbuf), "%hu", port);
+ return getaddrinfo(host, port == 0 ? nullptr : portbuf, &hints, res);
+}
+
+int HX_inet_connect(const char *host, uint16_t port, unsigned int oflags)
+{
+ struct addrinfo *aires = nullptr;
+ int ret = HX_inet_lookup(host, port, AI_ADDRCONFIG, &aires);
+ int saved_errno = 0;
+ if (ret != 0)
+ ;
+ for (const struct addrinfo *r = aires; r != nullptr; r = r->ai_next) {
+ int fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
+ if (fd < 0) {
+ if (saved_errno == 0)
+ saved_errno = errno;
+ continue;
+ }
+#ifdef O_NONBLOCK
+ if (oflags & O_NONBLOCK) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (flags < 0)
+ flags = 0;
+ flags |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) != 0) {
+ saved_errno = errno;
+ close(fd);
+ continue;
+ }
+ }
+#endif
+ ret = connect(fd, r->ai_addr, r->ai_addrlen);
+ if (ret == 0) {
+ freeaddrinfo(aires);
+ return fd;
+ }
+#ifdef O_NONBLOCK
+ if ((errno == EWOULDBLOCK || errno == EINPROGRESS) &&
+ (oflags & O_NONBLOCK)) {
+ freeaddrinfo(aires);
+ return fd;
+ }
+#endif
+ saved_errno = errno;
+ close(fd);
+ }
+ if (aires == nullptr && saved_errno == 0)
+ saved_errno = EHOSTUNREACH;
+ if (aires != nullptr)
+ freeaddrinfo(aires);
+ return -(errno = saved_errno);
+}
+
+static int HX_gai_listen(const struct addrinfo *r)
+{
+ int fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
+ if (fd < 0)
+ return -2;
+ static const int y = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, STUPIDWIN(&y), sizeof(y)) < 0)
+ /* warn setsockopt: %s, strerror(errno)) */ ;
+ int ret = bind(fd, r->ai_addr, r->ai_addrlen);
+ if (ret != 0) {
+ int se = errno;
+ close(fd);
+ errno = se;
+ return -1;
+ }
+ ret = listen(fd, SOMAXCONN);
+ if (ret != 0) {
+ int se = errno;
+ close(fd);
+ errno = se;
+ return -2;
+ }
+ return fd;
+}
+
+int HX_inet_listen(const char *host, uint16_t port)
+{
+ struct addrinfo *aires = nullptr;
+ int ret = HX_inet_lookup(host, port, AI_PASSIVE, &aires);
+ if (ret != 0)
+ ;
+ int saved_errno = EHOSTUNREACH;
+ bool use_env = getenv("HX_LISTEN_TOP_FD") != nullptr || getenv("LISTEN_FDS") != nullptr;
+ for (const struct addrinfo *r = aires; r != nullptr; r = r->ai_next) {
+ if (use_env) {
+ int fd = HX_socket_from_env(r, nullptr);
+ if (fd >= 0) {
+ freeaddrinfo(aires);
+ return fd;
+ }
+ }
+ int fd = HX_gai_listen(r);
+ if (fd >= 0) {
+ freeaddrinfo(aires);
+ return fd;
+ }
+ saved_errno = errno;
+ if (fd == -2)
+ continue;
+ break;
+ }
+ if (aires != nullptr)
+ freeaddrinfo(aires);
+ return -(errno = saved_errno);
+}
+
+int HX_local_listen(const char *path)
+{
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un u;
+ if (strlen(path) >= sizeof(u.sun_path))
+ return -EINVAL;
+ u.sun_family = AF_LOCAL;
+ strcpy(u.sun_path, path);
+ struct addrinfo r = {};
+ r.ai_flags = AI_PASSIVE;
+ r.ai_family = AF_LOCAL;
+ r.ai_socktype = SOCK_STREAM;
+ r.ai_addrlen = sizeof(u) - sizeof(u.sun_path) + strlen(u.sun_path) + 1;
+ r.ai_addr = reinterpret_cast(struct sockaddr *, &u);
+ bool use_env = getenv("HX_LISTEN_TOP_FD") != nullptr || getenv("LISTEN_FDS") != nullptr;
+ if (use_env) {
+ int fd = HX_socket_from_env(&r, nullptr);
+ if (fd >= 0)
+ return fd;
+ }
+ int ret = HX_gai_listen(&r);
+ if (ret >= 0)
+ return ret; /* fd */
+ if (ret == -2 || errno != EADDRINUSE)
+ return -errno;
+
+ struct stat sb;
+ ret = stat(path, &sb);
+ if (ret < 0)
+ return -errno;
+ if (!S_ISSOCK(sb.st_mode))
+ return -ENOTSOCK;
+
+ int testfd = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (testfd < 0)
+ return -errno;
+ ret = connect(testfd, r.ai_addr, r.ai_addrlen);
+ close(testfd);
+ if (ret == 0)
+ return -EADDRINUSE;
+
+ /* There will be a TOCTOU report, but what can you do... */
+ ret = unlink(path);
+ if (ret < 0 && errno != ENOENT)
+ return -errno;
+ ret = HX_gai_listen(&r);
+ if (ret >= 0)
+ return ret; /* fd */
+ return -errno;
+#else
+ return -EPROTONOSUPPORT;
+#endif
+}
+
static int try_sk_from_env(int fd, const struct addrinfo *ai, const char *intf)
{
int value = 0;
diff --git a/src/tc-list.c b/src/tc-list.c
index e0087e3..2fd6380 100644
--- a/src/tc-list.c
+++ b/src/tc-list.c
@@ -69,8 +69,14 @@ static void l_dump(bool pop)
while ((obj = (pop ?
HXclist_pop(&strings_ct, struct text_object, list) :
HXclist_shift(&strings_ct, struct text_object, list)
- )) != NULL)
+ )) != NULL) {
printf("%s item %u (\"%s\")\n", msg[pop], ++i, obj->id);
+#ifdef __cplusplus
+ delete obj;
+#else
+ free(obj);
+#endif
+ }
printf("Remaining elements: %u\n", strings_ct.items);
}
diff --git a/src/tc-socket.c b/src/tc-socket.c
index 9c73d24..3cdeb90 100644
--- a/src/tc-socket.c
+++ b/src/tc-socket.c
@@ -7,18 +7,46 @@
#include <libHX/socket.h>
#ifndef _WIN32
# include <netdb.h>
+# include <unistd.h>
#endif
#ifndef AI_V4MAPPED
# define AI_V4MAPPED 0
#endif
+#include "internal.h"
-int main(void)
+static int t_parse(void)
+{
+ char host[32] = "bogus";
+ if (HX_addrport_split("[::1]", host, sizeof(host), nullptr) != 1 ||
+ strcmp(host, "::1") != 0)
+ return 1;
+ if (HX_addrport_split("[]", host, sizeof(host), nullptr) != 1 ||
+ strcmp(host, "") != 0)
+ return 1;
+ if (HX_addrport_split("", host, sizeof(host), nullptr) != 1 ||
+ strcmp(host, "") != 0)
+ return 1;
+ return 0;
+}
+
+static int t_local(void)
{
static const char *addrs[] = {
"::1", "::2", "::ffff:127.0.0.1", "::",
+ "[::1]", "[::2]", "[::ffff:127.0.0.1]", "[::]",
"127.0.0.1", "127.0.0.2", "1.1.1.1", "255.255.255.255",
+ "[127.0.0.1]", "[127.0.0.2]", "[1.1.1.1]", "[255.255.255.255]",
};
for (size_t i = 0; i < ARRAY_SIZE(addrs); ++i) {
+ char host[32] = {};
+ uint16_t port = 0;
+
+ int ret = HX_addrport_split(addrs[i], host, sizeof(host), &port);
+ if (ret >= 0)
+ printf("Parse \"%s\" -> [%s]:%hu\n", addrs[i], host, port);
+ else
+ return EXIT_FAILURE;
+
printf("%-16s\t", addrs[i]);
int lcl = HX_ipaddr_is_local(addrs[i], AI_V4MAPPED);
if (lcl < 0) {
@@ -27,5 +55,50 @@ int main(void)
}
printf("%d\n", lcl);
}
+
+ char host[32] = {};
+ uint16_t port = 0;
+ int ret = HX_addrport_split("[fe80::1]:80", host, sizeof(host), &port);
+ if (ret < 0 || port != 80)
+ return EXIT_FAILURE;
+ port = 443;
+ ret = HX_addrport_split("::80", host, sizeof(host), &port);
+ if (ret < 0 || port != 443)
+ return EXIT_FAILURE;
+ ret = HX_addrport_split(":::80", host, sizeof(host), &port);
+ if (ret < 0 || port != 443)
+ return EXIT_FAILURE;
+ ret = HX_addrport_split("0.0.0.0", host, sizeof(host), &port);
+ if (ret < 0 || port != 443)
+ return EXIT_FAILURE;
+ ret = HX_addrport_split("0.0.0.0:80", host, sizeof(host), &port);
+ if (ret < 0 || port != 80)
+ return EXIT_FAILURE;
+
+ int fd = HX_inet_connect("::1", 80, 0);
+ if (fd >= 0) {
+ printf("Connected to [::1]:80\n");
+ close(fd);
+ } else {
+ fprintf(stderr, "HX_inet_connect [::1]:80: %s\n", strerror(-fd));
+ }
+ fd = HX_inet_connect("::", 80, 0);
+ if (fd >= 0) {
+ printf("Connected to [::]:80\n");
+ close(fd);
+ } else {
+ fprintf(stderr, "HX_inet_connect [::]:80: %s\n", strerror(-fd));
+ }
+ return EXIT_SUCCESS;
+}
+
+int main(void)
+{
+ int ret = t_parse();
+ if (ret != 0)
+ return ret;
+ ret = t_local();
+ if (ret != EXIT_SUCCESS)
+ return ret;
return EXIT_SUCCESS;
}
diff --git a/src/tc-string.c b/src/tc-string.c
index 77235c2..9bf668b 100644
--- a/src/tc-string.c
+++ b/src/tc-string.c
@@ -84,12 +84,16 @@ static void t_strncat(void)
{
char data[5] = "DATA";
+#ifndef __clang__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-truncation"
+#endif
if (snprintf(data, sizeof(data), "12345678") >=
static_cast(ssize_t, sizeof(data)))
printf("Not enough space\n");
+#ifndef __clang__
#pragma GCC diagnostic pop
+#endif
printf("String: >%s<\n", data);
HX_strlcat(data, "pqrstuv__", 2);