Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package libHX for openSUSE:Factory checked 
in at 2023-03-01 16:13:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libHX (Old)
 and      /work/SRC/openSUSE:Factory/.libHX.new.31432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libHX"

Wed Mar  1 16:13:34 2023 rev:71 rq:1068082 version:4.12

Changes:
--------
--- /work/SRC/openSUSE:Factory/libHX/libHX.changes      2023-01-30 
17:24:41.200960493 +0100
+++ /work/SRC/openSUSE:Factory/.libHX.new.31432/libHX.changes   2023-03-01 
16:13:39.342476818 +0100
@@ -1,0 +2,12 @@
+Mon Feb 27 13:57:50 UTC 2023 - Jan Engelhardt <jeng...@inai.de>
+
+- Update to release 4.12
+  * Plug a memory leak in HX_inet_listen
+
+-------------------------------------------------------------------
+Mon Feb 27 09:30:07 UTC 2023 - Jan Engelhardt <jeng...@inai.de>
+
+- Update to release 4.11
+  * Four new socket utility functions
+
+-------------------------------------------------------------------

Old:
----
  libHX-4.10.tar.asc
  libHX-4.10.tar.xz

New:
----
  libHX-4.12.tar.asc
  libHX-4.12.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libHX.spec ++++++
--- /var/tmp/diff_new_pack.aERtg9/_old  2023-03-01 16:13:40.030480377 +0100
+++ /var/tmp/diff_new_pack.aERtg9/_new  2023-03-01 16:13:40.034480397 +0100
@@ -18,7 +18,7 @@
 
 Name:           libHX
 %define lname   libHX32
-Version:        4.10
+Version:        4.12
 Release:        0
 Summary:        Collection of routines for C and C++ programming
 License:        LGPL-2.1-or-later

++++++ libHX-4.10.tar.xz -> libHX-4.12.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/configure new/libHX-4.12/configure
--- old/libHX-4.10/configure    2023-01-29 15:20:47.732895627 +0100
+++ new/libHX-4.12/configure    2023-02-27 14:55:44.471237664 +0100
@@ -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.12.
 #
 #
 # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -618,8 +618,8 @@
 # Identity of this package.
 PACKAGE_NAME='libHX'
 PACKAGE_TARNAME='libhx'
-PACKAGE_VERSION='4.10'
-PACKAGE_STRING='libHX 4.10'
+PACKAGE_VERSION='4.12'
+PACKAGE_STRING='libHX 4.12'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1375,7 +1375,7 @@
   # 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.12 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1446,7 +1446,7 @@
 
 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.12:";;
    esac
   cat <<\_ACEOF
 
@@ -1561,7 +1561,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libHX configure 4.10
+libHX configure 4.12
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2195,7 +2195,7 @@
 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.12, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -3684,7 +3684,7 @@
 
 # Define the identity of the package.
  PACKAGE='libhx'
- VERSION='4.10'
+ VERSION='4.12'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -18771,7 +18771,7 @@
 # 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.12, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -18839,7 +18839,7 @@
 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.12
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/configure.ac new/libHX-4.12/configure.ac
--- old/libHX-4.10/configure.ac 2023-01-29 15:20:04.000000000 +0100
+++ new/libHX-4.12/configure.ac 2023-02-27 14:55:08.000000000 +0100
@@ -1,4 +1,4 @@
-AC_INIT([libHX], [4.10])
+AC_INIT([libHX], [4.12])
 AC_CONFIG_AUX_DIR([build-aux])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_MACRO_DIR([m4])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/doc/api.rst new/libHX-4.12/doc/api.rst
--- old/libHX-4.10/doc/api.rst  2023-01-29 15:20:04.000000000 +0100
+++ new/libHX-4.12/doc/api.rst  2023-02-27 14:55:08.000000000 +0100
@@ -9,6 +9,10 @@
 ======  ======  ======  ========================================
 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/doc/changelog.rst 
new/libHX-4.12/doc/changelog.rst
--- old/libHX-4.10/doc/changelog.rst    2023-01-29 15:20:04.000000000 +0100
+++ new/libHX-4.12/doc/changelog.rst    2023-02-27 14:55:08.000000000 +0100
@@ -1,3 +1,20 @@
+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 +133,3 @@
 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/doc/socket_functions.rst 
