From 2888604d2818fee0ef364566c30f566bf7d0dd00 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 12 Feb 2023 09:41:42 +0100 Subject: Merging upstream version 2.11.0. Signed-off-by: Daniel Baumann --- CHANGES | 48 ++++++ Makefile.am | 2 +- Makefile.in | 2 +- README.md | 2 +- configure | 46 ++++-- configure.ac | 6 +- contrib/queryparse/queryparse | 2 +- contrib/queryparse/queryparse.1 | 2 +- m4/dnsperf.m4 | 2 +- src/Makefile.am | 12 +- src/Makefile.in | 77 +++++++--- src/buffer.h | 2 +- src/config.h.in | 3 + src/datafile.c | 2 +- src/datafile.h | 2 +- src/dns.c | 2 +- src/dns.h | 2 +- src/dnsperf.1.in | 31 +++- src/dnsperf.c | 264 ++++++++++++++++++++++++++------ src/edns.c | 2 +- src/edns.h | 2 +- src/ext/hg64.c | 327 ++++++++++++++++++++++++++++++++++++++++ src/ext/hg64.h | 88 +++++++++++ src/ext/parse_uri.c | 112 ++++++++++++++ src/ext/parse_uri.h | 41 +++++ src/list.h | 2 +- src/log.c | 2 +- src/log.h | 2 +- src/net.c | 2 +- src/net.h | 2 +- src/net_doh.c | 6 +- src/net_dot.c | 4 +- src/net_tcp.c | 4 +- src/net_udp.c | 2 +- src/opt.c | 40 +++-- src/opt.h | 2 +- src/os.c | 2 +- src/os.h | 2 +- src/parse_uri.c | 112 -------------- src/parse_uri.h | 41 ----- src/qtype.c | 2 +- src/qtype.h | 2 +- src/resperf-report | 2 +- src/resperf.1.in | 2 +- src/resperf.c | 2 +- src/result.h | 2 +- src/strerror.c | 2 +- src/strerror.h | 2 +- src/test/test1.sh | 5 + src/tsig.c | 2 +- src/tsig.h | 2 +- src/util.h | 2 +- 52 files changed, 1048 insertions(+), 285 deletions(-) create mode 100644 src/ext/hg64.c create mode 100644 src/ext/hg64.h create mode 100644 src/ext/parse_uri.c create mode 100644 src/ext/parse_uri.h delete mode 100644 src/parse_uri.c delete mode 100644 src/parse_uri.h diff --git a/CHANGES b/CHANGES index 5d686d3..7dd03c4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,51 @@ +2023-02-08 Jerry Lundström + + Release 2.11.0 + + A couple of new features this release courtesy of Petr Špaček + @pspacek (ISC) and a bunch of bugfixes. + + First off `dnsperf` can now do verbose statistics during each interval + when using `-S`, see long option `verbose-interval-stats`. + + Next is a new latency histogram output using data structures (hg64) + created by Tony Finch @fanf2 (ISC), see long option + `latency-histogram`. These will also be shown during `-S` when used + together with `verbose-interval-stats`. + + Lastly a small change to boolean long options, they no longer require + a value (`=yes`) to be enabled. + + Bugfixes: + - Make sure the number of outstanding queries don't go negative, + happens if queries are timed out before being sent + - Fixed #208: + - `recv_one()`: Fix handling errno, only store EAGAIN if no other + error has been received + - `do_recv()`: Don't break on error as it will count it as a received + message + - Treat `EBADF` as `EAGAIN` for stateful connections, receive thread + might read from a closed socket if send thread is reconnecting + - `dnsperf`: warn if -c, -T, -q, -Q values are auto-adjusted + - Fixed #222: don't process unexpected message if the message is + suppressed + + 14db835 Opt arg + fb81481 Suppress unexpected + 64b8c6d stats_t initialization + 8290775 Fix first call to diff_stats + 4f8bd24 Compile support histograms + a9b4f04 External code, latency histograms + d1f4b65 add detailed latency histograms + 044e3a2 data structures for detailed latency histograms + ad3fb03 Opt, verbose statistics + 38bc936 Command usage warnings + 9f31595 Bad file descriptor + d3650eb Receive socket error handling + 84c8e72 Negative outstanding + e7df5e1 Clarify meaning of dnsperf -S output in the man page + 830eb43 verbose interval stats for dnsperf + 2022-11-11 Jerry Lundström Release 2.10.0 diff --git a/Makefile.am b/Makefile.am index a992b0e..594735c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -# Copyright 2019-2022 OARC, Inc. +# Copyright 2019-2023 OARC, Inc. # Copyright 2017-2018 Akamai Technologies # Copyright 2006-2016 Nominum, Inc. # All rights reserved. diff --git a/Makefile.in b/Makefile.in index 1fe1047..945d94a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -14,7 +14,7 @@ @SET_MAKE@ -# Copyright 2019-2022 OARC, Inc. +# Copyright 2019-2023 OARC, Inc. # Copyright 2017-2018 Akamai Technologies # Copyright 2006-2016 Nominum, Inc. # All rights reserved. diff --git a/README.md b/README.md index 123c7a5..5ddb412 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ The contrib directory contains additional software related to `dnsperf` and ## License ``` -Copyright 2019-2022 OARC, Inc. +Copyright 2019-2023 OARC, Inc. Copyright 2017-2018 Akamai Technologies Copyright 2006-2016 Nominum, Inc. All rights reserved. diff --git a/configure b/configure index de90675..91c1516 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.69 for dnsperf 2.10.0. +# Generated by GNU Autoconf 2.69 for dnsperf 2.11.0. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='dnsperf' PACKAGE_TARNAME='dnsperf' -PACKAGE_VERSION='2.10.0' -PACKAGE_STRING='dnsperf 2.10.0' +PACKAGE_VERSION='2.11.0' +PACKAGE_STRING='dnsperf 2.11.0' PACKAGE_BUGREPORT='admin@dns-oarc.net' PACKAGE_URL='https://github.com/DNS-OARC/dnsperf/issues' @@ -649,6 +649,8 @@ libssl_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG +HAVE_STDATOMIC_FALSE +HAVE_STDATOMIC_TRUE PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CC @@ -1360,7 +1362,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 dnsperf 2.10.0 to adapt to many kinds of systems. +\`configure' configures dnsperf 2.11.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1431,7 +1433,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of dnsperf 2.10.0:";; + short | recursive ) echo "Configuration of dnsperf 2.11.0:";; esac cat <<\_ACEOF @@ -1570,7 +1572,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -dnsperf configure 2.10.0 +dnsperf configure 2.11.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1939,7 +1941,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 dnsperf $as_me 2.10.0, which was +It was created by dnsperf $as_me 2.11.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2802,7 +2804,7 @@ fi # Define the identity of the package. PACKAGE='dnsperf' - VERSION='2.10.0' + VERSION='2.11.0' cat >>confdefs.h <<_ACEOF @@ -12891,6 +12893,26 @@ _ACEOF fi +for ac_header in stdatomic.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default" +if test "x$ac_cv_header_stdatomic_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDATOMIC_H 1 +_ACEOF + +fi + +done + + if test "x$ac_cv_header_stdatomic_h" != "xno"; then + HAVE_STDATOMIC_TRUE= + HAVE_STDATOMIC_FALSE='#' +else + HAVE_STDATOMIC_TRUE='#' + HAVE_STDATOMIC_FALSE= +fi + # Check for OpenSSL @@ -14013,6 +14035,10 @@ if test -z "${ENABLE_GCOV_TRUE}" && test -z "${ENABLE_GCOV_FALSE}"; then as_fn_error $? "conditional \"ENABLE_GCOV\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${HAVE_STDATOMIC_TRUE}" && test -z "${HAVE_STDATOMIC_FALSE}"; then + as_fn_error $? "conditional \"HAVE_STDATOMIC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 @@ -14410,7 +14436,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 dnsperf $as_me 2.10.0, which was +This file was extended by dnsperf $as_me 2.11.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14477,7 +14503,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -dnsperf config.status 2.10.0 +dnsperf config.status 2.11.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 0a0130b..fa664da 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -# Copyright 2019-2022 OARC, Inc. +# Copyright 2019-2023 OARC, Inc. # Copyright 2017-2018 Akamai Technologies # Copyright 2006-2016 Nominum, Inc. # All rights reserved. @@ -16,7 +16,7 @@ # limitations under the License. AC_PREREQ(2.64) -AC_INIT([dnsperf], [2.10.0], [admin@dns-oarc.net], [dnsperf], [https://github.com/DNS-OARC/dnsperf/issues]) +AC_INIT([dnsperf], [2.11.0], [admin@dns-oarc.net], [dnsperf], [https://github.com/DNS-OARC/dnsperf/issues]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) AC_CONFIG_SRCDIR([src/dnsperf.c]) AC_CONFIG_HEADER([src/config.h]) @@ -56,6 +56,8 @@ AM_EXTRA_RECURSIVE_TARGETS([gcov]) # Checks for support. AX_PTHREAD AC_CHECK_LIB([m], [sqrt]) +AC_CHECK_HEADERS([stdatomic.h]) +AM_CONDITIONAL([HAVE_STDATOMIC], [test "x$ac_cv_header_stdatomic_h" != "xno"]) # Check for OpenSSL PKG_CHECK_MODULES([libssl], [libssl]) diff --git a/contrib/queryparse/queryparse b/contrib/queryparse/queryparse index b138406..8e12108 100755 --- a/contrib/queryparse/queryparse +++ b/contrib/queryparse/queryparse @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2019-2022 OARC, Inc. +# Copyright 2019-2023 OARC, Inc. # Copyright 2017-2018 Akamai Technologies # Copyright 2006-2016 Nominum, Inc. # All rights reserved. diff --git a/contrib/queryparse/queryparse.1 b/contrib/queryparse/queryparse.1 index 3483d27..36c14cb 100644 --- a/contrib/queryparse/queryparse.1 +++ b/contrib/queryparse/queryparse.1 @@ -1,4 +1,4 @@ -.\" Copyright 2019-2022 OARC, Inc. +.\" Copyright 2019-2023 OARC, Inc. .\" Copyright 2017-2018 Akamai Technologies .\" Copyright 2006-2016 Nominum, Inc. .\" All rights reserved. diff --git a/m4/dnsperf.m4 b/m4/dnsperf.m4 index fb5378d..4cf228f 100644 --- a/m4/dnsperf.m4 +++ b/m4/dnsperf.m4 @@ -1,4 +1,4 @@ -# Copyright 2019-2022 OARC, Inc. +# Copyright 2019-2023 OARC, Inc. # Copyright 2017-2018 Akamai Technologies # Copyright 2006-2016 Nominum, Inc. # All rights reserved. diff --git a/src/Makefile.am b/src/Makefile.am index 119e187..810f99b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -# Copyright 2019-2022 OARC, Inc. +# Copyright 2019-2023 OARC, Inc. # Copyright 2017-2018 Akamai Technologies # Copyright 2006-2016 Nominum, Inc. # All rights reserved. @@ -30,9 +30,15 @@ bin_PROGRAMS = dnsperf resperf dist_bin_SCRIPTS = resperf-report _libperf_sources = datafile.c dns.c log.c net.c opt.c os.c strerror.c qtype.c \ - edns.c tsig.c net_udp.c net_tcp.c net_dot.c net_doh.c parse_uri.c + edns.c tsig.c net_udp.c net_tcp.c net_dot.c net_doh.c ext/parse_uri.c + _libperf_headers = datafile.h dns.h log.h net.h opt.h os.h util.h strerror.h \ - list.h result.h buffer.h qtype.h edns.h tsig.h parse_uri.h + list.h result.h buffer.h qtype.h edns.h tsig.h ext/parse_uri.h + +if HAVE_STDATOMIC +_libperf_sources += ext/hg64.c +_libperf_headers += ext/hg64.h +endif dnsperf_SOURCES = $(_libperf_sources) dnsperf.c dist_dnsperf_SOURCES = $(_libperf_headers) diff --git a/src/Makefile.in b/src/Makefile.in index 1772980..1b510c7 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -14,7 +14,7 @@ @SET_MAKE@ -# Copyright 2019-2022 OARC, Inc. +# Copyright 2019-2023 OARC, Inc. # Copyright 2017-2018 Akamai Technologies # Copyright 2006-2016 Nominum, Inc. # All rights reserved. @@ -107,6 +107,8 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = dnsperf$(EXEEXT) resperf$(EXEEXT) +@HAVE_STDATOMIC_TRUE@am__append_1 = ext/hg64.c +@HAVE_STDATOMIC_TRUE@am__append_2 = ext/hg64.h subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_flag.m4 \ @@ -127,14 +129,23 @@ CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(man1dir)" PROGRAMS = $(bin_PROGRAMS) -am__objects_1 = datafile.$(OBJEXT) dns.$(OBJEXT) log.$(OBJEXT) \ +am__dnsperf_SOURCES_DIST = datafile.c dns.c log.c net.c opt.c os.c \ + strerror.c qtype.c edns.c tsig.c net_udp.c net_tcp.c net_dot.c \ + net_doh.c ext/parse_uri.c ext/hg64.c dnsperf.c +am__dirstamp = $(am__leading_dot)dirstamp +@HAVE_STDATOMIC_TRUE@am__objects_1 = ext/hg64.$(OBJEXT) +am__objects_2 = datafile.$(OBJEXT) dns.$(OBJEXT) log.$(OBJEXT) \ net.$(OBJEXT) opt.$(OBJEXT) os.$(OBJEXT) strerror.$(OBJEXT) \ qtype.$(OBJEXT) edns.$(OBJEXT) tsig.$(OBJEXT) \ net_udp.$(OBJEXT) net_tcp.$(OBJEXT) net_dot.$(OBJEXT) \ - net_doh.$(OBJEXT) parse_uri.$(OBJEXT) -am_dnsperf_OBJECTS = $(am__objects_1) dnsperf.$(OBJEXT) -am__objects_2 = -dist_dnsperf_OBJECTS = $(am__objects_2) + net_doh.$(OBJEXT) ext/parse_uri.$(OBJEXT) $(am__objects_1) +am_dnsperf_OBJECTS = $(am__objects_2) dnsperf.$(OBJEXT) +am__dist_dnsperf_SOURCES_DIST = datafile.h dns.h log.h net.h opt.h \ + os.h util.h strerror.h list.h result.h buffer.h qtype.h edns.h \ + tsig.h ext/parse_uri.h ext/hg64.h +am__objects_3 = +am__objects_4 = $(am__objects_3) +dist_dnsperf_OBJECTS = $(am__objects_4) dnsperf_OBJECTS = $(am_dnsperf_OBJECTS) $(dist_dnsperf_OBJECTS) am__DEPENDENCIES_1 = dnsperf_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @@ -144,8 +155,14 @@ AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = -am_resperf_OBJECTS = $(am__objects_1) resperf.$(OBJEXT) -dist_resperf_OBJECTS = $(am__objects_2) +am__resperf_SOURCES_DIST = datafile.c dns.c log.c net.c opt.c os.c \ + strerror.c qtype.c edns.c tsig.c net_udp.c net_tcp.c net_dot.c \ + net_doh.c ext/parse_uri.c ext/hg64.c resperf.c +am_resperf_OBJECTS = $(am__objects_2) resperf.$(OBJEXT) +am__dist_resperf_SOURCES_DIST = datafile.h dns.h log.h net.h opt.h \ + os.h util.h strerror.h list.h result.h buffer.h qtype.h edns.h \ + tsig.h ext/parse_uri.h ext/hg64.h +dist_resperf_OBJECTS = $(am__objects_4) resperf_OBJECTS = $(am_resperf_OBJECTS) $(dist_resperf_OBJECTS) resperf_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @@ -198,9 +215,9 @@ am__depfiles_remade = ./$(DEPDIR)/datafile.Po ./$(DEPDIR)/dns.Po \ ./$(DEPDIR)/net.Po ./$(DEPDIR)/net_doh.Po \ ./$(DEPDIR)/net_dot.Po ./$(DEPDIR)/net_tcp.Po \ ./$(DEPDIR)/net_udp.Po ./$(DEPDIR)/opt.Po ./$(DEPDIR)/os.Po \ - ./$(DEPDIR)/parse_uri.Po ./$(DEPDIR)/qtype.Po \ - ./$(DEPDIR)/resperf.Po ./$(DEPDIR)/strerror.Po \ - ./$(DEPDIR)/tsig.Po + ./$(DEPDIR)/qtype.Po ./$(DEPDIR)/resperf.Po \ + ./$(DEPDIR)/strerror.Po ./$(DEPDIR)/tsig.Po \ + ext/$(DEPDIR)/hg64.Po ext/$(DEPDIR)/parse_uri.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) @@ -222,8 +239,9 @@ am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(dnsperf_SOURCES) $(dist_dnsperf_SOURCES) \ $(resperf_SOURCES) $(dist_resperf_SOURCES) -DIST_SOURCES = $(dnsperf_SOURCES) $(dist_dnsperf_SOURCES) \ - $(resperf_SOURCES) $(dist_resperf_SOURCES) +DIST_SOURCES = $(am__dnsperf_SOURCES_DIST) \ + $(am__dist_dnsperf_SOURCES_DIST) $(am__resperf_SOURCES_DIST) \ + $(am__dist_resperf_SOURCES_DIST) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ @@ -440,12 +458,12 @@ AM_CFLAGS = -I$(srcdir) \ EXTRA_DIST = dnsperf.1.in resperf-report resperf.1.in dist_bin_SCRIPTS = resperf-report -_libperf_sources = datafile.c dns.c log.c net.c opt.c os.c strerror.c qtype.c \ - edns.c tsig.c net_udp.c net_tcp.c net_dot.c net_doh.c parse_uri.c - -_libperf_headers = datafile.h dns.h log.h net.h opt.h os.h util.h strerror.h \ - list.h result.h buffer.h qtype.h edns.h tsig.h parse_uri.h - +_libperf_sources = datafile.c dns.c log.c net.c opt.c os.c strerror.c \ + qtype.c edns.c tsig.c net_udp.c net_tcp.c net_dot.c net_doh.c \ + ext/parse_uri.c $(am__append_1) +_libperf_headers = datafile.h dns.h log.h net.h opt.h os.h util.h \ + strerror.h list.h result.h buffer.h qtype.h edns.h tsig.h \ + ext/parse_uri.h $(am__append_2) dnsperf_SOURCES = $(_libperf_sources) dnsperf.c dist_dnsperf_SOURCES = $(_libperf_headers) dnsperf_LDADD = $(PTHREAD_LIBS) $(libssl_LIBS) $(libcrypto_LIBS) \ @@ -555,6 +573,15 @@ clean-binPROGRAMS: list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list +ext/$(am__dirstamp): + @$(MKDIR_P) ext + @: > ext/$(am__dirstamp) +ext/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) ext/$(DEPDIR) + @: > ext/$(DEPDIR)/$(am__dirstamp) +ext/parse_uri.$(OBJEXT): ext/$(am__dirstamp) \ + ext/$(DEPDIR)/$(am__dirstamp) +ext/hg64.$(OBJEXT): ext/$(am__dirstamp) ext/$(DEPDIR)/$(am__dirstamp) dnsperf$(EXEEXT): $(dnsperf_OBJECTS) $(dnsperf_DEPENDENCIES) $(EXTRA_dnsperf_DEPENDENCIES) @rm -f dnsperf$(EXEEXT) @@ -601,6 +628,7 @@ uninstall-dist_binSCRIPTS: mostlyclean-compile: -rm -f *.$(OBJEXT) + -rm -f ext/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @@ -617,11 +645,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_udp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse_uri.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qtype.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resperf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strerror.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ext/$(DEPDIR)/hg64.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ext/$(DEPDIR)/parse_uri.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @@ -893,6 +922,8 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ext/$(DEPDIR)/$(am__dirstamp) + -rm -f ext/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -916,11 +947,12 @@ distclean: distclean-recursive -rm -f ./$(DEPDIR)/net_udp.Po -rm -f ./$(DEPDIR)/opt.Po -rm -f ./$(DEPDIR)/os.Po - -rm -f ./$(DEPDIR)/parse_uri.Po -rm -f ./$(DEPDIR)/qtype.Po -rm -f ./$(DEPDIR)/resperf.Po -rm -f ./$(DEPDIR)/strerror.Po -rm -f ./$(DEPDIR)/tsig.Po + -rm -f ext/$(DEPDIR)/hg64.Po + -rm -f ext/$(DEPDIR)/parse_uri.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-tags @@ -982,11 +1014,12 @@ maintainer-clean: maintainer-clean-recursive -rm -f ./$(DEPDIR)/net_udp.Po -rm -f ./$(DEPDIR)/opt.Po -rm -f ./$(DEPDIR)/os.Po - -rm -f ./$(DEPDIR)/parse_uri.Po -rm -f ./$(DEPDIR)/qtype.Po -rm -f ./$(DEPDIR)/resperf.Po -rm -f ./$(DEPDIR)/strerror.Po -rm -f ./$(DEPDIR)/tsig.Po + -rm -f ext/$(DEPDIR)/hg64.Po + -rm -f ext/$(DEPDIR)/parse_uri.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/src/buffer.h b/src/buffer.h index 52bfef2..1cc5962 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/config.h.in b/src/config.h.in index 49e5f44..bdd273f 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -36,6 +36,9 @@ /* Have PTHREAD_PRIO_INHERIT. */ #undef HAVE_PTHREAD_PRIO_INHERIT +/* Define to 1 if you have the header file. */ +#undef HAVE_STDATOMIC_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H diff --git a/src/datafile.c b/src/datafile.c index 06ea0ea..85e34b8 100644 --- a/src/datafile.c +++ b/src/datafile.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/datafile.h b/src/datafile.h index a1b737e..bebc1e9 100644 --- a/src/datafile.h +++ b/src/datafile.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/dns.c b/src/dns.c index 20bb354..c990d9b 100644 --- a/src/dns.c +++ b/src/dns.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/dns.h b/src/dns.h index c126f97..0c0df3c 100644 --- a/src/dns.h +++ b/src/dns.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/dnsperf.1.in b/src/dnsperf.1.in index 9ae24bd..c44a5f3 100644 --- a/src/dnsperf.1.in +++ b/src/dnsperf.1.in @@ -1,4 +1,4 @@ -.\" Copyright 2019-2022 OARC, Inc. +.\" Copyright 2019-2023 OARC, Inc. .\" Copyright 2017-2018 Akamai Technologies .\" Copyright 2006-2016 Nominum, Inc. .\" All rights reserved. @@ -341,8 +341,9 @@ The default is the loopback address, 127.0.0.1. \fB-S \fIstats_interval\fR .br .RS -If this parameter is specified, a count of the number of queries per second -during the interval will be printed out every stats_interval seconds. +If this parameter is specified, a count of the number of answers received +per second during the interval will be printed out every \fIstats_interval\fR +seconds. .RE \fB-t \fItimeout\fR @@ -458,7 +459,6 @@ Following type are available. .br \fBunexpected\fR: Suppress messages about answers with an unexpected message ID .RE - \fBnum-queries-per-conn=\fINUMBER\fR .br .RS @@ -474,6 +474,29 @@ Waiting for responses may timeout and the timeout used for this is the same as specified by \fB-t\fR. Note that this option is only useful for connection oriented protocols. .RE + +\fBverbose-interval-stats\fR +.br +.RS +Change the statistics format of \fB-S\fR to that shown at end of run. + +\fIPlease note\fR: Min/max values for latency and connections are not +available in interval statistics. +Number of answers received within \fIstats_interval\fR can legitimately +exceed number of queries sent, depending on answer latency, configured +\fItimeout\fR, and \fIstats_interval\fR. +.RE + +\fBlatency-histogram\fR +.br +.RS +Print detailed latency histograms for DNS answers and connections. +Latency is quantized into bins with roughly 3 % resolution, and latency +range for individual bins increases logarithmically. +This is done to to limit amount of memory required for histograms +and also allows to visualize latency using logarithmic percentile histograms +with minimal postprocessing. +.RE .SH "SEE ALSO" \fBresperf\fR(1) .SH AUTHOR diff --git a/src/dnsperf.c b/src/dnsperf.c index 7d10212..90b7874 100644 --- a/src/dnsperf.c +++ b/src/dnsperf.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. @@ -32,6 +32,10 @@ #include "util.h" #include "list.h" #include "buffer.h" +#if HAVE_STDATOMIC_H +#include "ext/hg64.h" +#define USE_HISTOGRAMS +#endif #include #include @@ -49,6 +53,8 @@ #include #include +#define HISTOGRAM_SIGBITS 5 /* about 3 % latency precision */ + #define DEFAULT_SERVER_NAME "127.0.0.1" #define DEFAULT_SERVER_PORT 53 #define DEFAULT_SERVER_DOT_PORT 853 @@ -85,6 +91,7 @@ typedef struct { uint32_t max_outstanding; uint32_t max_qps; uint64_t stats_interval; + bool verbose_interval_stats; bool updates; bool binary_input; perf_input_format_t input_format; @@ -92,6 +99,9 @@ typedef struct { enum perf_net_mode mode; perf_suppress_t suppress; size_t num_queries_per_conn; +#ifdef USE_HISTOGRAMS + bool latency_histogram; +#endif } config_t; typedef struct { @@ -101,8 +111,9 @@ typedef struct { struct timespec stop_time_ns; } times_t; +#define DNSPERF_STATS_RCODECOUNTS 16 typedef struct { - uint64_t rcodecounts[16]; + uint64_t rcodecounts[DNSPERF_STATS_RCODECOUNTS]; uint64_t num_sent; uint64_t num_interrupted; @@ -124,6 +135,11 @@ typedef struct { uint64_t conn_latency_sum_squares; uint64_t conn_latency_min; uint64_t conn_latency_max; + +#ifdef USE_HISTOGRAMS + hg64* latency; + hg64* conn_latency; +#endif } stats_t; typedef perf_list(struct query_info) query_list; @@ -257,7 +273,86 @@ stddev(uint64_t sum_of_squares, uint64_t sum, uint64_t total) } static void -print_statistics(const config_t* config, const times_t* times, stats_t* stats) +diff_stats(const config_t* config, stats_t* last, stats_t* now, stats_t* diff) +{ + int i = 0; + for (; i < DNSPERF_STATS_RCODECOUNTS; i++) { + diff->rcodecounts[i] = now->rcodecounts[i] - last->rcodecounts[i]; + } + + diff->num_sent = now->num_sent - last->num_sent; + diff->num_interrupted = now->num_interrupted - last->num_interrupted; + diff->num_timedout = now->num_timedout - last->num_timedout; + diff->num_completed = now->num_completed - last->num_completed; + + diff->total_request_size = now->total_request_size - last->total_request_size; + diff->total_response_size = now->total_response_size - last->total_response_size; + + diff->latency_sum = now->latency_sum - last->latency_sum; + diff->latency_sum_squares = now->latency_sum_squares - last->latency_sum_squares; + diff->latency_min = 0; /* not enough data */ + diff->latency_max = 0; + + diff->num_conn_reconnect = now->num_conn_reconnect - last->num_conn_reconnect; + diff->num_conn_completed = now->num_conn_completed - last->num_conn_completed; + + diff->conn_latency_sum = now->conn_latency_sum - last->conn_latency_sum; + diff->conn_latency_sum_squares = now->conn_latency_sum_squares - last->conn_latency_sum_squares; + diff->conn_latency_min = 0; + diff->conn_latency_max = 0; + +#ifdef USE_HISTOGRAMS + if (config->latency_histogram) { + free(diff->latency); + diff->latency = hg64_create(HISTOGRAM_SIGBITS); + if (last->latency) { + hg64_diff(now->latency, last->latency, diff->latency); + } else { /* first sample */ + hg64_merge(diff->latency, now->latency); + } + hg64_get(diff->latency, hg64_min_key(diff->latency), &diff->latency_min, NULL, NULL); + hg64_get(diff->latency, hg64_max_key(diff->latency), NULL, &diff->latency_max, NULL); + + free(diff->conn_latency); + diff->conn_latency = hg64_create(HISTOGRAM_SIGBITS); + if (last->conn_latency) { + hg64_diff(now->conn_latency, last->conn_latency, diff->conn_latency); + } else { /* first sample */ + hg64_merge(diff->conn_latency, now->conn_latency); + } + hg64_get(diff->conn_latency, hg64_min_key(diff->conn_latency), &diff->conn_latency_min, NULL, NULL); + hg64_get(diff->conn_latency, hg64_max_key(diff->conn_latency), NULL, &diff->conn_latency_max, NULL); + } +#endif +} + +#ifdef USE_HISTOGRAMS +static void +print_histogram(hg64* histogram, const char* const desc) +{ + printf(" Latency bucket (s): %s\n", desc); + uint64_t pmin, pmax, pcount; + for (unsigned key = 0; + hg64_get(histogram, key, &pmin, &pmax, &pcount) == true; + key = hg64_next(histogram, key)) { + if (pcount == 0) + continue; + printf(" %" PRIu64 ".%06" PRIu64 " - %" PRIu64 ".%06" PRIu64 ": %" PRIu64 "\n", + pmin / MILLION, + pmin % MILLION, + pmax / MILLION, + pmax % MILLION, + pcount); + }; +} +#endif + +/* + * now != 0 is call to print stats in the middle of test run. + * min-max values are not available on per-interval basis, so skip them. + */ +static void +print_statistics(const config_t* config, const times_t* times, stats_t* stats, uint64_t now, uint64_t interval_time) { const char* units; uint64_t run_time; @@ -267,9 +362,12 @@ print_statistics(const config_t* config, const times_t* times, stats_t* stats) units = config->updates ? "Updates" : "Queries"; - run_time = times->end_time - times->start_time; + if (now) + run_time = now - times->start_time; + else + run_time = times->end_time - times->start_time; - printf("Statistics:\n\n"); + printf("%sStatistics:\n\n", now ? "Interval " : ""); printf(" %s sent: %" PRIu64 "\n", units, stats->num_sent); @@ -287,7 +385,7 @@ print_statistics(const config_t* config, const times_t* times, stats_t* stats) printf(" Response codes: "); first_rcode = true; - for (i = 0; i < 16; i++) { + for (i = 0; i < DNSPERF_STATS_RCODECOUNTS; i++) { if (stats->rcodecounts[i] == 0) continue; if (first_rcode) @@ -308,23 +406,33 @@ print_statistics(const config_t* config, const times_t* times, stats_t* stats) (unsigned int)(run_time / MILLION), (unsigned int)(run_time % MILLION)); printf(" %s per second: %.6lf\n", units, - PERF_SAFE_DIV(stats->num_completed, (((double)run_time) / MILLION))); + PERF_SAFE_DIV(stats->num_completed, (((double)(now ? interval_time : run_time) / MILLION)))); printf("\n"); latency_avg = PERF_SAFE_DIV(stats->latency_sum, stats->num_completed); - printf(" Average Latency (s): %u.%06u (min %u.%06u, max %u.%06u)\n", + printf(" Average Latency (s): %u.%06u", (unsigned int)(latency_avg / MILLION), - (unsigned int)(latency_avg % MILLION), - (unsigned int)(stats->latency_min / MILLION), - (unsigned int)(stats->latency_min % MILLION), - (unsigned int)(stats->latency_max / MILLION), - (unsigned int)(stats->latency_max % MILLION)); + (unsigned int)(latency_avg % MILLION)); + if (!now) { + printf(" (min %u.%06u, max %u.%06u)\n", + (unsigned int)(stats->latency_min / MILLION), + (unsigned int)(stats->latency_min % MILLION), + (unsigned int)(stats->latency_max / MILLION), + (unsigned int)(stats->latency_max % MILLION)); + } else { + printf("\n"); + } + if (stats->num_completed > 1) { printf(" Latency StdDev (s): %f\n", stddev(stats->latency_sum_squares, stats->latency_sum, stats->num_completed) / MILLION); +#ifdef USE_HISTOGRAMS + if (config->latency_histogram) + print_histogram(stats->latency, "answer count"); +#endif } printf("\n"); @@ -336,32 +444,56 @@ print_statistics(const config_t* config, const times_t* times, stats_t* stats) printf("Connection Statistics:\n\n"); printf(" Reconnections: %" PRIu64 "\n\n", stats->num_conn_reconnect); latency_avg = PERF_SAFE_DIV(stats->conn_latency_sum, stats->num_conn_completed); - printf(" Average Latency (s): %u.%06u (min %u.%06u, max %u.%06u)\n", + printf(" Average Latency (s): %u.%06u", (unsigned int)(latency_avg / MILLION), - (unsigned int)(latency_avg % MILLION), - (unsigned int)(stats->conn_latency_min / MILLION), - (unsigned int)(stats->conn_latency_min % MILLION), - (unsigned int)(stats->conn_latency_max / MILLION), - (unsigned int)(stats->conn_latency_max % MILLION)); + (unsigned int)(latency_avg % MILLION)); + if (!now) { + printf(" (min %u.%06u, max %u.%06u)\n", + (unsigned int)(stats->conn_latency_min / MILLION), + (unsigned int)(stats->conn_latency_min % MILLION), + (unsigned int)(stats->conn_latency_max / MILLION), + (unsigned int)(stats->conn_latency_max % MILLION)); + } else { + printf("\n"); + } if (stats->num_conn_completed > 1) { printf(" Latency StdDev (s): %f\n", stddev(stats->conn_latency_sum_squares, stats->conn_latency_sum, stats->num_conn_completed) / MILLION); +#ifdef USE_HISTOGRAMS + if (config->latency_histogram) + print_histogram(stats->latency, "connection count"); +#endif } printf("\n"); } +/* + * Caller must free() stats->latency and stats->conn_latency. + */ static void sum_stats(const config_t* config, stats_t* total) { unsigned int i, j; memset(total, 0, sizeof(*total)); +#ifdef USE_HISTOGRAMS + if (config->latency_histogram) { + total->latency = hg64_create(HISTOGRAM_SIGBITS); + total->conn_latency = hg64_create(HISTOGRAM_SIGBITS); + } +#endif for (i = 0; i < config->threads; i++) { stats_t* stats = &threads[i].stats; +#ifdef USE_HISTOGRAMS + if (config->latency_histogram) { + hg64_merge(total->latency, stats->latency); + hg64_merge(total->conn_latency, stats->conn_latency); + } +#endif - for (j = 0; j < 16; j++) + for (j = 0; j < DNSPERF_STATS_RCODECOUNTS; j++) total->rcodecounts[j] += stats->rcodecounts[j]; total->num_sent += stats->num_sent; @@ -499,6 +631,12 @@ setup(int argc, char** argv, config_t* config) "suppress messages/warnings, see man-page for list of message types", NULL, &local_suppress); perf_long_opt_add("num-queries-per-conn", perf_opt_uint, "queries", "Number of queries to send per connection", NULL, &config->num_queries_per_conn); + perf_long_opt_add("verbose-interval-stats", perf_opt_boolean, NULL, + "print detailed statistics for each stats_interval", NULL, &config->verbose_interval_stats); +#ifdef USE_HISTOGRAMS + perf_long_opt_add("latency-histogram", perf_opt_boolean, NULL, + "collect and print detailed latency histograms", NULL, &config->latency_histogram); +#endif bool log_stdout = false; perf_opt_add('W', perf_opt_boolean, NULL, "log warnings and errors to stdout instead of stderr", NULL, &log_stdout); @@ -574,14 +712,18 @@ setup(int argc, char** argv, config_t* config) * If we run more threads than max-qps, some threads will have * ->max_qps set to 0, and be unlimited. */ - if (config->max_qps > 0 && config->threads > config->max_qps) + if (config->max_qps > 0 && config->threads > config->max_qps) { + perf_log_warning("requested max QPS limit (-Q %u) is lower than number of threads (-T %u), lowering number of threads", config->max_qps, config->threads); config->threads = config->max_qps; + } /* * We also can't run more threads than clients. */ - if (config->threads > config->clients) + if (config->threads > config->clients) { + perf_log_warning("requested number of threads (-T %u) exceeds number of clients (-c %u), lowering number of threads\n", config->threads, config->clients); config->threads = config->clients; + } #ifndef HAVE_LDNS if (config->updates) { @@ -636,6 +778,10 @@ query_move(threadinfo_t* tinfo, query_info* q, query_move_op op) static inline uint64_t num_outstanding(const stats_t* stats) { + /* make sure negative values aren't returned */ + if (stats->num_completed + stats->num_timedout > stats->num_sent) { + return 0; + } return stats->num_sent - stats->num_completed - stats->num_timedout; } @@ -920,7 +1066,10 @@ recv_one(threadinfo_t* tinfo, int which_sock, } if (!n) { // Treat connection closed like try again until reconnection features are in - *saved_errnop = EAGAIN; + if (!*saved_errnop) { + // only set this if there was no error before to allow above error check to overwrite EAGAIN + *saved_errnop = EAGAIN; + } return false; } recvd->sock = tinfo->socks[which_sock]; @@ -1006,8 +1155,6 @@ do_recv(void* arg) break; } bit_set(socketbits, current_socket); - if (saved_errno != EAGAIN) - break; } if (j == tinfo->nsocks) break; @@ -1039,11 +1186,13 @@ do_recv(void* arg) perf_log_warning("received short response"); continue; } - if (recvd[i].unexpected && !tinfo->config->suppress.unexpected) { - perf_log_warning("received a response with an " - "unexpected (maybe timed out) " - "id: %u", - recvd[i].qid); + if (recvd[i].unexpected) { + if (!tinfo->config->suppress.unexpected) { + perf_log_warning("received a response with an " + "unexpected (maybe timed out) " + "id: %u", + recvd[i].qid); + } continue; } latency = recvd[i].when - recvd[i].sent; @@ -1061,6 +1210,11 @@ do_recv(void* arg) stats->total_response_size += recvd[i].size; stats->rcodecounts[recvd[i].rcode]++; stats->latency_sum += latency; +#ifdef USE_HISTOGRAMS + if (stats->latency) { + hg64_inc(stats->latency, latency); + } +#endif stats->latency_sum_squares += (latency * latency); if (latency < stats->latency_min || stats->num_completed == 1) stats->latency_min = latency; @@ -1097,18 +1251,17 @@ static void* do_interval_stats(void* arg) { threadinfo_t* tinfo; - stats_t total; + stats_t total = {}; + stats_t last = {}; + stats_t diff = {}; uint64_t now; uint64_t last_interval_time; - uint64_t last_completed; uint64_t interval_time; - uint64_t num_completed; double qps; struct perf_net_socket sock = { .mode = sock_pipe, .fd = threadpipe[0] }; tinfo = arg; last_interval_time = tinfo->times->start_time; - last_completed = 0; wait_for_start(); while (perf_os_waituntilreadable(&sock, threadpipe[0], @@ -1117,13 +1270,23 @@ do_interval_stats(void* arg) now = perf_get_time(); sum_stats(tinfo->config, &total); interval_time = now - last_interval_time; - num_completed = total.num_completed - last_completed; - qps = num_completed / (((double)interval_time) / MILLION); - perf_log_printf("%u.%06u: %.6lf", - (unsigned int)(now / MILLION), - (unsigned int)(now % MILLION), qps); + + if (tinfo->config->verbose_interval_stats) { + diff_stats(tinfo->config, &last, &total, &diff); + print_statistics(tinfo->config, tinfo->times, &diff, now, interval_time); + } else { + qps = (total.num_completed - last.num_completed) / (((double)interval_time) / MILLION); + perf_log_printf("%u.%06u: %.6lf", + (unsigned int)(now / MILLION), + (unsigned int)(now % MILLION), qps); + } + last_interval_time = now; - last_completed = total.num_completed; +#ifdef USE_HISTOGRAMS + free(last.latency); + free(last.conn_latency); +#endif + last = total; } return NULL; @@ -1189,6 +1352,11 @@ static void perf__net_event(struct perf_net_socket* sock, perf_socket_event_t ev case perf_socket_event_connected: stats->num_conn_completed++; +#ifdef USE_HISTOGRAMS + if (stats->conn_latency) { + hg64_inc(stats->conn_latency, elapsed_time); + } +#endif stats->conn_latency_sum += elapsed_time; stats->conn_latency_sum_squares += (elapsed_time * elapsed_time); if (elapsed_time < stats->conn_latency_min || stats->num_conn_completed == 1) @@ -1218,6 +1386,12 @@ threadinfo_init(threadinfo_t* tinfo, const config_t* config, perf_list_init(tinfo->outstanding_queries); perf_list_init(tinfo->unused_queries); +#ifdef USE_HISTOGRAMS + if (config->latency_histogram) { + tinfo->stats.latency = hg64_create(HISTOGRAM_SIGBITS); + tinfo->stats.conn_latency = hg64_create(HISTOGRAM_SIGBITS); + } +#endif for (i = 0; i < NQIDS; i++) { perf_link_init(&tinfo->queries[i]); perf_list_append(tinfo->unused_queries, &tinfo->queries[i]); @@ -1240,11 +1414,15 @@ threadinfo_init(threadinfo_t* tinfo, const config_t* config, /* * We can't have more than 64k outstanding queries per thread. */ - if (tinfo->max_outstanding > NQIDS) + if (tinfo->max_outstanding > NQIDS) { + perf_log_warning("requested number of outstanding queries (-q %u) per single thread (-T) exceeds built-in maximum %u, adjusting\n", tinfo->max_outstanding, NQIDS); tinfo->max_outstanding = NQIDS; + } - if (tinfo->nsocks > MAX_SOCKETS) + if (tinfo->nsocks > MAX_SOCKETS) { + perf_log_warning("requested number of clients (-c %u) per thread (-T) exceeds built-in maximum %u, adjusting\n", tinfo->nsocks, MAX_SOCKETS); tinfo->nsocks = MAX_SOCKETS; + } if (!(tinfo->socks = calloc(tinfo->nsocks, sizeof(*tinfo->socks)))) { perf_log_fatal("out of memory"); @@ -1383,7 +1561,7 @@ int main(int argc, char** argv) print_final_status(&config); sum_stats(&config, &total_stats); - print_statistics(&config, ×, &total_stats); + print_statistics(&config, ×, &total_stats, 0, 0); perf_net_stats_print(config.mode); cleanup(&config); diff --git a/src/edns.c b/src/edns.c index fa66cc4..d3a0608 100644 --- a/src/edns.c +++ b/src/edns.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/edns.h b/src/edns.h index 8064cc4..bcd6822 100644 --- a/src/edns.h +++ b/src/edns.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/ext/hg64.c b/src/ext/hg64.c new file mode 100644 index 0000000..9cd4b4f --- /dev/null +++ b/src/ext/hg64.c @@ -0,0 +1,327 @@ +/* + * hg64 - 64-bit histograms + * + * Written by Tony Finch + * + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hg64.h" + +/* number of bins is same as number of bits in a value */ +#define BINS 64 + +typedef atomic_uint_fast64_t counter; +typedef _Atomic(counter*) bin_ptr; + +struct hg64 { + unsigned sigbits; + bin_ptr bin[BINS]; +}; + +static inline counter* +get_bin(hg64* hg, unsigned b) +{ + /* key_to_new_counter() below has the matching store / release */ + return (atomic_load_explicit(&hg->bin[b], memory_order_acquire)); +} + +/* + * when we only care about the histogram precision + */ +struct hg64p { + unsigned sigbits; +}; + +#ifdef __has_attribute +#if __has_attribute(__transparent_union__) +#define TRANSPARENT __attribute__((__transparent_union__)) +#endif +#endif + +#ifdef TRANSPARENT + +typedef union hg64u { + hg64* hg; + const struct hg64p* hp; +} hg64u TRANSPARENT; + +#define hg64p(hu) ((hu).hp) +#else + +typedef void* hg64u; + +#define hg64p(hu) ((const struct hg64p*)(hu)) +#endif + +/* + * The bins arrays have a static size for simplicity, but that means We + * waste a little extra space that could be saved by omitting the + * exponents that land in the denormal number bin. The following macros + * calculate (at run time) the exact number of keys when we need to do + * accurate bounds checks. + */ +#define DENORMALS(hp) ((hp)->sigbits - 1) +#define EXPONENTS(hp) (BINS - DENORMALS(hp)) +#define MANTISSAS(hp) (1 << (hp)->sigbits) +#define KEYS(hp) (EXPONENTS(hp) * MANTISSAS(hp)) + +#define BINSIZE(hp) MANTISSAS(hp) + +/**********************************************************************/ + +#define OUTARG(ptr, val) (void)(((ptr) != NULL) && (bool)(*(ptr) = (val))) + +/**********************************************************************/ + +hg64* hg64_create(unsigned sigbits) +{ + if (sigbits < 1 || 15 < sigbits) { + return (NULL); + } + hg64* hg = malloc(sizeof(*hg)); + hg->sigbits = sigbits; + /* + * it is probably portable to zero-initialize atomics but the + * C standard says we shouldn't rely on it; but this loop + * should optimize to memset() on most target systems + */ + for (unsigned b = 0; b < BINS; b++) { + atomic_init(&hg->bin[b], NULL); + } + return (hg); +} + +void hg64_destroy(hg64* hg) +{ + for (unsigned b = 0; b < BINS; b++) { + free(get_bin(hg, b)); + } + *hg = (hg64) { 0 }; + free(hg); +} + +/**********************************************************************/ + +static inline uint64_t +key_to_minval(hg64u hu, unsigned key) +{ + unsigned binsize = BINSIZE(hg64p(hu)); + unsigned exponent = (key / binsize) - 1; + uint64_t mantissa = (key % binsize) + binsize; + return (key < binsize ? key : mantissa << exponent); +} + +/* + * don't shift by 64, and don't underflow exponent; instead, + * reduce shift by 1 for each hazard and pre-shift UINT64_MAX + */ +static inline uint64_t +key_to_maxval(hg64u hu, unsigned key) +{ + unsigned binsize = BINSIZE(hg64p(hu)); + unsigned shift = 63 - (key / binsize); + uint64_t range = UINT64_MAX / 4 >> shift; + return (key_to_minval(hu, key) + range); +} + +/* + * This branchless conversion is due to Paul Khuong: see bin_down_of() in + * https://pvk.ca/Blog/2015/06/27/linear-log-bucketing-fast-versatile-simple/ + */ +static inline unsigned +value_to_key(hg64u hu, uint64_t value) +{ + /* fast path */ + const struct hg64p* hp = hg64p(hu); + /* ensure that denormal numbers are all in the same bin */ + uint64_t binned = value | BINSIZE(hp); + int clz = __builtin_clzll((unsigned long long)(binned)); + /* actually 1 less than the exponent except for denormals */ + unsigned exponent = 63 - hp->sigbits - clz; + /* mantissa has leading bit set except for denormals */ + unsigned mantissa = value >> exponent; + /* leading bit of mantissa adds one to exponent */ + return ((exponent << hp->sigbits) + mantissa); +} + +static counter* +key_to_new_counter(hg64* hg, unsigned key) +{ + /* slow path */ + unsigned binsize = BINSIZE(hg); + unsigned b = key / binsize; + unsigned c = key % binsize; + counter* old_bp = NULL; + counter* new_bp = malloc(sizeof(counter) * binsize); + /* see comment in hg64_create() above */ + for (unsigned i = 0; i < binsize; i++) { + atomic_init(new_bp + i, 0); + } + bin_ptr* bpp = &hg->bin[b]; + if (atomic_compare_exchange_strong_explicit(bpp, &old_bp, new_bp, + memory_order_acq_rel, memory_order_acquire)) { + return (new_bp + c); + } else { + /* lost the race, so use the winner's counters */ + free(new_bp); + return (old_bp + c); + } +} + +static inline counter* +key_to_counter(hg64* hg, unsigned key) +{ + /* fast path */ + unsigned binsize = BINSIZE(hg); + unsigned b = key / binsize; + unsigned c = key % binsize; + counter* bp = get_bin(hg, b); + return (bp == NULL ? NULL : bp + c); +} + +static inline uint64_t +get_key_count(hg64* hg, unsigned key) +{ + counter* ctr = key_to_counter(hg, key); + return (ctr == NULL ? 0 : atomic_load_explicit(ctr, memory_order_relaxed)); +} + +static inline void +add_key_count(hg64* hg, unsigned key, uint64_t inc) +{ + if (inc == 0) + return; + counter* ctr = key_to_counter(hg, key); + ctr = ctr ? ctr : key_to_new_counter(hg, key); + atomic_fetch_add_explicit(ctr, inc, memory_order_relaxed); +} + +/**********************************************************************/ + +void hg64_inc(hg64* hg, uint64_t value) +{ + add_key_count(hg, value_to_key(hg, value), 1); +} + +bool hg64_get(hg64* hg, unsigned key, + uint64_t* pmin, uint64_t* pmax, uint64_t* pcount) +{ + if (key < KEYS(hg)) { + OUTARG(pmin, key_to_minval(hg, key)); + OUTARG(pmax, key_to_maxval(hg, key)); + OUTARG(pcount, get_key_count(hg, key)); + return (true); + } else { + return (false); + } +} + +unsigned +hg64_next(hg64* hg, unsigned key) +{ + key++; + while (key < KEYS(hg) && (key & (BINSIZE(hg) - 1)) == 0 && key_to_counter(hg, key) == NULL) { + key += BINSIZE(hg); + } + return (key); +} + +/* + * https://fanf2.user.srcf.net/hermes/doc/antiforgery/stats.pdf + */ +void hg64_mean_variance(hg64* hg, double* pmean, double* pvar) +{ + double pop = 0.0; + double mean = 0.0; + double sigma = 0.0; + uint64_t min, max, count; + for (unsigned key = 0; + hg64_get(hg, key, &min, &max, &count); + key = hg64_next(hg, key)) { + double delta = (double)min / 2.0 + (double)max / 2.0 - mean; + if (count != 0) { /* avoid division by zero */ + pop += count; + mean += count * delta / pop; + sigma += count * delta * (min + max - mean); + } + } + OUTARG(pmean, mean); + OUTARG(pvar, sigma / pop); +} + +/**********************************************************************/ + +void hg64_merge(hg64* target, hg64* source) +{ + uint64_t count; + for (unsigned skey = 0; + hg64_get(source, skey, NULL, NULL, &count); + skey = hg64_next(source, skey)) { + uint64_t svmin = key_to_minval(source, skey); + uint64_t svmax = key_to_maxval(source, skey); + unsigned tkmin = value_to_key(target, svmin); + unsigned tkmax = value_to_key(target, svmax); + unsigned keys = tkmax - tkmin + 1; + /* is there a more cunning way to spread out the remainder? */ + uint64_t div = count / keys; + uint64_t rem = count % keys; + for (unsigned tkey = tkmin; tkey <= tkmax; tkey++) { + uint64_t inc = div + (uint64_t)(tkey < rem); + add_key_count(target, tkey, inc); + } + } +} + +void hg64_diff(hg64* a, hg64* b, hg64* diff) +{ + assert((a->sigbits == b->sigbits) && (b->sigbits == diff->sigbits)); + uint64_t count_a = 0; + uint64_t count_b = 0; + for (unsigned key = 0; + hg64_get(a, key, NULL, NULL, &count_a); + key++) { + hg64_get(b, key, NULL, NULL, &count_b); + add_key_count(diff, key, count_a - count_b); + } +} + +unsigned hg64_min_key(hg64* hg) +{ + uint64_t pcount; + for (unsigned key = 0; + hg64_get(hg, key, NULL, NULL, &pcount); + key = hg64_next(hg, key)) { + if (pcount > 0) + return key; + } + return 0; +} + +unsigned hg64_max_key(hg64* hg) +{ + unsigned last_key = 0; + uint64_t pcount; + for (unsigned key = 0; + hg64_get(hg, key, NULL, NULL, &pcount); + key = hg64_next(hg, key)) { + if (pcount > 0) + last_key = key; + } + return last_key; +} diff --git a/src/ext/hg64.h b/src/ext/hg64.h new file mode 100644 index 0000000..21ec3d3 --- /dev/null +++ b/src/ext/hg64.h @@ -0,0 +1,88 @@ +/* + * hg64 - 64-bit histograms + * + * Written by Tony Finch + * + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef HG64_H +#define HG64_H 1 + +typedef struct hg64 hg64; + +/* + * Allocate a new histogram. `sigbits` must be between 1 and 15 + * inclusive; it is the number of significant bits of each value + * to use when mapping values to buckets. + */ +hg64* hg64_create(unsigned sigbits); + +/* + * Free the memory used by a histogram + */ +void hg64_destroy(hg64* hg); + +/* + * Add 1 to the value's bucket + */ +void hg64_inc(hg64* hg, uint64_t value); + +/* + * Get information about a bucket. This can be used as an iterator, + * by initializing `key` to zero and incrementing by one or using + * `hg64_next()` until `hg64_get()` returns `false`. The number of + * iterations is a little less than `1 << (6 + sigbits)`. + * + * If `pmin` is non-NULL it is set to the bucket's minimum inclusive value. + * + * If `pmax` is non-NULL it is set to the bucket's maximum inclusive value. + * + * If `pcount` is non-NULL it is set to the bucket's counter, which + * can be zero. (Empty buckets are included in the iterator.) + */ +bool hg64_get(hg64* hg, unsigned key, + uint64_t* pmin, uint64_t* pmax, uint64_t* pcount); + +/* + * Skip to the next key, omitting groups of nonexistent buckets. + */ +unsigned hg64_next(hg64* hg, unsigned key); + +/* + * Get summary statistics about the histogram. + * + * If `pmean` is non-NULL it is set to the mean of the recorded data. + * + * If `pvar` is non-NULL it is set to the variance of the recorded + * data. The standard deviation is the square root of the variance. + */ +void hg64_mean_variance(hg64* hg, double* pmean, double* pvar); + +/* + * Increase the counts in `target` by the counts recorded in `source` + */ +void hg64_merge(hg64* target, hg64* source); + +/* + * diff = a - b + */ +void hg64_diff(hg64* a, hg64* b, hg64* diff); + +/* + * Get highest key with non-zero value. Returns 0 if all values are 0. + */ +unsigned hg64_max_key(hg64* hg); + +/* + * Get lowest key with non-zero value. Returns 0 if all values are 0. + */ +unsigned hg64_min_key(hg64* hg); + +#endif diff --git a/src/ext/parse_uri.c b/src/ext/parse_uri.c new file mode 100644 index 0000000..fa74c85 --- /dev/null +++ b/src/ext/parse_uri.c @@ -0,0 +1,112 @@ +#include "parse_uri.h" + +#include + +// From: https://github.com/nghttp2/nghttp2/blob/master/examples/client.c +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2013 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +int parse_uri(struct URI* res, const char* uri) +{ + /* We only interested in https */ + size_t len, i, offset; + int ipv6addr = 0; + memset(res, 0, sizeof(struct URI)); + len = strlen(uri); + if (len < 9 || memcmp("https://", uri, 8) != 0) { + return -1; + } + offset = 8; + res->host = res->hostport = &uri[offset]; + res->hostlen = 0; + if (uri[offset] == '[') { + /* IPv6 literal address */ + ++offset; + ++res->host; + ipv6addr = 1; + for (i = offset; i < len; ++i) { + if (uri[i] == ']') { + res->hostlen = i - offset; + offset = i + 1; + break; + } + } + } else { + const char delims[] = ":/?#"; + for (i = offset; i < len; ++i) { + if (strchr(delims, uri[i]) != NULL) { + break; + } + } + res->hostlen = i - offset; + offset = i; + } + if (res->hostlen == 0) { + return -1; + } + /* Assuming https */ + res->port = 443; + if (offset < len) { + if (uri[offset] == ':') { + /* port */ + const char delims[] = "/?#"; + int port = 0; + ++offset; + for (i = offset; i < len; ++i) { + if (strchr(delims, uri[i]) != NULL) { + break; + } + if ('0' <= uri[i] && uri[i] <= '9') { + port *= 10; + port += uri[i] - '0'; + if (port > 65535) { + return -1; + } + } else { + return -1; + } + } + if (port == 0) { + return -1; + } + offset = i; + res->port = (uint16_t)port; + } + } + res->hostportlen = (size_t)(uri + offset + ipv6addr - res->host); + for (i = offset; i < len; ++i) { + if (uri[i] == '#') { + break; + } + } + if (i - offset == 0) { + res->path = "/"; + res->pathlen = 1; + } else { + res->path = &uri[offset]; + res->pathlen = i - offset; + } + return 0; +} diff --git a/src/ext/parse_uri.h b/src/ext/parse_uri.h new file mode 100644 index 0000000..bb69e79 --- /dev/null +++ b/src/ext/parse_uri.h @@ -0,0 +1,41 @@ +// From: https://github.com/nghttp2/nghttp2/blob/master/examples/client.c +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2013 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +struct URI { + const char* host; + /* In this program, path contains query component as well. */ + const char* path; + size_t pathlen; + const char* hostport; + size_t hostlen; + size_t hostportlen; + uint16_t port; +}; + +int parse_uri(struct URI* res, const char* uri); diff --git a/src/list.h b/src/list.h index d52ad04..47064fb 100644 --- a/src/list.h +++ b/src/list.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/log.c b/src/log.c index e807dcc..661e373 100644 --- a/src/log.c +++ b/src/log.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/log.h b/src/log.h index e922ca1..040a29a 100644 --- a/src/log.h +++ b/src/log.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/net.c b/src/net.c index ca3750f..89e75e0 100644 --- a/src/net.c +++ b/src/net.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/net.h b/src/net.h index 89af773..1624be6 100644 --- a/src/net.h +++ b/src/net.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/net_doh.c b/src/net_doh.c index f483e0d..dafd736 100644 --- a/src/net_doh.c +++ b/src/net_doh.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. @@ -28,7 +28,7 @@ #include "net.h" #include "edns.h" -#include "parse_uri.h" +#include "ext/parse_uri.h" #include "log.h" #include "strerror.h" #include "util.h" @@ -324,6 +324,8 @@ static ssize_t perf__doh_recv(struct perf_net_socket* sock, void* buf, size_t le return -1; case SSL_ERROR_SYSCALL: switch (errno) { + case EBADF: + // treat this as a retry, can happen if sendto is reconnecting case ECONNREFUSED: case ECONNRESET: case ENOTCONN: diff --git a/src/net_dot.c b/src/net_dot.c index 9fd718d..7e58a73 100644 --- a/src/net_dot.c +++ b/src/net_dot.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. @@ -177,6 +177,8 @@ static ssize_t perf__dot_recv(struct perf_net_socket* sock, void* buf, size_t le break; case SSL_ERROR_SYSCALL: switch (errno) { + case EBADF: + // treat this as a retry, can happen if sendto is reconnecting case ECONNREFUSED: case ECONNRESET: case ENOTCONN: diff --git a/src/net_tcp.c b/src/net_tcp.c index 61676fc..026dcce 100644 --- a/src/net_tcp.c +++ b/src/net_tcp.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. @@ -171,6 +171,8 @@ static ssize_t perf__tcp_recv(struct perf_net_socket* sock, void* buf, size_t le return 0; } else if (n < 0) { switch (errno) { + case EBADF: + // treat this as a retry, can happen if sendto is reconnecting case ECONNREFUSED: case ECONNRESET: case ENOTCONN: diff --git a/src/net_udp.c b/src/net_udp.c index 5ca100f..2efc384 100644 --- a/src/net_udp.c +++ b/src/net_udp.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/opt.c b/src/opt.c index d65a0f8..7a0f346 100644 --- a/src/opt.c +++ b/src/opt.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. @@ -238,39 +238,57 @@ static int perf_opt_long_parse(char* optarg) ssize_t optlen; char* arg; - // TODO: Allow boolean not to have =/value - if (!(arg = strchr(optarg, '='))) { - return -1; - } - optlen = arg - optarg; - if (optlen < 1) { - return -1; + if ((arg = strchr(optarg, '='))) { + arg++; + optlen = arg - optarg; + if (optlen < 1) { + return -1; + } + } else { + optlen = strlen(optarg); } - arg++; long_opt_t* opt = longopts; while (opt) { if (!strncmp(optarg, opt->name, optlen)) { switch (opt->type) { case perf_opt_string: + if (!arg) { + return -1; + } *opt->u.stringp = arg; break; case perf_opt_boolean: *opt->u.boolp = true; break; case perf_opt_uint: + if (!arg) { + return -1; + } *opt->u.uintp = parse_uint(opt->desc, arg, 1, 0xFFFFFFFF); break; case perf_opt_zpint: + if (!arg) { + return -1; + } *opt->u.uintp = parse_uint(opt->desc, arg, 0, 0xFFFFFFFF); break; case perf_opt_timeval: + if (!arg) { + return -1; + } *opt->u.uint64p = parse_timeval(opt->desc, arg); break; case perf_opt_double: + if (!arg) { + return -1; + } *opt->u.doublep = parse_double(opt->desc, arg); break; case perf_opt_port: + if (!arg) { + return -1; + } *opt->u.portp = parse_uint(opt->desc, arg, 0, 0xFFFF); break; } @@ -284,10 +302,10 @@ static int perf_opt_long_parse(char* optarg) void perf_long_opt_usage(void) { - fprintf(stderr, "Usage: %s ... -O = ...\n\nAvailable long options:\n", progname); + fprintf(stderr, "Usage: %s ... -O [=] ...\n\nAvailable long options:\n", progname); long_opt_t* opt = longopts; while (opt) { - fprintf(stderr, " %s: %s", opt->name, opt->help); + fprintf(stderr, " %s%s: %s", opt->name, opt->type != perf_opt_boolean ? "=" : "", opt->help); if (opt->defval) { fprintf(stderr, " (default: %s)", opt->defval); } diff --git a/src/opt.h b/src/opt.h index e30ea8c..82a15a2 100644 --- a/src/opt.h +++ b/src/opt.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/os.c b/src/os.c index 24304bc..a36cbed 100644 --- a/src/os.c +++ b/src/os.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/os.h b/src/os.h index b21e6ed..0d9e8c5 100644 --- a/src/os.h +++ b/src/os.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/parse_uri.c b/src/parse_uri.c deleted file mode 100644 index fa74c85..0000000 --- a/src/parse_uri.c +++ /dev/null @@ -1,112 +0,0 @@ -#include "parse_uri.h" - -#include - -// From: https://github.com/nghttp2/nghttp2/blob/master/examples/client.c -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -int parse_uri(struct URI* res, const char* uri) -{ - /* We only interested in https */ - size_t len, i, offset; - int ipv6addr = 0; - memset(res, 0, sizeof(struct URI)); - len = strlen(uri); - if (len < 9 || memcmp("https://", uri, 8) != 0) { - return -1; - } - offset = 8; - res->host = res->hostport = &uri[offset]; - res->hostlen = 0; - if (uri[offset] == '[') { - /* IPv6 literal address */ - ++offset; - ++res->host; - ipv6addr = 1; - for (i = offset; i < len; ++i) { - if (uri[i] == ']') { - res->hostlen = i - offset; - offset = i + 1; - break; - } - } - } else { - const char delims[] = ":/?#"; - for (i = offset; i < len; ++i) { - if (strchr(delims, uri[i]) != NULL) { - break; - } - } - res->hostlen = i - offset; - offset = i; - } - if (res->hostlen == 0) { - return -1; - } - /* Assuming https */ - res->port = 443; - if (offset < len) { - if (uri[offset] == ':') { - /* port */ - const char delims[] = "/?#"; - int port = 0; - ++offset; - for (i = offset; i < len; ++i) { - if (strchr(delims, uri[i]) != NULL) { - break; - } - if ('0' <= uri[i] && uri[i] <= '9') { - port *= 10; - port += uri[i] - '0'; - if (port > 65535) { - return -1; - } - } else { - return -1; - } - } - if (port == 0) { - return -1; - } - offset = i; - res->port = (uint16_t)port; - } - } - res->hostportlen = (size_t)(uri + offset + ipv6addr - res->host); - for (i = offset; i < len; ++i) { - if (uri[i] == '#') { - break; - } - } - if (i - offset == 0) { - res->path = "/"; - res->pathlen = 1; - } else { - res->path = &uri[offset]; - res->pathlen = i - offset; - } - return 0; -} diff --git a/src/parse_uri.h b/src/parse_uri.h deleted file mode 100644 index bb69e79..0000000 --- a/src/parse_uri.h +++ /dev/null @@ -1,41 +0,0 @@ -// From: https://github.com/nghttp2/nghttp2/blob/master/examples/client.c -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -struct URI { - const char* host; - /* In this program, path contains query component as well. */ - const char* path; - size_t pathlen; - const char* hostport; - size_t hostlen; - size_t hostportlen; - uint16_t port; -}; - -int parse_uri(struct URI* res, const char* uri); diff --git a/src/qtype.c b/src/qtype.c index c41348f..bce24f3 100644 --- a/src/qtype.c +++ b/src/qtype.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/qtype.h b/src/qtype.h index 87e157c..d136870 100644 --- a/src/qtype.h +++ b/src/qtype.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/resperf-report b/src/resperf-report index 2d154bc..7c1431d 100755 --- a/src/resperf-report +++ b/src/resperf-report @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright 2019-2022 OARC, Inc. +# Copyright 2019-2023 OARC, Inc. # Copyright 2017-2018 Akamai Technologies # Copyright 2006-2016 Nominum, Inc. # All rights reserved. diff --git a/src/resperf.1.in b/src/resperf.1.in index 28f9bbb..1c31b35 100644 --- a/src/resperf.1.in +++ b/src/resperf.1.in @@ -1,4 +1,4 @@ -.\" Copyright 2019-2022 OARC, Inc. +.\" Copyright 2019-2023 OARC, Inc. .\" Copyright 2017-2018 Akamai Technologies .\" Copyright 2006-2016 Nominum, Inc. .\" All rights reserved. diff --git a/src/resperf.c b/src/resperf.c index aa58dc0..ae4f9cd 100644 --- a/src/resperf.c +++ b/src/resperf.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/result.h b/src/result.h index 7670a91..b50716b 100644 --- a/src/result.h +++ b/src/result.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/strerror.c b/src/strerror.c index 1a771f8..d870cb1 100644 --- a/src/strerror.c +++ b/src/strerror.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/strerror.h b/src/strerror.h index 915e06d..312b148 100644 --- a/src/strerror.h +++ b/src/strerror.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/test/test1.sh b/src/test/test1.sh index 945aab3..cd6af3c 100755 --- a/src/test/test1.sh +++ b/src/test/test1.sh @@ -2,3 +2,8 @@ ../dnsperf -h ../resperf -h + +! ../dnsperf -O suppress +! ../dnsperf -O suppress= +! ../resperf -O suppress +! ../resperf -O suppress= diff --git a/src/tsig.c b/src/tsig.c index ce10eea..b697141 100644 --- a/src/tsig.c +++ b/src/tsig.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/tsig.h b/src/tsig.h index 637b348..b69c2d1 100644 --- a/src/tsig.h +++ b/src/tsig.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. diff --git a/src/util.h b/src/util.h index c59e459..ae821b0 100644 --- a/src/util.h +++ b/src/util.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 OARC, Inc. + * Copyright 2019-2023 OARC, Inc. * Copyright 2017-2018 Akamai Technologies * Copyright 2006-2016 Nominum, Inc. * All rights reserved. -- cgit v1.2.3