Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package gensio for openSUSE:Factory checked in at 2021-06-09 21:51:57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/gensio (Old) and /work/SRC/openSUSE:Factory/.gensio.new.32437 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "gensio" Wed Jun 9 21:51:57 2021 rev:11 rq:897966 version:2.2.7 Changes: -------- --- /work/SRC/openSUSE:Factory/gensio/gensio.changes 2021-05-15 23:17:30.320421581 +0200 +++ /work/SRC/openSUSE:Factory/.gensio.new.32437/gensio.changes 2021-06-09 21:52:12.630464947 +0200 @@ -1,0 +2,8 @@ +Sat Jun 5 10:42:39 UTC 2021 - Martin Hauke <mar...@gmx.de> + +- Update to version 2.2.7 + * Fix: multiple connections to UDP sockets not work correctly. +- Update to version 2.2.6 + * Mostly small bug fixes. + +------------------------------------------------------------------- Old: ---- gensio-2.2.5.tar.gz New: ---- gensio-2.2.7.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ gensio.spec ++++++ --- /var/tmp/diff_new_pack.ipeRWW/_old 2021-06-09 21:52:13.142465860 +0200 +++ /var/tmp/diff_new_pack.ipeRWW/_new 2021-06-09 21:52:13.146465867 +0200 @@ -25,7 +25,7 @@ %bcond_with openipmi %endif Name: gensio -Version: 2.2.5 +Version: 2.2.7 Release: 0 Summary: Library to abstract stream and packet I/O # examples/* is licenced under Apache-2.0 ++++++ gensio-2.2.5.tar.gz -> gensio-2.2.7.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gensio-2.2.5/CMakeLists.txt new/gensio-2.2.7/CMakeLists.txt --- old/gensio-2.2.5/CMakeLists.txt 2021-05-11 03:04:32.000000000 +0200 +++ new/gensio-2.2.7/CMakeLists.txt 2021-05-28 21:16:02.000000000 +0200 @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.10) -project(gensio VERSION 2.2.4) +project(gensio VERSION 2.2.6) set (gensio_VERSION_STRING "${gensio_VERSION_MAJOR}.${gensio_VERSION_MINOR}.${gensio_VERSION_PATCH}") include_directories("${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/include" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gensio-2.2.5/configure.ac new/gensio-2.2.7/configure.ac --- old/gensio-2.2.5/configure.ac 2021-05-11 03:04:32.000000000 +0200 +++ new/gensio-2.2.7/configure.ac 2021-05-28 21:16:02.000000000 +0200 @@ -1,7 +1,7 @@ -AC_INIT([gensio], [2.2.5], [miny...@acm.org]) +AC_INIT([gensio], [2.2.7], [miny...@acm.org]) AC_SUBST(gensio_VERSION_MAJOR, 2) AC_SUBST(gensio_VERSION_MINOR, 2) -AC_SUBST(gensio_VERSION_PATCH, 5) +AC_SUBST(gensio_VERSION_PATCH, 7) AC_SUBST(gensio_VERSION_STRING, ${PACKAGE_VERSION}) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE([-Wall]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gensio-2.2.5/lib/gensio_ll_fd.c new/gensio-2.2.7/lib/gensio_ll_fd.c --- old/gensio-2.2.5/lib/gensio_ll_fd.c 2021-05-11 03:04:32.000000000 +0200 +++ new/gensio-2.2.7/lib/gensio_ll_fd.c 2021-05-28 21:16:02.000000000 +0200 @@ -587,7 +587,14 @@ int err; err = fdll->ops->check_open(fdll->handler_data, fdll->fd); - if (err && fdll->ops->retry_open) { + /* + * The GE_NOMEM check is strange here, but it really has more + * to do with testing. check_open() is not going to return + * GE_NOMEM unless it's an error trigger failure, and we really + * want to fail in that case or we will get a "error triggered + * but no failure" in the test. + */ + if (err && err != GE_NOMEM && fdll->ops->retry_open) { fd_set_state(fdll, FD_IN_OPEN_RETRY); fdll->o->clear_fd_handlers(fdll->o, fdll->fd); } else { @@ -722,8 +729,11 @@ if (fdll->state == FD_IN_OPEN_RETRY) { gensio_os_close(fdll->o, &fdll->fd); err = fdll->ops->retry_open(fdll->handler_data, &fdll->fd); - if (err == GE_INPROGRESS) + if (err == GE_INPROGRESS) { err = fd_setup_handlers(fdll); + if (!err) + fd_set_state(fdll, FD_IN_OPEN); + } if (err) { fd_deref(fdll); fd_finish_open(fdll, err); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gensio-2.2.5/lib/gensio_net.c new/gensio-2.2.7/lib/gensio_net.c --- old/gensio-2.2.5/lib/gensio_net.c 2021-05-11 03:04:32.000000000 +0200 +++ new/gensio-2.2.7/lib/gensio_net.c 2021-05-28 21:16:02.000000000 +0200 @@ -66,6 +66,7 @@ int protocol = tdata->istcp ? GENSIO_NET_PROTOCOL_TCP : GENSIO_NET_PROTOCOL_UNIX; + retry: err = gensio_os_socket_open(tdata->o, tdata->ai, protocol, &new_fd); if (err) goto out; @@ -76,16 +77,24 @@ if (err) goto out; - retry: err = gensio_os_connect(tdata->o, new_fd, tdata->ai); if (err == GE_INPROGRESS) { *fd = new_fd; goto out_return; } - if (err) { - if (gensio_addr_next(tdata->ai)) + /* + * The GE_NOMEM check is strange here, but it really has more to + * do with testing. connect() is not going to return GE_NOMEM + * unless it's an error trigger failure, and we really want to + * fail in that case or we will get a "error triggered but no + * failure" in the test. + */ + if (err && err != GE_NOMEM) { + if (gensio_addr_next(tdata->ai)) { + gensio_os_close(tdata->o, &new_fd); goto retry; + } } out: if (err) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gensio-2.2.5/lib/gensio_osops.c new/gensio-2.2.7/lib/gensio_osops.c --- old/gensio-2.2.5/lib/gensio_osops.c 2021-05-11 03:04:32.000000000 +0200 +++ new/gensio-2.2.7/lib/gensio_osops.c 2021-05-28 21:16:02.000000000 +0200 @@ -137,6 +137,25 @@ return 0; } +static bool sockaddr_equal(const struct sockaddr *a1, socklen_t l1, + const struct sockaddr *a2, socklen_t l2, + bool compare_ports); + +/* Does sa have an equivalent address in the list before this address? */ +static bool +sockaddr_in_list_b4(struct addrinfo *sa, struct addrinfo *l) +{ + for (; l; l = l->ai_next) { + if (sa == l) + break; + if (sockaddr_equal(sa->ai_addr, sa->ai_addrlen, + l->ai_addr, l->ai_addrlen, + true)) + return true; + } + return false; +} + #define ERRHANDLE() \ do { \ int err = 0; \ @@ -255,7 +274,7 @@ } static struct gensio_addr * -gensio_addr_make(struct gensio_os_funcs *o, socklen_t size) +gensio_addr_make(struct gensio_os_funcs *o, socklen_t size, bool do_refcount) { struct gensio_addr *addr = o->zalloc(o, sizeof(*addr)); struct addrinfo *ai = NULL; @@ -264,19 +283,22 @@ return NULL; #if HAVE_GCC_ATOMICS - addr->refcount = o->zalloc(o, sizeof(*addr->refcount)); - if (!addr->refcount) { - o->free(o, addr); - return NULL; + if (do_refcount) { + addr->refcount = o->zalloc(o, sizeof(*addr->refcount)); + if (!addr->refcount) { + o->free(o, addr); + return NULL; + } + *addr->refcount = 1; } - *addr->refcount = 1; #endif if (size > 0) { ai = o->zalloc(o, sizeof(*ai)); if (!ai) { #if HAVE_GCC_ATOMICS - o->free(o, addr->refcount); + if (addr->refcount) + o->free(o, addr->refcount); #endif o->free(o, addr); return NULL; @@ -285,7 +307,8 @@ ai->ai_addr = o->zalloc(o, size); if (!ai->ai_addr) { #if HAVE_GCC_ATOMICS - o->free(o, addr->refcount); + if (addr->refcount) + o->free(o, addr->refcount); #endif o->free(o, addr); o->free(o, ai); @@ -349,7 +372,7 @@ return GE_INVAL; } - a = gensio_addr_make(o, slen); + a = gensio_addr_make(o, slen, true); if (!a) return GE_NOMEM; a->a->ai_family = s->sa_family; @@ -362,7 +385,12 @@ struct gensio_addr * gensio_addr_alloc_recvfrom(struct gensio_os_funcs *o) { - return gensio_addr_make(o, sizeof(struct sockaddr_storage)); + /* + * Addresses used for recvfrom cannot be duplicated with refcounts + * because the storage is reused. So allocate them without a + * refcount to mark them to always do a full replication. + */ + return gensio_addr_make(o, sizeof(struct sockaddr_storage), false); } int @@ -408,7 +436,7 @@ return GE_NOMEM; if (raddr) { - addr = gensio_addr_make(o, sizeof(struct sockaddr_storage)); + addr = gensio_addr_make(o, sizeof(struct sockaddr_storage), true); if (!addr) return GE_NOMEM; sa = addr->curr->ai_addr; @@ -500,7 +528,7 @@ void *data, unsigned int opensock_flags, struct opensocks **rfds, unsigned int *rnr_fds) { - struct addrinfo *ai; + struct addrinfo *ai, *rp; unsigned int i; int family = AF_INET6; int rv = 0; @@ -510,20 +538,30 @@ memset(&scaninfo, 0, sizeof(scaninfo)); + ai = addr->a; retry: - for (ai = addr->a; ai; ai = ai->ai_next) { + for (rp = ai; rp; rp = rp->ai_next) { unsigned int port; - if (family != ai->ai_family) + if (family != rp->ai_family) continue; + /* + * getaddrinfo() will return the same address twice in the + * list if ::1 and 127.0.0.1 are both set for localhost in + * /etc/hosts. So the second open attempt will fail if we + * don't ignore this. In general, it's probably better to + * ignore duplicates in this function, anyway. + */ + if (sockaddr_in_list_b4(rp, ai)) + continue; - rv = sockaddr_get_port(ai->ai_addr, &port); + rv = sockaddr_get_port(rp->ai_addr, &port); if (rv) goto out_err; for (i = 0; i < nr_fds; i++) { if (port == fds[i].port && (fds[i].family == family)) { - if (sctp_bindx(fds[i].fd, ai->ai_addr, 1, + if (sctp_bindx(fds[i].fd, rp->ai_addr, 1, SCTP_BINDX_ADD_ADDR)) { rv = gensio_os_err_to_err(o, errno); goto out_err; @@ -543,9 +581,9 @@ if (fds) memcpy(tfds, fds, sizeof(*tfds) * i); - rv = gensio_setup_listen_socket(o, true, ai->ai_family, - SOCK_STREAM, IPPROTO_SCTP, ai->ai_flags, - ai->ai_addr, ai->ai_addrlen, + rv = gensio_setup_listen_socket(o, true, rp->ai_family, + SOCK_STREAM, IPPROTO_SCTP, rp->ai_flags, + rp->ai_addr, rp->ai_addrlen, readhndlr, NULL, data, fd_handler_cleared, setup_socket, opensock_flags, @@ -554,8 +592,8 @@ o->free(o, tfds); goto out_err; } - tfds[i].family = ai->ai_family; - tfds[i].flags = ai->ai_flags; + tfds[i].family = rp->ai_family; + tfds[i].flags = rp->ai_flags; if (fds) o->free(o, fds); fds = tfds; @@ -695,29 +733,15 @@ struct addrinfo *ai; char *saddrs, *s; unsigned int slen = 0, i, memlen = 0; - int ipv6_only = -1; + int ipv6_only = 1; for (ai = addrs->a; ai; ai = ai->ai_next) { unsigned int len; if (ai->ai_addr->sa_family == AF_INET6) { len = sizeof(struct sockaddr_in6); - if (ai->ai_flags & AI_V4MAPPED) { - if (ipv6_only == 1) - /* Can't mix IPV6-only with IPV4 mapped. */ - return GE_INVAL; - ipv6_only = 0; - } else if (ipv6_only == 0) { - /* Can't mix IPV6-only with IPV4 mapped. */ - return GE_INVAL; - } else { - ipv6_only = 1; - } } else if (ai->ai_addr->sa_family == AF_INET) { len = sizeof(struct sockaddr_in); - if (ipv6_only == 1) - /* Can't mix IPV6-only with IPV4. */ - return GE_INVAL; ipv6_only = 0; } else { return GE_INVAL; @@ -844,7 +868,7 @@ char *d; int rv; - addr = gensio_addr_make(o, 0); + addr = gensio_addr_make(o, 0, true); if (!addr) return GE_NOMEM; @@ -983,9 +1007,11 @@ const struct gensio_addr *addr, int protocol, int *fd) { - int sockproto, socktype; + int sockproto, socktype, family; int newfd; + family = addr->curr->ai_family; + if (do_errtrig()) return GE_NOMEM; @@ -1005,6 +1031,13 @@ case GENSIO_NET_PROTOCOL_SCTP: sockproto = IPPROTO_SCTP; socktype = SOCK_STREAM; +#ifdef AF_INET6 + /* + * For SCTP, always use AF_INET6 if available. sctp_connectx() + * can use ipv4 addresses, too, on an AF_INET6 socket. + */ + family = AF_INET6; +#endif break; #endif @@ -1012,7 +1045,7 @@ return GE_INVAL; } - newfd = socket(addr->a->ai_family, socktype, sockproto); + newfd = socket(family, socktype, sockproto); if (newfd == -1) return gensio_os_err_to_err(o, errno); *fd = newfd; @@ -1058,11 +1091,12 @@ } if (bindaddr) { - struct addrinfo *ai = bindaddr->a; + struct addrinfo *ai; switch (protocol) { #if HAVE_LIBSCTP case GENSIO_NET_PROTOCOL_SCTP: + ai = bindaddr->a; while (ai) { if (sctp_bindx(fd, ai->ai_addr, 1, SCTP_BINDX_ADD_ADDR) == -1) return gensio_os_err_to_err(o, errno); @@ -1074,6 +1108,7 @@ case GENSIO_NET_PROTOCOL_TCP: case GENSIO_NET_PROTOCOL_UDP: case GENSIO_NET_PROTOCOL_UNIX: + ai = bindaddr->curr; if (bind(fd, ai->ai_addr, ai->ai_addrlen) == -1) return gensio_os_err_to_err(o, errno); break; @@ -1309,7 +1344,7 @@ if (do_errtrig()) return GE_NOMEM; - addr = gensio_addr_make(o, sizeof(struct sockaddr_storage)); + addr = gensio_addr_make(o, sizeof(struct sockaddr_storage), true); if (!addr) return GE_NOMEM; @@ -1461,6 +1496,15 @@ for (rp = ai->a; rp != NULL; rp = rp->ai_next) { if (family != rp->ai_family) continue; + /* + * getaddrinfo() will return the same address twice in the + * list if ::1 and 127.0.0.1 are both set for localhost in + * /etc/hosts. So the second open attempt will fail if we + * don't ignore this. In general, it's probably better to + * ignore duplicates in this function, anyway. + */ + if (sockaddr_in_list_b4(rp, ai->a)) + continue; rv = gensio_setup_listen_socket(o, rp->ai_socktype == SOCK_STREAM, rp->ai_family, rp->ai_socktype, @@ -1950,7 +1994,7 @@ if (!strtok_buffer) return GE_NOMEM; - addr = gensio_addr_make(o, 0); + addr = gensio_addr_make(o, 0, true); if (!addr) { o->free(o, strtok_buffer); return GE_NOMEM; @@ -1959,7 +2003,7 @@ ip = strtok_r(strtok_buffer, ",", &strtok_data); while (ip) { int family = ifamily, rflags = 0; - bool notype = false; + bool notype = false, gotaddr = false; if (strcmp(ip, "ipv4") == 0) { if (family != AF_UNSPEC && family != AF_INET) { @@ -2010,9 +2054,9 @@ * host). If the user does not specify an IP address, use * AF_INET6 and AI_V4MAPPED and it works fine. If the * user specifies an IP address, pull the V6 addresses - * then the V4 addresses. But only for listen sockets, - * connect sockets can only connect to one address (or one - * address type for SCTP). + * then the V4 addresses. Do this for TCP connect + * sockets, too, as the connection will be tried on each + * address. */ if (family == AF_UNSPEC) { notype = true; @@ -2066,9 +2110,16 @@ goto redo_getaddrinfo; } #endif + if (gotaddr) { + /* We got some address earlier, go with it. */ + rv = 0; + goto ignore_getaddr_error; + } + rv = GE_INVAL; goto out_err; } + gotaddr = true; /* * If a port was/was not set, this must be consistent for all @@ -2110,14 +2161,13 @@ goto out_err; } #ifdef AF_INET6 - if (listen && ip && notype && ifamily == AF_UNSPEC && - family == AF_INET6) { + if (ip && notype && ifamily == AF_UNSPEC && family == AF_INET6) { /* See comments above on why this is done. Yes, it's strange. */ family = AF_INET; goto redo_getaddrinfo; } #endif - + ignore_getaddr_error: ip = strtok_r(NULL, ",", &strtok_data); first = false; } @@ -2157,7 +2207,7 @@ if (len >= sizeof(saddr->sun_path) - 1) return GE_TOOBIG; - addr = gensio_addr_make(o, sizeof(socklen_t) + len + 1); + addr = gensio_addr_make(o, sizeof(socklen_t) + len + 1, true); if (!addr) return GE_NOMEM; @@ -2452,21 +2502,34 @@ addr->o = o; #if HAVE_GCC_ATOMICS - addr->refcount = iaddr->refcount; - addr->a = iaddr->a; - addr->is_getaddrinfo = iaddr->is_getaddrinfo; - __atomic_add_fetch(addr->refcount, 1, __ATOMIC_SEQ_CST); -#else - do { - int rv; + if (iaddr->refcount) { + addr->refcount = iaddr->refcount; + addr->a = iaddr->a; + addr->is_getaddrinfo = iaddr->is_getaddrinfo; + __atomic_add_fetch(addr->refcount, 1, __ATOMIC_SEQ_CST); + } else { +#endif + do { + int rv; - rv = addrinfo_list_dup(o, iaddr->a, &addr->a, NULL); - if (rv) { - addrinfo_list_free(o, addr->a); - o->free(o, addr); - return NULL; - } - } while(false); + rv = addrinfo_list_dup(o, iaddr->a, &addr->a, NULL); + if (rv) { + addrinfo_list_free(o, addr->a); + o->free(o, addr); + return NULL; + } +#if HAVE_GCC_ATOMICS + addr->refcount = o->zalloc(o, sizeof(*addr->refcount)); + if (!addr->refcount) { + addrinfo_list_free(o, addr->a); + o->free(o, addr); + return NULL; + } + *addr->refcount = 1; +#endif + } while(false); +#if HAVE_GCC_ATOMICS + } #endif addr->curr = addr->a; @@ -2482,7 +2545,7 @@ struct addrinfo *aip = NULL; int rv; - addr = gensio_addr_make(o, 0); + addr = gensio_addr_make(o, 0, true); if (!addr) return NULL; @@ -2555,11 +2618,13 @@ o = addr->o; #if HAVE_GCC_ATOMICS - if (__atomic_sub_fetch(addr->refcount, 1, __ATOMIC_SEQ_CST) != 0) { - o->free(o, addr); - return; + if (addr->refcount) { + if (__atomic_sub_fetch(addr->refcount, 1, __ATOMIC_SEQ_CST) != 0) { + o->free(o, addr); + return; + } + o->free(o, addr->refcount); } - o->free(o, addr->refcount); #endif if (addr->a) { if (addr->is_getaddrinfo)