new/libHX-4.12/doc/socket_functions.rst
--- old/libHX-4.10/doc/socket_functions.rst     2023-01-29 15:20:04.000000000 
+0100
+++ new/libHX-4.12/doc/socket_functions.rst     2023-02-27 14:55:08.000000000 
+0100
@@ -6,10 +6,46 @@
 
        #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 @@
        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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/include/libHX/libxml_helper.h 
new/libHX-4.12/include/libHX/libxml_helper.h
--- old/libHX-4.10/include/libHX/libxml_helper.h        2023-01-29 
15:20:04.000000000 +0100
+++ new/libHX-4.12/include/libHX/libxml_helper.h        2023-02-27 
14:55:08.000000000 +0100
@@ -7,6 +7,7 @@
 #      include <string.h>
 #endif
 #include <libxml/parser.h>
+#include <libHX/defs.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -30,6 +31,10 @@
 #endif
 }
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
 static __inline__ char *xml_getprop(xmlNode *node, const char *attr)
 {
 #ifdef __cplusplus
@@ -106,7 +111,15 @@
 }
 
 #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<const xmlNode *>(node), nsprefix, attr);
+}
 #endif
 
 #endif /* _LIBHX_LIBXML_HELPER_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/include/libHX/socket.h 
new/libHX-4.12/include/libHX/socket.h
--- old/libHX-4.10/include/libHX/socket.h       2023-01-29 15:20:04.000000000 
+0100
+++ new/libHX-4.12/include/libHX/socket.h       2023-02-27 14:55:08.000000000 
+0100
@@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/src/Makefile.am 
new/libHX-4.12/src/Makefile.am
--- old/libHX-4.10/src/Makefile.am      2023-01-29 15:20:04.000000000 +0100
+++ new/libHX-4.12/src/Makefile.am      2023-02-27 14:55:08.000000000 +0100
@@ -13,7 +13,7 @@
                    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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/src/Makefile.in 
new/libHX-4.12/src/Makefile.in
--- old/libHX-4.10/src/Makefile.in      2023-01-29 15:20:48.268899141 +0100
+++ new/libHX-4.12/src/Makefile.in      2023-02-27 14:55:46.139240599 +0100
@@ -780,7 +780,7 @@
        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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/src/io.c new/libHX-4.12/src/io.c
--- old/libHX-4.10/src/io.c     2023-01-29 15:20:04.000000000 +0100
+++ new/libHX-4.12/src/io.c     2023-02-27 14:55:08.000000000 +0100
@@ -11,6 +11,7 @@
 #      include "config.h"
 #endif
 #include <sys/stat.h>
+#include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
@@ -594,39 +595,37 @@
 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/src/libHX.map new/libHX-4.12/src/libHX.map
--- old/libHX-4.10/src/libHX.map        2023-01-29 15:20:04.000000000 +0100
+++ new/libHX-4.12/src/libHX.map        2023-02-27 14:55:08.000000000 +0100
@@ -159,3 +159,11 @@
        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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/src/rand.c new/libHX-4.12/src/rand.c
--- old/libHX-4.10/src/rand.c   2023-01-29 15:20:04.000000000 +0100
+++ new/libHX-4.12/src/rand.c   2023-02-27 14:55:08.000000000 +0100
@@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/src/socket.c new/libHX-4.12/src/socket.c
--- old/libHX-4.10/src/socket.c 2023-01-29 15:20:04.000000000 +0100
+++ new/libHX-4.12/src/socket.c 2023-02-27 14:55:08.000000000 +0100
@@ -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,256 @@
 #      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')
+                       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;
+       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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/src/tc-list.c new/libHX-4.12/src/tc-list.c
--- old/libHX-4.10/src/tc-list.c        2023-01-29 15:20:04.000000000 +0100
+++ new/libHX-4.12/src/tc-list.c        2023-02-27 14:55:08.000000000 +0100
@@ -69,8 +69,14 @@
        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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.10/src/tc-socket.c 
new/libHX-4.12/src/tc-socket.c
--- old/libHX-4.10/src/tc-socket.c      2023-01-29 15:20:04.000000000 +0100
+++ new/libHX-4.12/src/tc-socket.c      2023-02-27 14:55:08.000000000 +0100
@@ -7,6 +7,7 @@
 #include <libHX/socket.h>
 #ifndef _WIN32
 #      include <netdb.h>
+#      include <unistd.h>
 #endif
 #ifndef AI_V4MAPPED
 #      define AI_V4MAPPED 0
@@ -19,6 +20,15 @@
                "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 +37,39 @@
                }
                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;
 }

Reply via email to