diff options
Diffstat (limited to 'compat')
-rw-r--r-- | compat/Makefile.am | 22 | ||||
-rw-r--r-- | compat/Makefile.in | 617 | ||||
-rw-r--r-- | compat/Thread.c | 582 | ||||
-rw-r--r-- | compat/delay.c | 407 | ||||
-rw-r--r-- | compat/error.c | 210 | ||||
-rw-r--r-- | compat/gettcpinfo.c | 110 | ||||
-rw-r--r-- | compat/gettimeofday.c | 92 | ||||
-rw-r--r-- | compat/inet_ntop.c | 210 | ||||
-rw-r--r-- | compat/inet_pton.c | 209 | ||||
-rw-r--r-- | compat/signal.c | 204 | ||||
-rw-r--r-- | compat/snprintf.c | 101 | ||||
-rw-r--r-- | compat/string.c | 76 |
12 files changed, 2840 insertions, 0 deletions
diff --git a/compat/Makefile.am b/compat/Makefile.am new file mode 100644 index 0000000..75ac787 --- /dev/null +++ b/compat/Makefile.am @@ -0,0 +1,22 @@ +noinst_LIBRARIES = libcompat.a + +AM_CPPFLAGS = @STRIP_BEGIN@ \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/include \ + @STRIP_END@ + +AM_CXXFLAGS = -Wall +AM_CFLAGS = -Wall +AM_LDFLAGS = -lrt + +libcompat_a_SOURCES = \ + Thread.c \ + error.c \ + delay.c \ + gettimeofday.c \ + gettcpinfo.c \ + inet_ntop.c \ + inet_pton.c \ + signal.c \ + snprintf.c \ + string.c diff --git a/compat/Makefile.in b/compat/Makefile.in new file mode 100644 index 0000000..5d5bbcd --- /dev/null +++ b/compat/Makefile.in @@ -0,0 +1,617 @@ +# Makefile.in generated by automake 1.16.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = compat +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_create_stdint_h.m4 \ + $(top_srcdir)/m4/dast.m4 $(top_srcdir)/m4/ax_pthread.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libcompat_a_AR = $(AR) $(ARFLAGS) +libcompat_a_LIBADD = +am_libcompat_a_OBJECTS = Thread.$(OBJEXT) error.$(OBJEXT) \ + delay.$(OBJEXT) gettimeofday.$(OBJEXT) gettcpinfo.$(OBJEXT) \ + inet_ntop.$(OBJEXT) inet_pton.$(OBJEXT) signal.$(OBJEXT) \ + snprintf.$(OBJEXT) string.$(OBJEXT) +libcompat_a_OBJECTS = $(am_libcompat_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/Thread.Po ./$(DEPDIR)/delay.Po \ + ./$(DEPDIR)/error.Po ./$(DEPDIR)/gettcpinfo.Po \ + ./$(DEPDIR)/gettimeofday.Po ./$(DEPDIR)/inet_ntop.Po \ + ./$(DEPDIR)/inet_pton.Po ./$(DEPDIR)/signal.Po \ + ./$(DEPDIR)/snprintf.Po ./$(DEPDIR)/string.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libcompat_a_SOURCES) +DIST_SOURCES = $(libcompat_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +STRIP_BEGIN = @STRIP_BEGIN@ +STRIP_DUMMY = @STRIP_DUMMY@ +STRIP_END = @STRIP_END@ +VERSION = @VERSION@ +WEB100_CFLAGS = @WEB100_CFLAGS@ +WEB100_CONFIG = @WEB100_CONFIG@ +WEB100_LIBS = @WEB100_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +ax_pthread_config = @ax_pthread_config@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LIBRARIES = libcompat.a +AM_CPPFLAGS = @STRIP_BEGIN@ \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/include \ + @STRIP_END@ + +AM_CXXFLAGS = -Wall +AM_CFLAGS = -Wall +AM_LDFLAGS = -lrt +libcompat_a_SOURCES = \ + Thread.c \ + error.c \ + delay.c \ + gettimeofday.c \ + gettcpinfo.c \ + inet_ntop.c \ + inet_pton.c \ + signal.c \ + snprintf.c \ + string.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu compat/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu compat/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libcompat.a: $(libcompat_a_OBJECTS) $(libcompat_a_DEPENDENCIES) $(EXTRA_libcompat_a_DEPENDENCIES) + $(AM_V_at)-rm -f libcompat.a + $(AM_V_AR)$(libcompat_a_AR) libcompat.a $(libcompat_a_OBJECTS) $(libcompat_a_LIBADD) + $(AM_V_at)$(RANLIB) libcompat.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Thread.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delay.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gettcpinfo.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gettimeofday.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inet_ntop.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inet_pton.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snprintf.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +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) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/Thread.Po + -rm -f ./$(DEPDIR)/delay.Po + -rm -f ./$(DEPDIR)/error.Po + -rm -f ./$(DEPDIR)/gettcpinfo.Po + -rm -f ./$(DEPDIR)/gettimeofday.Po + -rm -f ./$(DEPDIR)/inet_ntop.Po + -rm -f ./$(DEPDIR)/inet_pton.Po + -rm -f ./$(DEPDIR)/signal.Po + -rm -f ./$(DEPDIR)/snprintf.Po + -rm -f ./$(DEPDIR)/string.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/Thread.Po + -rm -f ./$(DEPDIR)/delay.Po + -rm -f ./$(DEPDIR)/error.Po + -rm -f ./$(DEPDIR)/gettcpinfo.Po + -rm -f ./$(DEPDIR)/gettimeofday.Po + -rm -f ./$(DEPDIR)/inet_ntop.Po + -rm -f ./$(DEPDIR)/inet_pton.Po + -rm -f ./$(DEPDIR)/signal.Po + -rm -f ./$(DEPDIR)/snprintf.Po + -rm -f ./$(DEPDIR)/string.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-noinstLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/compat/Thread.c b/compat/Thread.c new file mode 100644 index 0000000..307535e --- /dev/null +++ b/compat/Thread.c @@ -0,0 +1,582 @@ +/*--------------------------------------------------------------- + * Copyright (c) 1999,2000,2001,2002,2003 + * The Board of Trustees of the University of Illinois + * All Rights Reserved. + *--------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software (Iperf) 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: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the names of the University of Illinois, NCSA, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * 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 CONTIBUTORS 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. + * ________________________________________________________________ + * National Laboratory for Applied Network Research + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * http://www.ncsa.uiuc.edu + * ________________________________________________________________ + * + * Thread.c + * by Kevin Gibbs <kgibbs@nlanr.net> + * + * Based on: + * Thread.cpp + * by Mark Gates <mgates@nlanr.net> + * ------------------------------------------------------------------- + * The thread subsystem is responsible for all thread functions. It + * provides a thread implementation agnostic interface to Iperf. If + * threads are not available (HAVE_THREAD is undefined), thread_start + * does not start a new thread but just launches the specified object + * in the current thread. Everything that defines a thread of + * execution in Iperf is contained in an thread_Settings structure. To + * start a thread simply pass one such structure into thread_start. + * ------------------------------------------------------------------- + * headers + * uses + * <stdlib.h> + * <stdio.h> + * <assert.h> + * <errno.h> + * Thread.h may include <pthread.h> + * ------------------------------------------------------------------- */ + +#include "headers.h" + +#include "Thread.h" +#include "Locale.h" +#include "util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if HAVE_THREAD_DEBUG +#include <time.h> +#include <unistd.h> +#if HAVE_GETTID_SYSCALL +#include <sys/syscall.h> +#endif +#include <sys/types.h> +#include <stdarg.h> +#include "Reporter.h" +void reporttype_text(struct ReportHeader *reporthdr, char *rs) { + switch (reporthdr->type) { + case DATA_REPORT: + strncpy(rs,"data", REPORTTXTMAX); + break; + case SUM_REPORT: + strncpy(rs,"sum", REPORTTXTMAX); + break; + case SETTINGS_REPORT: + strncpy(rs,"settings", REPORTTXTMAX); + break; + case CONNECTION_REPORT: + strncpy(rs,"connection", REPORTTXTMAX); + break; + case SERVER_RELAY_REPORT: + strncpy(rs,"server", REPORTTXTMAX); + break; + default : + strncpy(rs,"unknown", REPORTTXTMAX); + } + rs[REPORTTXTMAX-1] = '\0'; +} + +Mutex thread_debug_mutex; +static void __gettimestamp(char *timestr) { + struct timespec t1; + clock_gettime(CLOCK_REALTIME, &t1); + struct tm *t; + t=localtime(&t1.tv_sec); + if (t) { +#if WIN32 + strftime(timestr, 200, "%Y-%m-%d %H:%M:%S", t); +#else + strftime(timestr, 200, "%T", t); +#endif + // strftime(buf, len, "%F %T", &t); + snprintf(×tr[strlen(timestr)], strlen(timestr), ".%09ld", t1.tv_nsec); + timestr[199]='\0'; + } else { + *timestr='\0'; + } +} +static int __log(const char *level, const char *format, va_list args) { + int len; + char *newformat; + char timestamp[200]; + char logformat[]="%s(%ld):[%s] %s\n"; + + __gettimestamp(timestamp); + #if HAVE_GETTID_SYSCALL + unsigned long tid = syscall(SYS_gettid); + #else + unsigned long tid = -1; + #endif + len = snprintf(NULL, 0, logformat, level, tid, timestamp, format); + len++; // Trailing null byte + extra + newformat = malloc(len); + len = snprintf(newformat, len, logformat, level, tid, timestamp, format); + if (len > 0) { + len = vprintf(newformat, args); + } + free(newformat); + return len; +} + +void thread_debug(const char *format, ...) { + Mutex_Lock(&thread_debug_mutex); + va_list ap; + va_start(ap, format); + __log("THREAD", format, ap); + va_end(ap); + fflush(stdout); + Mutex_Unlock(&thread_debug_mutex); +} +#endif + +/* ------------------------------------------------------------------- + * define static variables. + * ------------------------------------------------------------------- */ + +// number of currently running threads +int thread_sNum = 0; +// number of currently running traffic threads +int thread_trfc_sNum = 0; +int thread_trfctx_sNum = 0; +int thread_trfcrx_sNum = 0; +// number of non-terminating running threads (ie listener thread) +int nonterminating_num = 0; +// condition to protect updating the above and alerting on +// changes to above +struct Condition thread_sNum_cond; + + +/* ------------------------------------------------------------------- + * Initialize the thread subsystems variables and set the concurrency + * level in solaris. + * ------------------------------------------------------------------- */ +void thread_init() { + Condition_Initialize(&thread_sNum_cond); +#if defined(sun) + /* Solaris apparently doesn't default to timeslicing threads, + * as such we force it to play nice. This may not work perfectly + * when _sending_ multiple _UDP_ streams. + */ + pthread_setconcurrency (3); +#endif +} + +/* ------------------------------------------------------------------- + * Destroy the thread subsystems variables. + * ------------------------------------------------------------------- */ +void thread_destroy() { + Condition_Destroy(&thread_sNum_cond); +} + +/* ------------------------------------------------------------------- + * Start the specified object's thread execution. Increments thread + * count, spawns new thread, and stores thread ID. + * ------------------------------------------------------------------- */ +void thread_start_all(struct thread_Settings* thread) { + struct thread_Settings *ithread = thread; + while(ithread) { + thread_start(ithread); + ithread = ithread->runNow; + } +} + +void thread_start(struct thread_Settings* thread) { + // Make sure this object has not been started already + if (!thread_equalid(thread->mTID, thread_zeroid())) { + WARN(1, "thread_start called on running thread"); +#if HAVE_THREAD_DEBUG + thread_debug("Thread_start info %p id=%d ", (void *)thread, (int)thread->mTID); +#endif + } else { + // increment thread count + Condition_Lock(thread_sNum_cond); + thread_sNum++; + if ((thread->mThreadMode == kMode_Client) || (thread->mThreadMode == kMode_Server)) { + thread_trfc_sNum++; + } + Condition_Unlock(thread_sNum_cond); + +#if defined(HAVE_POSIX_THREAD) + // pthreads -- spawn new thread + if (pthread_create(&thread->mTID, NULL, thread_run_wrapper, thread) != 0) { + WARN(1, "pthread_create"); + + // decrement thread count + Condition_Lock(thread_sNum_cond); + thread_sNum--; + if (thread->mThreadMode == kMode_Client) { + thread_trfc_sNum--; + thread_trfctx_sNum--; + } + if (thread->mThreadMode == kMode_Server) { + thread_trfc_sNum--; + thread_trfcrx_sNum--; + } + Condition_Unlock(thread_sNum_cond); + } +#if HAVE_THREAD_DEBUG + thread_debug("Thread_run_wrapper(%p mode=%x) thread counts tot/trfc=%d/%d (id=%d)", (void *)thread, thread->mThreadMode, thread_sNum, thread_trfc_sNum, (int)thread->mTID); +#endif +#elif defined(HAVE_WIN32_THREAD) + // Win32 threads -- spawn new thread + // Win32 has a thread handle in addition to the thread ID + thread->mHandle = CreateThread(NULL, 0, thread_run_wrapper, thread, 0, &thread->mTID); + if (thread->mHandle == NULL) { + WARN(1, "CreateThread"); + + // decrement thread count + Condition_Lock(thread_sNum_cond); + thread_sNum--; + if ((thread->mThreadMode == kMode_Client) || (thread->mThreadMode == kMode_Server)) { + thread_trfc_sNum--; + } + Condition_Unlock(thread_sNum_cond); + } +#else + // single-threaded -- call Run_Wrapper in this thread + thread_run_wrapper(thread); +#endif + } +} // end thread_start + +/* ------------------------------------------------------------------- + * Stop the specified object's thread execution (if any) immediately. + * Decrements thread count and resets the thread ID. + * + * Note: This does not free any objects and calling it without + * lots of conideration will likely cause memory leaks. Better to let + * thread_start's thread_run_wrapper run to completion and not + * preemptively stop a thread. + * ------------------------------------------------------------------- */ +void thread_stop(struct thread_Settings* thread) { +#ifdef HAVE_THREAD + #ifdef HAVE_THREAD_DEBUG + thread_debug("Thread stop invoked %p (%d/%d)", (void *)thread, thread_sNum, thread_trfc_sNum); + #endif + // Make sure we have been started + if (!thread_equalid(thread->mTID, thread_zeroid())) { + + // decrement thread count + Condition_Lock(thread_sNum_cond); + thread_sNum--; + if ((thread->mThreadMode == kMode_Client) || (thread->mThreadMode == kMode_Server)) { + thread_trfc_sNum--; + } + Condition_Signal(&thread_sNum_cond); + Condition_Unlock(thread_sNum_cond); + + // use exit() if called from within this thread + // use cancel() if called from a different thread + if (thread_equalid(thread_getid(), thread->mTID)) { + + // Destroy the object + Settings_Destroy(thread); + + // Exit +#if defined(HAVE_POSIX_THREAD) + pthread_exit(NULL); +#else // Win32 + CloseHandle(thread->mHandle); + ExitThread(0); +#endif + } else { + + // Cancel +#if defined(HAVE_POSIX_THREAD) + // Cray J90 doesn't have pthread_cancel; Iperf works okay without +#ifdef HAVE_PTHREAD_CANCEL + pthread_cancel(thread->mTID); +#endif +#else // Win32 + // this is a somewhat dangerous function; it's not + // suggested to Stop() threads a lot. + TerminateThread(thread->mHandle, 0); +#endif + + // Destroy the object only after killing the thread + Settings_Destroy(thread); + } + } +#endif +} // end Stop + +/* ------------------------------------------------------------------- + * This function is the entry point for new threads created in + * thread_start. + * ------------------------------------------------------------------- */ +#if defined(HAVE_WIN32_THREAD) +DWORD WINAPI +#else +void* +#endif +thread_run_wrapper(void* paramPtr) { + bool signal_on_exit = false; + struct thread_Settings* thread = (struct thread_Settings*) paramPtr; + + // which type of object are we + switch (thread->mThreadMode) { + case kMode_Server: + { + signal_on_exit = true; + /* Spawn a Server thread with these settings */ + server_spawn(thread); + } break; + case kMode_Client: + { + signal_on_exit = true; + /* Spawn a Client thread with these settings */ + client_spawn(thread); + } break; + case kMode_Reporter: + case kMode_ReporterClient: + { + /* Spawn a Reporter thread with these settings */ + reporter_spawn(thread); + } break; + case kMode_Listener: + { + // Increment the non-terminating thread count + thread_register_nonterm(); + /* Spawn a Listener thread with these settings */ + listener_spawn(thread); + // Decrement the non-terminating thread count + thread_unregister_nonterm(); + } break; + default: + { + FAIL(1, "Unknown Thread Type!\n", thread); + } break; + } + +#ifdef HAVE_POSIX_THREAD + // detach Thread. If someone already joined it will not do anything + // If none has then it will free resources upon return from this + // function (Run_Wrapper) + pthread_detach(thread->mTID); +#endif + + // decrement thread count and send condition signal + Condition_Lock(thread_sNum_cond); + thread_sNum--; + if ((thread->mThreadMode == kMode_Client) || (thread->mThreadMode == kMode_Server)) { + thread_trfc_sNum--; + } + Condition_Signal(&thread_sNum_cond); + Condition_Unlock(thread_sNum_cond); + + // Check if we need to start up a thread after executing this one + if (thread->runNext != NULL) { + thread_start(thread->runNext); + } + // Destroy this thread object + Settings_Destroy(thread); + // signal the reporter thread now that thread state has changed + if (signal_on_exit) { + Condition_Signal(&ReportCond); +#if HAVE_THREAD_DEBUG + thread_debug("Signal sent to reporter thread"); +#endif + } + return 0; +} // end run_wrapper + +/* ------------------------------------------------------------------- + * Wait for all thread object's execution to complete. Depends on the + * thread count being accurate and the threads sending a condition + * signal when they terminate. + * ------------------------------------------------------------------- */ +void thread_joinall(void) { + Condition_Lock(thread_sNum_cond); + while (thread_sNum > 0) { + Condition_Wait(&thread_sNum_cond); + } + Condition_Unlock(thread_sNum_cond); +} // end Joinall + + +/* ------------------------------------------------------------------- + * Compare the thread ID's (inLeft == inRight); return true if they + * are equal. On some OS's nthread_t is a struct so == will not work. + * TODO use pthread_equal. Any Win32 equivalent?? + * ------------------------------------------------------------------- */ +int thread_equalid(nthread_t inLeft, nthread_t inRight) { + return(memcmp(&inLeft, &inRight, sizeof(inLeft)) == 0); +} + +/* ------------------------------------------------------------------- + * Return a zero'd out thread ID. On some OS's nthread_t is a struct + * so == 0 will not work. + * [static] + * ------------------------------------------------------------------- */ +nthread_t thread_zeroid(void) { + nthread_t a; + memset(&a, 0, sizeof(a)); + return a; +} + +/* ------------------------------------------------------------------- + * set a thread to be ignorable, so joinall won't wait on it + * this simply decrements the thread count that joinall uses. + * This is utilized by the reporter thread which knows when it + * is ok to quit (aka no pending reports). + * ------------------------------------------------------------------- */ +void thread_setignore() { + Condition_Lock(thread_sNum_cond); + thread_sNum--; + Condition_Signal(&thread_sNum_cond); + Condition_Unlock(thread_sNum_cond); +} + +/* ------------------------------------------------------------------- + * unset a thread from being ignorable, so joinall will wait on it + * this simply increments the thread count that joinall uses. + * This is utilized by the reporter thread which knows when it + * is ok to quit (aka no pending reports). + * ------------------------------------------------------------------- */ +void thread_unsetignore(void) { + Condition_Lock(thread_sNum_cond); + thread_sNum++; + Condition_Signal(&thread_sNum_cond); + Condition_Unlock(thread_sNum_cond); +} + +/* ------------------------------------------------------------------- + * set a thread to be non-terminating, so if you cancel through + * Ctrl-C they can be ignored by the joinall. + * ------------------------------------------------------------------- */ +void thread_register_nonterm(void) { + Condition_Lock(thread_sNum_cond); + nonterminating_num++; + Condition_Unlock(thread_sNum_cond); +} + +/* ------------------------------------------------------------------- + * unset a thread from being non-terminating, so if you cancel through + * Ctrl-C they can be ignored by the joinall. + * ------------------------------------------------------------------- */ +void thread_unregister_nonterm(void) { + Condition_Lock(thread_sNum_cond); + if (nonterminating_num == 0) { + // nonterminating has been released with release_nonterm + // Add back to the threads to wait on + thread_sNum++; + } else { + nonterminating_num--; + } + Condition_Unlock(thread_sNum_cond); +} + +/* ------------------------------------------------------------------- + * this function releases all non-terminating threads from the list + * of active threads, so that when all terminating threads quit + * the joinall will complete. This is called on a Ctrl-C input. It is + * also used by the -P usage on the server side + * ------------------------------------------------------------------- */ +int thread_release_nonterm(int interrupt) { + Condition_Lock(thread_sNum_cond); + thread_sNum -= nonterminating_num; + if (thread_sNum > 1 && nonterminating_num > 0 && interrupt != 0) { + fprintf(stderr, "%s", wait_server_threads); + } + nonterminating_num = 0; + Condition_Signal(&thread_sNum_cond); + Condition_Unlock(thread_sNum_cond); + return thread_sNum; +} + +/* ------------------------------------------------------------------- + * Return the number of threads currently running (doesn't include + * active threads that have called setdaemon (aka reporter thread)) + * ------------------------------------------------------------------- */ +int thread_numuserthreads(void) { + return thread_sNum; +} + +/* ------------------------------------------------------------------- + * Return the number of taffic threads currently running + * ------------------------------------------------------------------- */ +int thread_numtrafficthreads(void) { + return thread_trfc_sNum; +} + +/* ------------------------------------------------------------------- + * Support for realtime scheduling of threads + * ------------------------------------------------------------------- */ +#if HAVE_SCHED_SETSCHEDULER +#include <sched.h> +#endif +#ifdef HAVE_MLOCKALL +#include <sys/mman.h> +#endif +void thread_setscheduler(struct thread_Settings *thread) { +#if HAVE_SCHED_SETSCHEDULER + if (isRealtime(thread)) { + struct sched_param sp; + sp.sched_priority = sched_get_priority_max(SCHED_RR); + // SCHED_OTHER, SCHED_FIFO, SCHED_RR + if (sched_setscheduler(0, SCHED_RR, &sp) < 0) { + perror("Client set scheduler"); +#ifdef HAVE_MLOCKALL + } else if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) { + // lock the threads memory + perror ("mlockall"); +#endif // MLOCK + } + } +#endif // SCHED +} + +/* + * ------------------------------------------------------------------- + * Allow another thread to execute. If no other threads are runable this + * is not guarenteed to actually rest. + * ------------------------------------------------------------------- */ +void thread_rest (void) { +#if defined(HAVE_THREAD) +#if defined(HAVE_POSIX_THREAD) + #if HAVE_SCHED_YIELD + sched_yield(); + #endif +#else // Win32 + SwitchToThread(); +#endif +#endif +} + +#ifdef __cplusplus +} /* end extern "C" */ +#endif diff --git a/compat/delay.c b/compat/delay.c new file mode 100644 index 0000000..95bde3e --- /dev/null +++ b/compat/delay.c @@ -0,0 +1,407 @@ +/*--------------------------------------------------------------- + * Copyright (c) 1999,2000,2001,2002,2003 + * The Board of Trustees of the University of Illinois + * All Rights Reserved. + *--------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software (Iperf) 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: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the names of the University of Illinois, NCSA, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * 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 CONTIBUTORS 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. + * ________________________________________________________________ + * National Laboratory for Applied Network Research + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * http://www.ncsa.uiuc.edu + * ________________________________________________________________ + * + * delay.c + * by Mark Gates <mgates@nlanr.net> + * updates + * by Robert J. McMahon <rmcmahon@broadcom.com> <rjmcmahon@rjmcmahon.com> + * ------------------------------------------------------------------- + * attempts at accurate microsecond delays + * ------------------------------------------------------------------- */ +#include "headers.h" +#include "util.h" +#include "delay.h" +#include "Thread.h" +#include <math.h> + +#define MILLION 1000000 +#define BILLION 1000000000 + +/* ------------------------------------------------------------------- + * A micro-second delay function + * o Use a busy loop or nanosleep + * + * Some notes: + * o clock nanosleep with a relative is preferred (see man page for why) + * o clock_gettime() (if available) is preferred over gettimeofday() + * as it give nanosecond resolution and should be more efficient. + * It also supports CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW + * though CLOCK_REALTIME is being used by the code. + * o This code does not use Timestamp object, as the goal of these + * functions is accurate delays (vs accurate timestamps.) + * o The syscalls such as nanosleep guarantee at least the request time + * and can and will delay longer, particularly due to things like context + * switching, causing the delay to lose accuracy + * o Kalman filtering is used to predict delay error which in turn + * is used to adjust the delay, hopefully mitigating the above. + * Note: This can cause the delay to return faster than the request, + * i.e. the *at least* guarantee is not preserved for the kalman + * adjusted delay calls. + * o Remember, the Client is keeping a running average delay for the + * thread so errors in delay will also be adjusted there. (Assuming + * it's possible. It's not really possible at top line link rates + * because lost time can't be made up for by speeding up the transmits. + * Hence, don't lose time with delay calls which error on the side of + * taking too long. Kalman should help much here.) + * + * POSIX nanosleep(). This allows a higher timing resolution + * (under Linux e.g. it uses hrtimers), does not affect any signals, + * and will use up remaining time when interrupted. + * ------------------------------------------------------------------- */ + +void delay_loop(unsigned long usec) +{ +#ifdef HAVE_CLOCK_NANOSLEEP + { + struct timespec res; + res.tv_sec = usec/MILLION; + res.tv_nsec = (usec * 1000) % BILLION; + #ifndef WIN32 + clock_nanosleep(CLOCK_MONOTONIC, 0, &res, NULL); + #else + clock_nanosleep(0, 0, &res, NULL); + #endif + } +#else + #ifdef HAVE_KALMAN + delay_kalman(usec); + #else + #ifdef HAVE_NANOSLEEP + delay_nanosleep(usec); + #else + delay_busyloop(usec); + #endif + #endif +#endif +} + +int clock_usleep (struct timeval *request) { + int rc = 0; +#if HAVE_THREAD_DEBUG + thread_debug("Thread called clock_usleep() until %ld.%ld", request->tv_sec, request->tv_usec); +#endif +#ifdef HAVE_CLOCK_NANOSLEEP + struct timespec tmp; + tmp.tv_sec = request->tv_sec; + tmp.tv_nsec = request->tv_usec * 1000; + +// Cygwin systems have an issue with CLOCK_MONOTONIC +#if defined(CLOCK_MONOTONIC) && !defined(WIN32) + rc = clock_nanosleep(CLOCK_MONOTONIC, 0, &tmp, NULL); +#else + rc = clock_nanosleep(0, 0, &tmp, NULL); +#endif + if (rc) { + fprintf(stderr, "failed clock_nanosleep()=%d\n", rc); + } +#else + struct timeval now; + struct timeval next = *request; +#ifdef HAVE_CLOCK_GETTIME + struct timespec t1; + clock_gettime(CLOCK_REALTIME, &t1); + now.tv_sec = t1.tv_sec; + now.tv_usec = t1.tv_nsec / 1000; +#else + gettimeofday(&now, NULL); +#endif + double delta_usecs; + if ((delta_usecs = TimeDifference(next, now)) > 0.0) { + delay_loop(delta_usecs); + } +#endif + return rc; +} + +int clock_usleep_abstime (struct timeval *request) { + int rc = 0; +#if defined(HAVE_CLOCK_NANOSLEEP) && defined(TIMER_ABSTIME) && !defined(WIN32) + struct timespec tmp; + tmp.tv_sec = request->tv_sec; + tmp.tv_nsec = request->tv_usec * 1000; + rc = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tmp, NULL); + if (rc) { + fprintf(stderr, "failed clock_nanosleep()=%d\n", rc); + } +#else + struct timeval now; + struct timeval next = *request; +#ifdef HAVE_CLOCK_GETTIME + struct timespec t1; + clock_gettime(CLOCK_REALTIME, &t1); + now.tv_sec = t1.tv_sec; + now.tv_usec = t1.tv_nsec / 1000; +#else + gettimeofday(&now, NULL); +#endif + double delta_usecs; + if ((delta_usecs = (1e6 * TimeDifference(next, now))) > 0.0) { + delay_loop(delta_usecs); + } +#endif + return rc; +} + +#ifdef HAVE_NANOSLEEP +// Can use the nanosleep syscall suspending the thread +void delay_nanosleep (unsigned long usec) { + struct timespec requested, remaining; + requested.tv_sec = 0; + requested.tv_nsec = usec * 1000L; + // Note, signals will cause the nanosleep + // to return early. That's fine. + nanosleep(&requested, &remaining); +} +#endif + +#if defined (HAVE_NANOSLEEP) || defined (HAVE_CLOCK_GETTIME) +static void timespec_add_ulong (struct timespec *tv0, unsigned long value) { + tv0->tv_sec += (value / BILLION); + tv0->tv_nsec += (value % BILLION); + if (tv0->tv_nsec >= BILLION) { + tv0->tv_sec++; + tv0->tv_nsec -= BILLION; + } +} +#endif + +#ifdef HAVE_KALMAN +// Kalman versions attempt to support delay request +// accuracy over a minimum guaranteed delay by +// prediciting the delay error. This is +// the basic recursive algorithm. +static void kalman_update (struct kalman_state *state, double measurement) { + //prediction update + state->p = state->p + state->q; + //measurement update + state->k = state->p / (state->p + state->r); + state->x = state->x + (state->k * (measurement - state->x)); + state->p = (1 - state->k) * state->p; +} +#endif + +#ifdef HAVE_CLOCK_GETTIME +// Delay calls for systems with clock_gettime +// Working units are nanoseconds and structures are timespec +static void timespec_add_double (struct timespec *tv0, double value) { + tv0->tv_nsec += (unsigned long) value; + if (tv0->tv_nsec >= BILLION) { + tv0->tv_sec++; + tv0->tv_nsec -= BILLION; + } +} +// tv1 assumed greater than tv0 +static double timespec_diff (struct timespec tv1, struct timespec tv0) { + double result; + if (tv1.tv_nsec < tv0.tv_nsec) { + tv1.tv_nsec += BILLION; + tv1.tv_sec--; + } + result = (double) (((tv1.tv_sec - tv0.tv_sec) * BILLION) + (tv1.tv_nsec - tv0.tv_nsec)); + return result; +} +static void timespec_add( struct timespec *tv0, struct timespec *tv1) +{ + tv0->tv_sec += tv1->tv_sec; + tv0->tv_nsec += tv1->tv_nsec; + if ( tv0->tv_nsec >= BILLION ) { + tv0->tv_nsec -= BILLION; + tv0->tv_sec++; + } +} +static inline +int timespec_greaterthan(struct timespec tv1, struct timespec tv0) { + if (tv1.tv_sec > tv0.tv_sec || \ + ((tv0.tv_sec == tv1.tv_sec) && (tv1.tv_nsec > tv0.tv_nsec))) { + return 1; + } else { + return 0; + } +} +// A cpu busy loop for systems with clock_gettime +void delay_busyloop (unsigned long usec) { + struct timespec t1, t2; + clock_gettime(CLOCK_REALTIME, &t1); + timespec_add_ulong(&t1, (usec * 1000L)); + while (1) { + clock_gettime(CLOCK_REALTIME, &t2); + if (timespec_greaterthan(t2, t1)) + break; + } +} +// Kalman routines for systems with clock_gettime +#ifdef HAVE_KALMAN +// Request units is microseconds +// Adjust units is nanoseconds +void delay_kalman (unsigned long usec) { + struct timespec t1, t2, finishtime, requested={0,0}, remaining; + double nsec_adjusted, err; + static struct kalman_state kalmanerr={ + 0.00001, //q process noise covariance + 0.1, //r measurement noise covariance + 0.0, //x value, error predictio (units nanoseconds) + 1, //p estimation error covariance + 0.75 //k kalman gain + }; + // Get the current clock + clock_gettime(CLOCK_REALTIME, &t1); + // Perform the kalman adjust per the predicted delay error + nsec_adjusted = (usec * 1000.0) - kalmanerr.x; + // Set a timespec to be used by the nanosleep + // as well as for the finished time calculation + timespec_add_double(&requested, nsec_adjusted); + // Set the finish time in timespec format + finishtime = t1; + timespec_add(&finishtime, &requested); +# ifdef HAVE_NANOSLEEP + // Don't call nanosleep for values less than 10 microseconds + // as the syscall is too expensive. Let the busy loop + // provide the delay for times under that. + if (nsec_adjusted > 10000) { + nanosleep(&requested, &remaining); + } +# endif + while (1) { + clock_gettime(CLOCK_REALTIME, &t2); + if (timespec_greaterthan(t2, finishtime)) + break; + } + // Compute the delay error in units of nanoseconds + // and cast to type double + err = (timespec_diff(t2, t1) - (usec * 1000)); + // printf("req: %ld adj: %f err: %.5f (ns)\n", usec, nsec_adjusted, kalmanerr.x); + kalman_update(&kalmanerr, err); +} +#endif // HAVE_KALMAN +#else +// Sadly, these systems must use the not so efficient gettimeofday() +// and working units are microseconds, struct is timeval +static void timeval_add_ulong (struct timeval *tv0, unsigned long value) { + tv0->tv_usec += value; + if (tv0->tv_usec >= MILLION) { + tv0->tv_sec++; + tv0->tv_usec -= MILLION; + } +} +static inline +int timeval_greaterthan(struct timeval tv1, struct timeval tv0) { + if (tv1.tv_sec > tv0.tv_sec || \ + ((tv0.tv_sec == tv1.tv_sec) && (tv1.tv_usec > tv0.tv_usec))) { + return 1; + } else { + return 0; + } +} +// tv1 assumed greater than tv0 +static double timeval_diff (struct timeval tv1, struct timeval tv0) { + double result; + if (tv1.tv_usec < tv0.tv_usec) { + tv1.tv_usec += MILLION; + tv1.tv_sec--; + } + result = (double) (((tv1.tv_sec - tv0.tv_sec) * MILLION) + (tv1.tv_usec - tv0.tv_usec)); + return result; +} +void delay_busyloop (unsigned long usec) { + struct timeval t1, t2; + gettimeofday( &t1, NULL ); + timeval_add_ulong(&t1, usec); + while (1) { + gettimeofday( &t2, NULL ); + if (timeval_greaterthan(t2, t1)) + break; + } +} +#ifdef HAVE_KALMAN +// Request units is microseconds +// Adjust units is microseconds +void delay_kalman (unsigned long usec) { + struct timeval t1, t2, finishtime; + long usec_adjusted; + double err; + static struct kalman_state kalmanerr={ + 0.00001, //q process noise covariance + 0.1, //r measurement noise covariance + 0.0, //x value, error predictio (units nanoseconds) + 1, //p estimation error covariance + 0.25 //k kalman gain + }; + // Get the current clock + gettimeofday( &t1, NULL ); + // Perform the kalman adjust per the predicted delay error + if (kalmanerr.x > 0) { + usec_adjusted = usec - (long) floor(kalmanerr.x); + if (usec_adjusted < 0) + usec_adjusted = 0; + } + else + usec_adjusted = usec + (long) floor(kalmanerr.x); + // Set the finishtime + finishtime = t1; + timeval_add_ulong(&finishtime, usec_adjusted); +# ifdef HAVE_NANOSLEEP + // Don't call nanosleep for values less than 10 microseconds + // as the syscall is too expensive. Let the busy loop + // provide the delay for times under that. + if (usec_adjusted > 10) { + struct timespec requested={0,0}, remaining; + timespec_add_ulong(&requested, (usec_adjusted * 1000)); + nanosleep(&requested, &remaining); + } +# endif + while (1) { + gettimeofday(&t2, NULL ); + if (timeval_greaterthan(t2, finishtime)) + break; + } + // Compute the delay error in units of microseconds + // and cast to type double + err = (double)(timeval_diff(t2, t1) - usec); + // printf("req: %ld adj: %ld err: %.5f (us)\n", usec, usec_adjusted, kalmanerr.x); + kalman_update(&kalmanerr, err); +} +#endif // Kalman +#endif diff --git a/compat/error.c b/compat/error.c new file mode 100644 index 0000000..53d1727 --- /dev/null +++ b/compat/error.c @@ -0,0 +1,210 @@ +/*--------------------------------------------------------------- + * Copyright (c) 1999,2000,2001,2002,2003 + * The Board of Trustees of the University of Illinois + * All Rights Reserved. + *--------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software (Iperf) 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: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the names of the University of Illinois, NCSA, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * 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 CONTIBUTORS 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. + * ________________________________________________________________ + * National Laboratory for Applied Network Research + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * http://www.ncsa.uiuc.edu + * ________________________________________________________________ + * + * error.c + * by Mark Gates <mgates@nlanr.net> + * ------------------------------------------------------------------- + * error handlers + * ------------------------------------------------------------------- */ + +#include "headers.h" +#include "util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 + +/* ------------------------------------------------------------------- + * Implement a simple Win32 strerror function for our purposes. + * These error values weren't handled by FormatMessage; + * any particular reason why not?? + * ------------------------------------------------------------------- */ + +struct mesg { + DWORD err; + const char* str; +}; + +const struct mesg error_mesgs[] = +{ + { WSAEACCES, "Permission denied"}, + { WSAEADDRINUSE, "Address already in use"}, + { WSAEADDRNOTAVAIL, "Cannot assign requested address"}, + { WSAEAFNOSUPPORT, "Address family not supported by protocol family"}, + { WSAEALREADY, "Operation already in progress"}, + { WSAECONNABORTED, "Software caused connection abort"}, + { WSAECONNREFUSED, "Connection refused"}, + { WSAECONNRESET, "Connection reset by peer"}, + { WSAEDESTADDRREQ, "Destination address required"}, + { WSAEFAULT, "Bad address"}, + { WSAEHOSTDOWN, "Host is down"}, + { WSAEHOSTUNREACH, "No route to host"}, + { WSAEINPROGRESS, "Operation now in progress"}, + { WSAEINTR, "Interrupted function call."}, + { WSAEINVAL, "Invalid argument."}, + { WSAEISCONN, "Socket is already connected."}, + { WSAEMFILE, "Too many open files."}, + { WSAEMSGSIZE, "Message too long"}, + { WSAENETDOWN, "Network is down"}, + { WSAENETRESET, "Network dropped connection on reset"}, + { WSAENETUNREACH, "Network is unreachable"}, + { WSAENOBUFS, "No buffer space available."}, + { WSAENOPROTOOPT, "Bad protocol option."}, + { WSAENOTCONN, "Socket is not connected"}, + { WSAENOTSOCK, "Socket operation on non-socket."}, + { WSAEOPNOTSUPP, "Operation not supported"}, + { WSAEPFNOSUPPORT, "Protocol family not supported"}, + { WSAEPROCLIM, "Too many processes."}, + { WSAEPROTONOSUPPORT, "Protocol not supported"}, + { WSAEPROTOTYPE, "Protocol wrong type for socket"}, + { WSAESHUTDOWN, "Cannot send after socket shutdown"}, + { WSAESOCKTNOSUPPORT, "Socket type not supported."}, + { WSAETIMEDOUT, "Connection timed out."}, + { WSATYPE_NOT_FOUND, "Class type not found."}, + { WSAEWOULDBLOCK, "Resource temporarily unavailable"}, + { WSAHOST_NOT_FOUND, "Host not found."}, + { WSA_INVALID_HANDLE, "Specified event object handle is invalid."}, + { WSA_INVALID_PARAMETER, "One or more parameters are invalid."}, + { WSA_IO_INCOMPLETE, "Overlapped I/O event object not in signaled state."}, + { WSA_IO_PENDING, "Overlapped operations will complete later."}, + { WSA_NOT_ENOUGH_MEMORY, "Insufficient memory available."}, + { WSANOTINITIALISED, "Successful WSAStartup not yet performed."}, + { WSANO_DATA, "Valid name, no data record of requested type."}, + { WSANO_RECOVERY, "This is a non-recoverable error."}, + { WSASYSCALLFAILURE, "System call failure."}, + { WSASYSNOTREADY, "Network subsystem is unavailable."}, + { WSATRY_AGAIN, "Non-authoritative host not found."}, + { WSAVERNOTSUPPORTED, "WINSOCK.DLL version out of range."}, + { WSAEDISCON, "Graceful shutdown in progress."}, + { WSA_OPERATION_ABORTED, "Overlapped operation aborted."}, + { 0, "No error."} + + /* These appeared in the documentation, but didn't compile. + * { WSAINVALIDPROCTABLE, "Invalid procedure table from service provider." }, + * { WSAINVALIDPROVIDER, "Invalid service provider version number." }, + * { WSAPROVIDERFAILEDINIT, "Unable to initialize a service provider." }, + */ + +}; /* end error_mesgs[] */ + +const char* winsock_strerror( DWORD inErrno ); + +/* ------------------------------------------------------------------- + * winsock_strerror + * + * returns a string representing the error code. The error messages + * were taken from Microsoft's online developer library. + * ------------------------------------------------------------------- */ + +const char* winsock_strerror( DWORD inErrno ) { + const char* str = "Unknown error"; + int i; + for ( i = 0; i < sizeof(error_mesgs); i++ ) { + if ( error_mesgs[i].err == inErrno ) { + str = error_mesgs[i].str; + break; + } + } + + return str; +} /* end winsock_strerror */ + +#endif /* WIN32 */ + +/* ------------------------------------------------------------------- + * warn + * + * Prints message and return + * ------------------------------------------------------------------- */ + +void warn( const char *inMessage, const char *inFile, int inLine ) { + fflush( 0 ); + +#ifdef NDEBUG + fprintf( stderr, "%s failed\n", inMessage ); +#else + + /* while debugging output file/line number also */ + fprintf( stderr, "%s failed (%s:%d)\n", inMessage, inFile, inLine ); +#endif +} /* end warn */ + +/* ------------------------------------------------------------------- + * warn_errno + * + * Prints message and errno message, and return. + * ------------------------------------------------------------------- */ + +void warn_errno( const char *inMessage, const char *inFile, int inLine ) { + int my_err; + const char* my_str; + + /* get platform's errno and error message */ +#ifdef WIN32 + my_err = WSAGetLastError(); + my_str = winsock_strerror( my_err ); +#else + my_err = errno; + my_str = strerror( my_err ); +#endif + + fflush( 0 ); + +#ifdef NDEBUG + fprintf( stderr, "%s failed: %s\n", inMessage, my_str ); +#else + + /* while debugging output file/line number and errno value also */ + fprintf( stderr, "%s failed (%s:%d): %s (%d)\n", + inMessage, inFile, inLine, my_str, my_err ); +#endif +} /* end warn_errno */ + +#ifdef __cplusplus +} /* end extern "C" */ +#endif diff --git a/compat/gettcpinfo.c b/compat/gettcpinfo.c new file mode 100644 index 0000000..11f92fe --- /dev/null +++ b/compat/gettcpinfo.c @@ -0,0 +1,110 @@ +/*--------------------------------------------------------------- + * Copyright (c) 2021 + * Broadcom Corporation + * All Rights Reserved. + *--------------------------------------------------------------- + * 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: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the name of Broadcom Coporation, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * 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 CONTIBUTORS 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. + * ________________________________________________________________ + * + * gettcpinfo.c + * Suppport for tcp info in a portable way + * + * by Robert J. McMahon (rjmcmahon@rjmcmahon.com, bob.mcmahon@broadcom.com) + * ------------------------------------------------------------------- + */ +#include "headers.h" +#include "gettcpinfo.h" +#ifdef HAVE_THREAD_DEBUG +// needed for thread_debug +#include "Thread.h" +#endif + +#if HAVE_TCP_STATS +inline void gettcpinfo (int sock, struct iperf_tcpstats *stats) { + assert(stats); +#if HAVE_DECL_TCP_INFO + struct tcp_info tcp_info_buf; + socklen_t tcp_info_length = sizeof(struct tcp_info); + if ((sock > 0) && !(getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tcp_info_buf, &tcp_info_length) < 0)) { + stats->cwnd = tcp_info_buf.tcpi_snd_cwnd * tcp_info_buf.tcpi_snd_mss / 1024; + stats->rtt = tcp_info_buf.tcpi_rtt; + stats->rttvar = tcp_info_buf.tcpi_rttvar; + stats->retry_tot = tcp_info_buf.tcpi_total_retrans; + stats->mss_negotiated = tcp_info_buf.tcpi_snd_mss; + stats->isValid = true; +#elif HAVE_DECL_TCP_CONNECTION_INFO + struct tcp_connection_info tcp_info_buf; + socklen_t tcp_info_length = sizeof(struct tcp_connection_info); + if ((sock > 0) && !(getsockopt(sock, IPPROTO_TCP, TCP_CONNECTION_INFO, &tcp_info_buf, &tcp_info_length) < 0)) { +#ifdef __APPLE__ + stats->cwnd = tcp_info_buf.tcpi_snd_cwnd / 1024; +#else + stats->cwnd = tcp_info_buf.tcpi_snd_cwnd * tcp_info_buf.tcpi_maxseg / 1024; +#endif + stats->rtt = tcp_info_buf.tcpi_rttcur * 1000; // OS X units is ms + stats->rttvar = tcp_info_buf.tcpi_rttvar; + stats->retry_tot = tcp_info_buf.tcpi_txretransmitpackets; + stats->mss_negotiated = tcp_info_buf.tcpi_maxseg; + stats->isValid = true; +#endif + } else { + stats->rtt = 1; + stats->isValid = false; + } +} +inline void tcpstats_copy (struct iperf_tcpstats *stats_dst, struct iperf_tcpstats *stats_src) { + stats_dst->cwnd = stats_src->cwnd; + stats_dst->rtt = stats_src->rtt; + stats_dst->rttvar = stats_src->rttvar; + stats_dst->mss_negotiated = stats_src->mss_negotiated; + stats_dst->retry_tot = stats_src->retry_tot; + stats_dst->connecttime = stats_src->connecttime; + stats_dst->isValid = stats_src->isValid; +} +#else +#if WIN32 +inline void gettcpinfo (SOCKET sock, struct iperf_tcpstats *stats) { +#else +inline void gettcpinfo (int sock, struct iperf_tcpstats *stats) { +#endif + stats->rtt = 1; + stats->isValid = false; +}; +inline void tcpstats_copy (struct iperf_tcpstats *stats_dst, struct iperf_tcpstats *stats_src) { + stats_dst->rtt = stats_src->rtt; + stats_dst->isValid = stats_src->isValid; +} +#endif diff --git a/compat/gettimeofday.c b/compat/gettimeofday.c new file mode 100644 index 0000000..0e20123 --- /dev/null +++ b/compat/gettimeofday.c @@ -0,0 +1,92 @@ +/*--------------------------------------------------------------- + * Copyright (c) 1999,2000,2001,2002,2003 + * The Board of Trustees of the University of Illinois + * All Rights Reserved. + *--------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software (Iperf) 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: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the names of the University of Illinois, NCSA, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * 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 CONTIBUTORS 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. + * ________________________________________________________________ + * National Laboratory for Applied Network Research + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * http://www.ncsa.uiuc.edu + * ________________________________________________________________ + * + * gettimeofday.c + * by Mark Gates <mgates@nlanr.net> + * ------------------------------------------------------------------- + * A (hack) implementation of gettimeofday for Windows. + * Since I send sec/usec in UDP packets, this made the most sense. + * ------------------------------------------------------------------- */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#ifndef HAVE_GETTIMEOFDAY + + #include "headers.h" + #include "gettimeofday.h" + + #ifdef __cplusplus +extern "C" { +#endif + +int gettimeofday( struct timeval* tv, void* timezone ) { + FILETIME time; + double timed; + + GetSystemTimeAsFileTime( &time ); + + // Apparently Win32 has units of 1e-7 sec (tenths of microsecs) + // 4294967296 is 2^32, to shift high word over + // 11644473600 is the number of seconds between + // the Win32 epoch 1601-Jan-01 and the Unix epoch 1970-Jan-01 + // Tests found floating point to be 10x faster than 64bit int math. + + timed = ((time.dwHighDateTime * 4294967296e-7) - 11644473600.0) + + (time.dwLowDateTime * 1e-7); + + tv->tv_sec = (long) timed; + tv->tv_usec = (long) ((timed - tv->tv_sec) * 1e6); + + return 0; +} + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* HAVE_GETTIMEOFDAY */ diff --git a/compat/inet_ntop.c b/compat/inet_ntop.c new file mode 100644 index 0000000..d34e737 --- /dev/null +++ b/compat/inet_ntop.c @@ -0,0 +1,210 @@ +#include "inet_aton.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +// support for hiding v4 addresses from outputs +const char* +inet_ntop_hide(int af, const void *src, char *dst, socklen_t size) { + switch ( af ) { + case AF_INET: + return(inet_ntop4_hide(src, dst, size)); + default: + return NULL; + } + /* NOTREACHED */ +} +const char* +inet_ntop4_hide(const unsigned char *src, char *dst, socklen_t size) { + static const char *fmt = "%s.%s.%s.%u"; + char tmp[sizeof "255.255.255.255"]; + + if ( (size_t)sprintf(tmp, fmt, "*","*","*", src[3]) >= size ) { + return NULL; + } + strcpy(dst, tmp); + + return dst; +} + + +#ifndef HAVE_INET_NTOP +#define NS_INT16SZ 2 +#define NS_INADDRSZ 4 +#define NS_IN6ADDRSZ 16 + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + + +/* char * + * isc_net_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char* +inet_ntop(int af, const void *src, char *dst, socklen_t size) { + switch ( af ) { + case AF_INET: + return(inet_ntop4(src, dst, size)); +#if HAVE_IPV6 + case AF_INET6: + return(inet_ntop6(src, dst, size)); +#endif + default: + return NULL; + } + /* NOTREACHED */ +} + + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a unsigned char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +const char* +inet_ntop4(const unsigned char *src, char *dst, socklen_t size) { + static const char *fmt = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + + if ( (size_t)sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) >= size ) { + return NULL; + } + strcpy(dst, tmp); + + return dst; +} + +/* const char * + * isc_inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +#if HAVE_IPV6 +const char* +inet_ntop6(const unsigned char *src, char *dst, socklen_t size) { + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { + int base, len; + } best, cur; + unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for ( i = 0; i < NS_IN6ADDRSZ; i++ ) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for ( i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++ ) { + if ( words[i] == 0 ) { + if ( cur.base == -1 ) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if ( cur.base != -1 ) { + if ( best.base == -1 || cur.len > best.len ) + best = cur; + cur.base = -1; + } + } + } + if ( cur.base != -1 ) { + if ( best.base == -1 || cur.len > best.len ) + best = cur; + } + if ( best.base != -1 && best.len < 2 ) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for ( i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++ ) { + /* Are we inside the best run of 0x00's? */ + if ( best.base != -1 && i >= best.base && + i < (best.base + best.len) ) { + if ( i == best.base ) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if ( i != 0 ) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if ( i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff)) ) { + if ( !inet_ntop4(src+12, tp, + sizeof tmp - (tp - tmp)) ) + return NULL; + tp += strlen(tp); + break; + } + tp += sprintf(tp, "%x", words[i]); + } + /* Was it a trailing run of 0x00's? */ + if ( best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ) ) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ( (size_t)(tp - tmp) > size ) { + errno = ENOSPC; + return NULL; + } + strcpy(dst, tmp); + return dst; +} +#endif /* HAVE_IPV6 */ +#endif /* HAVE_INET_NTOP */ + +#ifdef __cplusplus +} /* end extern "C" */ +#endif diff --git a/compat/inet_pton.c b/compat/inet_pton.c new file mode 100644 index 0000000..32ee887 --- /dev/null +++ b/compat/inet_pton.c @@ -0,0 +1,209 @@ +#include "inet_aton.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef HAVE_INET_PTON +#define NS_INT16SZ 2 +#define NS_INADDRSZ 4 +#define NS_IN6ADDRSZ 16 + +/* int + * isc_net_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * author: + * Paul Vixie, 1996. + */ +int +inet_pton(int af, + const char *src, + void *dst) { + switch ( af ) { + case AF_INET: + return(inet_pton4(src, dst)); +#if HAVE_IPV6 + case AF_INET6: + return(inet_pton6(src, dst)); +#endif + default: + return 0; + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +int +inet_pton4(src, dst) +const char *src; +unsigned char *dst; +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ( (ch = *src++) != '\0' ) { + const char *pch; + + if ( (pch = strchr(digits, ch)) != NULL ) { + unsigned int new = *tp * 10 + (pch - digits); + + if ( new > 255 ) + return(0); + *tp = new; + if ( ! saw_digit ) { + if ( ++octets > 4 ) + return(0); + saw_digit = 1; + } + } else if ( ch == '.' && saw_digit ) { + if ( octets == 4 ) + return(0); + *++tp = 0; + saw_digit = 0; + } else + return(0); + } + if ( octets < 4 ) + return(0); + memcpy(dst, tmp, NS_INADDRSZ); + return(1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +#if HAVE_IPV6 +int +inet_pton6(src, dst) +const char *src; +unsigned char *dst; +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + unsigned int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if ( *src == ':' ) + if ( *++src != ':' ) + return(0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ( (ch = *src++) != '\0' ) { + const char *pch; + + if ( (pch = strchr((xdigits = xdigits_l), ch)) == NULL ) + pch = strchr((xdigits = xdigits_u), ch); + if ( pch != NULL ) { + val <<= 4; + val |= (pch - xdigits); + if ( val > 0xffff ) + return(0); + saw_xdigit = 1; + continue; + } + if ( ch == ':' ) { + curtok = src; + if ( !saw_xdigit ) { + if ( colonp ) + return(0); + colonp = tp; + continue; + } + if ( tp + NS_INT16SZ > endp ) + return(0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if ( ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0 ) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return(0); + } + if ( saw_xdigit ) { + if ( tp + NS_INT16SZ > endp ) + return(0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if ( colonp != NULL ) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + for ( i = 1; i <= n; i++ ) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if ( tp != endp ) + return(0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return(1); +} +#endif + +#endif /* HAVE_INET_PTON */ + +#ifdef __cplusplus +} /* end extern "C" */ +#endif diff --git a/compat/signal.c b/compat/signal.c new file mode 100644 index 0000000..7060305 --- /dev/null +++ b/compat/signal.c @@ -0,0 +1,204 @@ +/*--------------------------------------------------------------- + * Copyright (c) 1999,2000,2001,2002,2003 + * The Board of Trustees of the University of Illinois + * All Rights Reserved. + *--------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software (Iperf) 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: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the names of the University of Illinois, NCSA, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * 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 CONTIBUTORS 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. + * ________________________________________________________________ + * National Laboratory for Applied Network Research + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * http://www.ncsa.uiuc.edu + * ________________________________________________________________ + * + * signal.c + * by Mark Gates <mgates@nlanr.net> + * ------------------------------------------------------------------- + * standard signal installer + * ------------------------------------------------------------------- */ + +#include "headers.h" +#include "util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 + +/* list of signal handlers. _NSIG is number of signals defined. */ + +static SigfuncPtr handlers[ _NSIG ] = { 0}; + +/* ------------------------------------------------------------------- + * sig_dispatcher + * + * dispatches the signal to appropriate signal handler. This emulates + * the signal handling of Unix. + * + * ------------------------------------------------------------------- */ + +BOOL WINAPI sig_dispatcher( DWORD type ) { + SigfuncPtr h = NULL; + int signo; + + switch ( type ) { + case CTRL_C_EVENT: + signo = SIGINT; + h = handlers[ SIGINT ]; + break; + + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + signo = SIGTERM; + h = handlers[ SIGTERM ]; + break; + + default: + break; + } + + if ( h != NULL ) { + // call the signal handler + h( signo ); + return 1; + } else { + return 0; + } +} + +/* ------------------------------------------------------------------- + * my_signal + * + * installs a signal handler. I emulate Unix signals by storing the + * function pointers and dispatching events myself, using the + * sig_dispatcher above. + * ------------------------------------------------------------------- */ + +SigfuncPtr my_signal( int inSigno, SigfuncPtr inFunc ) { + SigfuncPtr old = NULL; + + if ( inSigno >= 0 && inSigno < _NSIG ) { + old = handlers[ inSigno ]; + handlers[ inSigno ] = inFunc; + } + + return old; +} /* end my_signal */ + +#else /* not WIN32 */ + +/* ------------------------------------------------------------------- + * my_signal + * + * installs a signal handler, and returns the old handler. + * This emulates the semi-standard signal() function in a + * standard way using the Posix sigaction function. + * + * from Stevens, 1998, section 5.8 + * ------------------------------------------------------------------- */ + +SigfuncPtr my_signal( int inSigno, SigfuncPtr inFunc ) { + struct sigaction theNewAction, theOldAction; + + assert( inFunc != NULL ); + + theNewAction.sa_handler = inFunc; + sigemptyset( &theNewAction.sa_mask ); + theNewAction.sa_flags = 0; + + if ( inSigno == SIGALRM ) { +#ifdef SA_INTERRUPT + theNewAction.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */ +#endif + } else { +#ifdef SA_RESTART + theNewAction.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD */ +#endif + } + + if ( sigaction( inSigno, &theNewAction, &theOldAction ) < 0 ) { + return SIG_ERR; + } else { + return theOldAction.sa_handler; + } +} /* end my_signal */ + +#endif /* not WIN32 */ + +/* ------------------------------------------------------------------- + * sig_exit + * + * Quietly exits. This protects some against being called multiple + * times. (TODO: should use a mutex to ensure (num++ == 0) is atomic.) + * ------------------------------------------------------------------- */ + +void sig_exit( int inSigno ) { + static int num = 0; + if ( num++ == 0 ) { + fflush( 0 ); + _exit(0); + } +} /* end sig_exit */ + +void disarm_itimer(void) { +#ifdef HAVE_SETITIMER + struct itimerval it; + memset (&it, 0, sizeof (it)); + setitimer(ITIMER_REAL, &it, NULL); +#endif +} + +int set_itimer(uintmax_t usecs) { + int err = 0; +#ifdef HAVE_SETITIMER + if (usecs < 0) { + WARN(1, "set_itimer value invalid"); + } else { + struct itimerval it; + memset (&it, 0, sizeof (it)); + it.it_value.tv_sec = (int)(usecs / 1000000); + it.it_value.tv_usec = (int)(usecs % 1000000); + err = setitimer(ITIMER_REAL, &it, NULL); + } +#endif + return err; +} + +#ifdef __cplusplus +} /* end extern "C" */ +#endif diff --git a/compat/snprintf.c b/compat/snprintf.c new file mode 100644 index 0000000..be56a53 --- /dev/null +++ b/compat/snprintf.c @@ -0,0 +1,101 @@ +/*--------------------------------------------------------------- + * Copyright (c) 1999,2000,2001,2002,2003 + * The Board of Trustees of the University of Illinois + * All Rights Reserved. + *--------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software (Iperf) 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: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the names of the University of Illinois, NCSA, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * 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 CONTIBUTORS 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. + * ________________________________________________________________ + * National Laboratory for Applied Network Research + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * http://www.ncsa.uiuc.edu + * ________________________________________________________________ + * Author: Mark Gates + * + * snprintf.c + * + * This is from + * W. Richard Stevens, 'UNIX Network Programming', Vol 1, 2nd Edition, + * Prentice Hall, 1998. + * + * + * Throughout the book I use snprintf() because it's safer than sprintf(). + * But as of the time of this writing, not all systems provide this + * function. The function below should only be built on those systems + * that do not provide a real snprintf(). + * The function below just acts like sprintf(); it is not safe, but it + * tries to detect overflow. + * ________________________________________________________________ */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#ifndef HAVE_SNPRINTF + + #include <stdlib.h> + #include <string.h> + #include <stdio.h> + #include <stdarg.h> + + #include "snprintf.h" + + #ifdef __cplusplus +extern "C" { +#endif + +int snprintf(char *buf, size_t size, const char *fmt, ...) { + int n; + va_list ap; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); /* Sigh, some vsprintf's return ptr, not length */ + n = strlen(buf); + va_end(ap); + + if ( n >= size ) { + fprintf( stderr, "snprintf: overflowed array\n" ); + exit(1); + } + + return(n); +} + +#ifdef __cplusplus +} /* end extern "C" */ + #endif + +#endif /* HAVE_SNPRINTF */ diff --git a/compat/string.c b/compat/string.c new file mode 100644 index 0000000..99415b5 --- /dev/null +++ b/compat/string.c @@ -0,0 +1,76 @@ +/*--------------------------------------------------------------- + * Copyright (c) 1999,2000,2001,2002,2003 + * The Board of Trustees of the University of Illinois + * All Rights Reserved. + *--------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software (Iperf) 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: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the names of the University of Illinois, NCSA, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * 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 CONTIBUTORS 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. + * ________________________________________________________________ + * National Laboratory for Applied Network Research + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * http://www.ncsa.uiuc.edu + * ________________________________________________________________ + * + * string.c + * by Mark Gates <mgates@nlanr.net> + * ------------------------------------------------------------------- + * various string utilities + * ------------------------------------------------------------------- */ + +#include "headers.h" +#include "util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------------------------------------------------------- + * pattern + * + * Initialize the buffer with a pattern of (index mod 10). + * ------------------------------------------------------------------- */ + +void pattern( char *outBuf, int inBytes ) { + assert( outBuf != NULL ); + + while ( inBytes-- > 0 ) { + outBuf[ inBytes ] = (inBytes % 10) + '0'; + } +} /* end pattern */ + +#ifdef __cplusplus +} /* end extern "C" */ +#endif |