diff options
Diffstat (limited to 'src')
47 files changed, 5620 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..c5f77fa --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,44 @@ +## Helder Correia <helder.correia@netcabo.pt> + +bin_PROGRAMS = nload + +nload_SOURCES = \ + dataframe.h \ + device.cpp device.h \ + devreader.cpp devreader.h \ + devreaderfactory.cpp devreaderfactory.h \ + form_field.cpp form_field.h \ + graph.cpp graph.h \ + main.cpp main.h \ + opt_window.cpp opt_window.h \ + screen.cpp screen.h \ + setting.cpp setting.h \ + settingfilter.cpp settingfilter.h \ + settingstore.cpp settingstore.h \ + statistics.cpp statistics.h \ + stringutils.cpp stringutils.h \ + traffic_window.cpp traffic_window.h \ + window.cpp window.h + +if HAVE_BSD +nload_SOURCES += \ + devreader-bsd.cpp devreader-bsd.h +endif + +if HAVE_HPUX +nload_SOURCES += \ + devreader-hpux.cpp devreader-hpux.h +endif + +if HAVE_LINUX +nload_SOURCES += \ + devreader-linux.cpp devreader-linux.h \ + devreader-linux-proc.cpp devreader-linux-proc.h \ + devreader-linux-sys.cpp devreader-linux-sys.h +endif + +if HAVE_SOLARIS +nload_SOURCES += \ + devreader-solaris.cpp devreader-solaris.h +endif + diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..52a5278 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,536 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@ +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@ +bin_PROGRAMS = nload$(EXEEXT) +@HAVE_BSD_TRUE@am__append_1 = \ +@HAVE_BSD_TRUE@ devreader-bsd.cpp devreader-bsd.h + +@HAVE_HPUX_TRUE@am__append_2 = \ +@HAVE_HPUX_TRUE@ devreader-hpux.cpp devreader-hpux.h + +@HAVE_LINUX_TRUE@am__append_3 = \ +@HAVE_LINUX_TRUE@ devreader-linux.cpp devreader-linux.h \ +@HAVE_LINUX_TRUE@ devreader-linux-proc.cpp devreader-linux-proc.h \ +@HAVE_LINUX_TRUE@ devreader-linux-sys.cpp devreader-linux-sys.h + +@HAVE_SOLARIS_TRUE@am__append_4 = \ +@HAVE_SOLARIS_TRUE@ devreader-solaris.cpp devreader-solaris.h + +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am__nload_SOURCES_DIST = dataframe.h device.cpp device.h devreader.cpp \ + devreader.h devreaderfactory.cpp devreaderfactory.h \ + form_field.cpp form_field.h graph.cpp graph.h main.cpp main.h \ + opt_window.cpp opt_window.h screen.cpp screen.h setting.cpp \ + setting.h settingfilter.cpp settingfilter.h settingstore.cpp \ + settingstore.h statistics.cpp statistics.h stringutils.cpp \ + stringutils.h traffic_window.cpp traffic_window.h window.cpp \ + window.h devreader-bsd.cpp devreader-bsd.h devreader-hpux.cpp \ + devreader-hpux.h devreader-linux.cpp devreader-linux.h \ + devreader-linux-proc.cpp devreader-linux-proc.h \ + devreader-linux-sys.cpp devreader-linux-sys.h \ + devreader-solaris.cpp devreader-solaris.h +@HAVE_BSD_TRUE@am__objects_1 = devreader-bsd.$(OBJEXT) +@HAVE_HPUX_TRUE@am__objects_2 = devreader-hpux.$(OBJEXT) +@HAVE_LINUX_TRUE@am__objects_3 = devreader-linux.$(OBJEXT) \ +@HAVE_LINUX_TRUE@ devreader-linux-proc.$(OBJEXT) \ +@HAVE_LINUX_TRUE@ devreader-linux-sys.$(OBJEXT) +@HAVE_SOLARIS_TRUE@am__objects_4 = devreader-solaris.$(OBJEXT) +am_nload_OBJECTS = device.$(OBJEXT) devreader.$(OBJEXT) \ + devreaderfactory.$(OBJEXT) form_field.$(OBJEXT) \ + graph.$(OBJEXT) main.$(OBJEXT) opt_window.$(OBJEXT) \ + screen.$(OBJEXT) setting.$(OBJEXT) settingfilter.$(OBJEXT) \ + settingstore.$(OBJEXT) statistics.$(OBJEXT) \ + stringutils.$(OBJEXT) traffic_window.$(OBJEXT) \ + window.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) $(am__objects_4) +nload_OBJECTS = $(am_nload_OBJECTS) +nload_LDADD = $(LDADD) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(nload_SOURCES) +DIST_SOURCES = $(am__nload_SOURCES_DIST) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +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@ +INCLUDES = @INCLUDES@ +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@ +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@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +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@ +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@ +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@ +nload_SOURCES = dataframe.h device.cpp device.h devreader.cpp \ + devreader.h devreaderfactory.cpp devreaderfactory.h \ + form_field.cpp form_field.h graph.cpp graph.h main.cpp main.h \ + opt_window.cpp opt_window.h screen.cpp screen.h setting.cpp \ + setting.h settingfilter.cpp settingfilter.h settingstore.cpp \ + settingstore.h statistics.cpp statistics.h stringutils.cpp \ + stringutils.h traffic_window.cpp traffic_window.h window.cpp \ + window.h $(am__append_1) $(am__append_2) $(am__append_3) \ + $(am__append_4) +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +$(srcdir)/Makefile.in: $(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 src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: 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__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +nload$(EXEEXT): $(nload_OBJECTS) $(nload_DEPENDENCIES) + @rm -f nload$(EXEEXT) + $(CXXLINK) $(nload_OBJECTS) $(nload_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/device.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devreader-bsd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devreader-hpux.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devreader-linux-proc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devreader-linux-sys.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devreader-linux.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devreader-solaris.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devreader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devreaderfactory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/form_field.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/graph.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt_window.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/screen.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setting.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/settingfilter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/settingstore.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statistics.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringutils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/traffic_window.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/window.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + 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 +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + 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" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(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 $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +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: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +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-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -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-binPROGRAMS + +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 -rf ./$(DEPDIR) + -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: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + 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 uninstall \ + uninstall-am uninstall-binPROGRAMS + + +# 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/src/dataframe.h b/src/dataframe.h new file mode 100644 index 0000000..3311292 --- /dev/null +++ b/src/dataframe.h @@ -0,0 +1,88 @@ +/*************************************************************************** + dataframe.h + ------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef DATAFRAME_H +#define DATAFRAME_H + +#include <string> + +class DataFrame +{ + public: + DataFrame() + : m_totalDataIn(0), m_totalDataOut(0), m_totalPacketsIn(0), m_totalPacketsOut(0), + m_totalErrorsIn(0), m_totalErrorsOut(0), m_totalDropsIn(0), m_totalDropsOut(0), + m_timeStampSeconds(0), m_timeStampMicroseconds(0), m_valid(false) {} + ~DataFrame() {} + + bool isValid() const { return m_valid; } + void setValid(bool valid) { m_valid = valid; } + + const std::string& getDeviceName() const { return m_deviceName; } + void setDeviceName(const std::string& deviceName) { m_deviceName = deviceName; } + + const std::string& getIpV4() const { return m_ipv4; } + void setIpV4(const std::string& ipv4) { m_ipv4 = ipv4; } + + unsigned long long getTotalDataIn() const { return m_totalDataIn; } + void setTotalDataIn(unsigned long long totalDataIn) { m_totalDataIn = totalDataIn; } + + unsigned long long getTotalDataOut() const { return m_totalDataOut; } + void setTotalDataOut(unsigned long long totalDataOut) { m_totalDataOut = totalDataOut; } + + unsigned long long getTotalPacketsIn() const { return m_totalPacketsIn; } + void setTotalPacketsIn(unsigned long long totalPacketsIn) { m_totalPacketsIn = totalPacketsIn; } + + unsigned long long getTotalPacketsOut() const { return m_totalPacketsOut; } + void setTotalPacketsOut(unsigned long long totalPacketsOut) { m_totalPacketsOut = totalPacketsOut; } + + unsigned long long getTotalErrorsIn() const { return m_totalErrorsIn; } + void setTotalErrorsIn(unsigned long long totalErrorsIn) { m_totalErrorsIn = totalErrorsIn; } + + unsigned long long getTotalErrorsOut() const { return m_totalErrorsOut; } + void setTotalErrorsOut(unsigned long long totalErrorsOut) { m_totalErrorsOut = totalErrorsOut; } + + unsigned long long getTotalDropsIn() const { return m_totalDropsIn; } + void setTotalDropsIn(unsigned long long totalDropsIn) { m_totalDropsIn = totalDropsIn; } + + unsigned long long getTotalDropsOut() const { return m_totalDropsOut; } + void setTotalDropsOut(unsigned long long totalDropsOut) { m_totalDropsOut = totalDropsOut; } + + unsigned long getTimeStampSeconds() const { return m_timeStampSeconds; } + void setTimeStampSeconds(unsigned long seconds) { m_timeStampSeconds = seconds; } + + unsigned long getTimeStampMicroseconds() const { return m_timeStampMicroseconds; } + void setTimeStampMicroseconds(unsigned long microseconds) { m_timeStampMicroseconds = microseconds; } + + private: + std::string m_deviceName; + std::string m_ipv4; + unsigned long long m_totalDataIn; + unsigned long long m_totalDataOut; + unsigned long long m_totalPacketsIn; + unsigned long long m_totalPacketsOut; + unsigned long long m_totalErrorsIn; + unsigned long long m_totalErrorsOut; + unsigned long long m_totalDropsIn; + unsigned long long m_totalDropsOut; + unsigned long m_timeStampSeconds; + unsigned long m_timeStampMicroseconds; + bool m_valid; +}; + +#endif + diff --git a/src/device.cpp b/src/device.cpp new file mode 100644 index 0000000..e3d6372 --- /dev/null +++ b/src/device.cpp @@ -0,0 +1,226 @@ +/*************************************************************************** + dev.cpp + ------------------- + begin : Wed Aug 1 2001 + copyright : (C) 2001 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "device.h" +#include "devreader.h" +#include "graph.h" +#include "setting.h" +#include "settingstore.h" +#include "window.h" + +#include <iomanip> + +using namespace std; + +Device::Device(DevReader& devReader) + : m_deviceNumber(0), m_totalNumberOfDevices(0), m_devReader(devReader) +{ +} + +Device::~Device() +{ +} + +// update the device's data +void Device::update() +{ + // read current traffic + DataFrame dataFrame = m_devReader.getNewDataFrame(); + + if(dataFrame.isValid()) + { + /* Depending on the CPU architecture and the OS interface + * used for reading the device statistics, the counts can + * overflow. We monitor the overflows and fix them. + */ + fixOverflows(dataFrame, m_dataFrameOld); + + m_deviceStatistics.insertDataFrame(dataFrame); + + m_deviceGraphIn.update(m_deviceStatistics.getDataInPerSecond()); + m_deviceGraphOut.update(m_deviceStatistics.getDataOutPerSecond()); + + m_dataFrameOld = dataFrame; + } + else + { + m_deviceStatistics.reset(); + m_deviceGraphIn.resetTrafficData(); + m_deviceGraphOut.resetTrafficData(); + } +} + +// print the device's data +void Device::print(Window& window) +{ + // if device does not exist + if(!m_deviceStatistics.isValid()) + { + // ... print warning message ... + window.print() << "Device " << m_devReader.getDeviceName() << " (" << (m_deviceNumber + 1) << "/" << m_totalNumberOfDevices << "): does not exist" << endl; + window.print() << string(window.getWidth(), '=') << endl; + + // ... and exit + return; + } + + // print header + string ip4 = m_dataFrameOld.getIpV4(); + if(!ip4.empty()) + window.print() << "Device " << m_devReader.getDeviceName() << " [" << ip4 << "] (" << (m_deviceNumber + 1) << "/" << m_totalNumberOfDevices << "):" << endl; + else + window.print() << "Device " << m_devReader.getDeviceName() << " (" << (m_deviceNumber + 1) << "/" << m_totalNumberOfDevices << "):" << endl; + window.print() << string(window.getWidth(), '='); + + // if graphs should be hidden ... + if(SettingStore::get("MultipleDevices")) + { + window.print() << "Incoming:"; + window.print(window.getWidth() / 2) << "Outgoing:" << endl; + + int statusY = window.getY(); + + printStatisticsIn(window, 0, statusY); + printStatisticsOut(window, window.getWidth() / 2, statusY); + + window.print() << endl; + } + // ... or not + else + { + // incoming traffic + window.print() << "Incoming:" << endl; + + m_deviceGraphIn.setNumOfBars(window.getWidth() * 2 / 3); + m_deviceGraphIn.setHeightOfBars((window.getHeight() - window.getY() - 1) / 2); + m_deviceGraphIn.setMaxDeflection((unsigned long long) SettingStore::get("BarMaxIn") * 1024 / 8); + m_deviceGraphIn.print(window, 0, window.getY()); + + printStatisticsIn(window, window.getWidth() * 2 / 3 + 2, window.getY() - 5); + + // outgoing traffic + window.print() << "Outgoing:" << endl; + + m_deviceGraphOut.setNumOfBars(window.getWidth() * 2 / 3); + m_deviceGraphOut.setHeightOfBars(window.getHeight() - window.getY()); + m_deviceGraphOut.setMaxDeflection((unsigned long long) SettingStore::get("BarMaxOut") * 1024 / 8); + m_deviceGraphOut.print(window, 0, window.getY()); + + printStatisticsOut(window, window.getWidth() * 2 / 3 + 2, window.getY() - 4); + } +} + +// set the number identifying the device (for display only) +void Device::setDeviceNumber(int deviceNumber) +{ + m_deviceNumber = deviceNumber; +} + +// set the total number of shown devices (for display only) +void Device::setTotalNumberOfDevices(int totalNumberOfDevices) +{ + m_totalNumberOfDevices = totalNumberOfDevices; +} + +void Device::fixOverflows(DataFrame& dataFrame, const DataFrame& dataFrameOld) +{ + if(!dataFrame.isValid() || !dataFrameOld.isValid()) + return; + + dataFrame.setTotalDataIn(fixOverflow(dataFrame.getTotalDataIn(), dataFrameOld.getTotalDataIn())); + dataFrame.setTotalDataOut(fixOverflow(dataFrame.getTotalDataOut(), dataFrameOld.getTotalDataOut())); + dataFrame.setTotalPacketsIn(fixOverflow(dataFrame.getTotalPacketsIn(), dataFrameOld.getTotalPacketsIn())); + dataFrame.setTotalPacketsOut(fixOverflow(dataFrame.getTotalPacketsOut(), dataFrameOld.getTotalPacketsOut())); + dataFrame.setTotalErrorsIn(fixOverflow(dataFrame.getTotalErrorsIn(), dataFrameOld.getTotalErrorsIn())); + dataFrame.setTotalErrorsOut(fixOverflow(dataFrame.getTotalErrorsOut(), dataFrameOld.getTotalErrorsOut())); + dataFrame.setTotalDropsIn(fixOverflow(dataFrame.getTotalDropsIn(), dataFrameOld.getTotalDropsIn())); + dataFrame.setTotalDropsOut(fixOverflow(dataFrame.getTotalDropsOut(), dataFrameOld.getTotalDropsOut())); +} + +unsigned long long Device::fixOverflow(unsigned long long value, unsigned long long valueOld) +{ + if(value > 0xffffffffULL) + return value; + + if(value < (valueOld & 0xffffffffULL)) + { + // overflow happend (again) + valueOld += 0x100000000ULL; + } + + // no overflow happend, keep previous ones + valueOld &= 0xffffffff00000000ULL; + value |= valueOld; + return value; +} + +void Device::printTrafficValue(Window& window, int x, int y, const std::string& description, unsigned long long value) +{ + Statistics::dataUnit trafficFormat = (Statistics::dataUnit) ((int) SettingStore::get("TrafficFormat")); + + string unitString = Statistics::getUnitString(trafficFormat, value); + float unitFactor = Statistics::getUnitFactor(trafficFormat, value); + + window.print(x, y) << fixed << setprecision(2) << description << ": " << ((float) value / unitFactor) << " " << unitString << "/s" << endl; +} + +void Device::printDataValue(Window& window, int x, int y, const std::string& description, unsigned long long value) +{ + Statistics::dataUnit dataFormat = (Statistics::dataUnit) ((int) SettingStore::get("DataFormat")); + + string unitString = Statistics::getUnitString(dataFormat, value); + float unitFactor = Statistics::getUnitFactor(dataFormat, value); + + window.print(x, y) << fixed << setprecision(2) << description << ": " << ((float) value / unitFactor) << " " << unitString << endl; +} + +void Device::printStatisticsIn(Window& window, int x, int y) +{ + // print current traffic + printTrafficValue(window, x, y, "Curr", m_deviceStatistics.getDataInPerSecond()); + + // print average traffic + printTrafficValue(window, x, y + 1, "Avg", m_deviceStatistics.getDataInAverage()); + + // print min traffic since nload start + printTrafficValue(window, x, y + 2, "Min", m_deviceStatistics.getDataInMin()); + + // print max traffic since nload start + printTrafficValue(window, x, y + 3, "Max", m_deviceStatistics.getDataInMax()); + + // print total traffic since last system reboot + printDataValue(window, x, y + 4, "Ttl", m_deviceStatistics.getDataInTotal()); +} + +void Device::printStatisticsOut(Window& window, int x, int y) +{ + // print current traffic + printTrafficValue(window, x, y, "Curr", m_deviceStatistics.getDataOutPerSecond()); + + // print average traffic + printTrafficValue(window, x, y + 1, "Avg", m_deviceStatistics.getDataOutAverage()); + + // print min traffic since nload start + printTrafficValue(window, x, y + 2, "Min", m_deviceStatistics.getDataOutMin()); + + // print max traffic since nload start + printTrafficValue(window, x, y + 3, "Max", m_deviceStatistics.getDataOutMax()); + + // print total traffic since last system reboot + printDataValue(window, x, y + 4, "Ttl", m_deviceStatistics.getDataOutTotal()); +} + diff --git a/src/device.h b/src/device.h new file mode 100644 index 0000000..25d8211 --- /dev/null +++ b/src/device.h @@ -0,0 +1,62 @@ +/*************************************************************************** + device.h + ------------------- + begin : Wed Aug 1 2001 + copyright : (C) 2001 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef DEVICE_H +#define DEVICE_H + +#include "dataframe.h" +#include "graph.h" +#include "statistics.h" + +#include <string> + +class DevReader; +class Window; + +class Device +{ + public: + explicit Device(DevReader& devReader); + ~Device(); + + void update(); + void print(Window&); + void setDeviceNumber(int deviceNumber); + void setTotalNumberOfDevices(int totalNumberOfDevices); + + private: + void fixOverflows(DataFrame& dataFrame, const DataFrame& dataFrameOld); + unsigned long long fixOverflow(unsigned long long value, unsigned long long valueOld); + + void printTrafficValue(Window& window, int x, int y, const std::string& description, unsigned long long value); + void printDataValue(Window& window, int x, int y, const std::string& description, unsigned long long value); + void printStatisticsIn(Window& window, int x, int y); + void printStatisticsOut(Window& window, int x, int y); + + int m_deviceNumber; + int m_totalNumberOfDevices; + + Statistics m_deviceStatistics; + Graph m_deviceGraphIn; + Graph m_deviceGraphOut; + + DataFrame m_dataFrameOld; + DevReader& m_devReader; +}; + +#endif + diff --git a/src/devreader-bsd.cpp b/src/devreader-bsd.cpp new file mode 100644 index 0000000..b542704 --- /dev/null +++ b/src/devreader-bsd.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +/*************************************************************************** + * Free/Net/OpenBSD specific network code taken out of gkrellm: * + * Copyright by Bill Wilson <bill@gkrellm.net> * + * FreeBSD code by Hajimu Umemoto <ume@mahoroba.org> * + * NetBSD code by Anthony Mallet <anthony.mallet@useless-ficus.net> * + * Hajimu Umemoto merged Free/Net/OpenBSD code * + * adapted for nload by Roland Riegel <feedback@roland-riegel.de> * + ***************************************************************************/ + +#include "devreader-bsd.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <net/if_dl.h> +#include <net/route.h> + +#include <string> +#include <list> + +using namespace std; + +DevReaderBsd::DevReaderBsd(const string& deviceName) + : DevReader(deviceName) +{ +} + +DevReaderBsd::~DevReaderBsd() +{ +} + +list<string> DevReaderBsd::findAllDevices() +{ + list<string> interfaceNames; + + struct if_msghdr *ifm, *nextifm; + struct sockaddr_dl *sdl; + char *lim, *next; + size_t needed; + int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; + char *buf = 0; + + if(sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + return interfaceNames; + + buf = (char *) malloc(needed); + if(buf == NULL) + return interfaceNames; + + if(sysctl(mib, 6, buf, &needed, NULL, 0) < 0) + return interfaceNames; + + lim = buf + needed; + + next = buf; + while(next < lim) + { + ifm = (struct if_msghdr *) next; + if(ifm->ifm_type != RTM_IFINFO) + break; + + next += ifm->ifm_msglen; + + while(next < lim) + { + nextifm = (struct if_msghdr *) next; + if(nextifm->ifm_type != RTM_NEWADDR) + break; + next += nextifm->ifm_msglen; + } + + sdl = (struct sockaddr_dl *) (ifm + 1); + if(sdl->sdl_family != AF_LINK) + continue; + + interfaceNames.push_back(string(sdl->sdl_data)); + } + + free(buf); + + return interfaceNames; +} + +void DevReaderBsd::readFromDevice(DataFrame& dataFrame) +{ + struct if_msghdr *ifm, *nextifm; + struct sockaddr_dl *sdl; + char *lim, *next; + size_t needed; + int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; + char *buf = 0; + + if(m_deviceName.empty()) + return; + + do + { + if(sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + break; + + buf = (char *) malloc(needed); + if(buf == NULL) + break; + + if(sysctl(mib, 6, buf, &needed, NULL, 0) < 0) + break; + + lim = buf + needed; + + next = buf; + while(next < lim) + { + ifm = (struct if_msghdr *) next; + if(ifm->ifm_type != RTM_IFINFO) + break; + + next += ifm->ifm_msglen; + + while(next < lim) + { + nextifm = (struct if_msghdr *) next; + if(nextifm->ifm_type != RTM_NEWADDR) + break; + next += nextifm->ifm_msglen; + } + + if(ifm->ifm_flags & IFF_UP) + { + sdl = (struct sockaddr_dl *) (ifm + 1); + if(sdl->sdl_family != AF_LINK) + continue; + + if(strncmp(m_deviceName.c_str(), sdl->sdl_data, sdl->sdl_nlen) == 0) + { + dataFrame.setTotalDataIn(ifm->ifm_data.ifi_ibytes); + dataFrame.setTotalDataOut(ifm->ifm_data.ifi_obytes); + + dataFrame.setTotalPacketsIn(ifm->ifm_data.ifi_ipackets); + dataFrame.setTotalPacketsOut(ifm->ifm_data.ifi_opackets); + + dataFrame.setTotalErrorsIn(ifm->ifm_data.ifi_ierrors); + dataFrame.setTotalErrorsOut(ifm->ifm_data.ifi_oerrors); + + dataFrame.setTotalDropsIn(0); // ifi_iqdrops ? + dataFrame.setTotalDropsOut(0); + + dataFrame.setValid(true); + + break; + } + } + } + } while(0); + + free(buf); +} + diff --git a/src/devreader-bsd.h b/src/devreader-bsd.h new file mode 100644 index 0000000..0907b19 --- /dev/null +++ b/src/devreader-bsd.h @@ -0,0 +1,39 @@ +/*************************************************************************** + devreader-bsd.h + ------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef DEVREADER_BSD_H +#define DEVREADER_BSD_H + +#include "devreader.h" + +#include <string> +#include <list> + +class DevReaderBsd : public DevReader +{ + public: + DevReaderBsd(const std::string& deviceName); + virtual ~DevReaderBsd(); + + static std::list<std::string> findAllDevices(); + + protected: + void readFromDevice(DataFrame& dataFrame); +}; + +#endif + diff --git a/src/devreader-hpux.cpp b/src/devreader-hpux.cpp new file mode 100644 index 0000000..c1f5403 --- /dev/null +++ b/src/devreader-hpux.cpp @@ -0,0 +1,294 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +/*************************************************************************** + * HP-UX specific network code * + * * + * Copyright 1998 by Hewlett-Packard Company * + * * + * Permission to use, copy, modify, and distribute this * + * software and its documentation for any purpose and without * + * fee is hereby granted, provided that the above copyright * + * notice appear in all copies and that both that copyright * + * notice and this permission notice appear in supporting * + * documentation, and that the name of Hewlett-Packard Company not * + * be used in advertising or publicity pertaining to distribution * + * of the software without specific, written prior permission. * + * Hewlett-Packard makes no representations about the * + * suitability of this software for any purpose. It is provided * + * "as is" without express or implied warranty. * + * * + * * + * Modification History: * + * * + * int_stats.c : Get network statistics from the dlpi device * + * On 10.20 only get a mib_ifEntry, on 11.0 this is followed * + * by an mib_Dot3StatsEntry. Accessing the latter structure * + * is left as an exercise for the reader, the struct is defined * + * in /usr/include/sys/mib.h along with mib_ifEntry. * + * * + * Author: Jon Dewis, SPP 3/26/98 * + * (With ackn to 'lanadmin' source code and streams class notes) * + * * + * 24-June-1998 Add mib3 stats (AJD) when compiling * + * for 11.0 ensure HP_UX11 macro defined * + * e.g. cc -o int_stats -DHP_UX11 int_stats.c * + * 16-Dec-1999 Change to obviate need for lanscan to get * + * nmid - thus assumes any old nmid will do * + * and just iterates thru the 1st 100 possibilities * + * (MAX_NMID). Works on 10.20 and 11.0 * + * Dec 2003 Modified by Roshan Sequeira roshan.sequeira@hp.com, * + * to get network statistics for the nload port to HP-UX. * + * Original code available at * + * http://h21007.www2.hp.com/dspp/tech/tech_TechDocumentDetailPage_IDX/1,1701,2599,00.html + * * + ***************************************************************************/ + +#include "devreader-hpux.h" +#include "stringutils.h" + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stropts.h> +#include <sys/dlpi.h> +#include <sys/dlpi_ext.h> +#include <sys/mib.h> + +#include <string> +#include <list> + +using namespace std; + +#define AREA_SIZE 40000 +#define LONG_AREA_SIZE (AREA_SIZE / sizeof(u_long)) + +static u_long ctrl_area[LONG_AREA_SIZE]; /* for control messages */ +static u_long data_area[LONG_AREA_SIZE]; /* for data messages */ +static u_long ppa_area[LONG_AREA_SIZE]; /* for saving ppa area */ +static struct strbuf ctrl_buf = {AREA_SIZE, 0, (char*) ctrl_area}; +static struct strbuf data_buf = {AREA_SIZE, 0, (char*) data_area}; + +DevReaderHpux::DevReaderHpux(const string& deviceName) + : DevReader(deviceName) +{ +} + +DevReaderHpux::~DevReaderHpux() +{ +} + +list<string> DevReaderHpux::findAllDevices() +{ + list<string> devicesFound; + + dl_hp_ppa_info_t* ppa_info_temp; + dl_hp_ppa_req_t* ppa_req; + dl_hp_ppa_ack_t* ppa_ack; + dl_attach_req_t* attach_req; + + int fd = -1; + if((fd = open("/dev/dlpi", O_RDWR)) < 0) + { + perror("open /dev/dlpi"); + return devicesFound; + } + + do + { + ppa_req = (dl_hp_ppa_req_t*) ctrl_area; + ppa_ack = (dl_hp_ppa_ack_t*) ctrl_area; + + ppa_req->dl_primitive = DL_HP_PPA_REQ; + + ctrl_buf.len = sizeof(dl_hp_ppa_req_t); + if(putmsg(fd, &ctrl_buf, 0, 0) < 0) + { + perror("putmsg DL_HP_PPA_REQ"); + break; + } + + int flags = 0; + ctrl_area[0] = 0; + + if(getmsg(fd, &ctrl_buf, &data_buf, &flags) < 0) + { + perror("getmsg DL_HP_PPA_REQ"); + break; + } + + if(ppa_ack->dl_length == 0) + { + fprintf(stderr, "error: no PPAs available\n"); + break; + } + + // save all the PPA information + memcpy((u_char*) ppa_area, (u_char*) ctrl_area + ppa_ack->dl_offset, ppa_ack->dl_length); + int ppa_count = ppa_ack->dl_count; + + int count; + for(count = 0, ppa_info_temp = (dl_hp_ppa_info_t*) ppa_area; count < ppa_count; count++, ppa_info_temp++) + devicesFound.push_back(string("lan") + toString(ppa_info_temp->dl_ppa)); + + } while(0); + + close(fd); + + return devicesFound; +} + +void DevReaderHpux::readFromDevice(DataFrame& dataFrame) +{ + dl_get_statistics_req_t* get_statistics_req = (dl_get_statistics_req_t*) ctrl_area; + dl_get_statistics_ack_t* get_statistics_ack = (dl_get_statistics_ack_t*) ctrl_area; + + dl_hp_ppa_info_t ppa_info; + dl_hp_ppa_info_t* ppa_info_temp; + dl_hp_ppa_req_t* ppa_req; + dl_hp_ppa_ack_t* ppa_ack; + dl_attach_req_t* attach_req; + mib_ifEntry* mib_ptr; + + unsigned int ppa = 0; + int flags = 0, ppa_count = 0, count = 0; + + // make sure interface name begins with lan + if(m_deviceName.length() < 3 || m_deviceName.substr(0, 3) != "lan") + return; + + // get the PPA from the interface name + ppa = fromString<int>(m_deviceName.substr(3)); + if(ppa == 0 && m_deviceName != "lan0") + return; + + int fd = -1; + if((fd = open("/dev/dlpi", O_RDWR)) < 0) + { + perror("open /dev/dlpi"); + return; + } + + do + { + ppa_req = (dl_hp_ppa_req_t*) ctrl_area; + ppa_ack = (dl_hp_ppa_ack_t*) ctrl_area; + + ppa_req->dl_primitive = DL_HP_PPA_REQ; + + ctrl_buf.len = sizeof(dl_hp_ppa_req_t); + if(putmsg(fd, &ctrl_buf, 0, 0) < 0) + { + perror("putmsg DL_HP_PPA_REQ"); + break; + } + + flags = 0; + ctrl_area[0] = 0; + + if(getmsg(fd, &ctrl_buf, &data_buf, &flags) < 0) + { + perror("getmsg DL_HP_PPA_REQ"); + break; + } + + if(ppa_ack->dl_length == 0) + { + fprintf(stderr, "Error: No PPAs available\n"); + break; + } + + // save all the PPA information + memcpy((u_char*) ppa_area, (u_char*) ctrl_area + ppa_ack->dl_offset, ppa_ack->dl_length); + ppa_count = ppa_ack->dl_count; + + bool found = false; + for(count = 0, ppa_info_temp = (dl_hp_ppa_info_t*) ppa_area; count < ppa_count; count++, ppa_info_temp++) + { + if(ppa_info_temp->dl_ppa == ppa) + { + found = true; + break; + } + } + if(!found) + { + fprintf(stderr, "error: PPA %d not found\n", ppa); + break; + } + + attach_req = (dl_attach_req_t*) ctrl_area; + attach_req->dl_primitive = DL_ATTACH_REQ; + attach_req->dl_ppa = ppa; + ctrl_buf.len = sizeof(dl_attach_req_t); + if(putmsg(fd, &ctrl_buf, 0, 0) < 0) + { + perror("putmsg DL_ATTACH_REQ"); + break; + } + + ctrl_area[0] = 0; + if(getmsg(fd, &ctrl_buf, &data_buf, &flags) < 0) + { + perror("getmsg DL_ATTACH_REQ"); + break; + } + memcpy(&ppa_info, ppa_info_temp, sizeof(ppa_info)); + + get_statistics_req->dl_primitive = DL_GET_STATISTICS_REQ; + ctrl_buf.len = sizeof(dl_get_statistics_req_t); + flags = 0; + + if(putmsg(fd, &ctrl_buf, NULL, 0) < 0) + { + perror("putmsg DL_GET_STATISTICS_REQ"); + break; + } + + if(getmsg(fd, &ctrl_buf, NULL, &flags) < 0) + { + perror("getmsg DL_GET_STATISTICS_REQ"); + break; + } + if(get_statistics_ack->dl_primitive != DL_GET_STATISTICS_ACK) + fprintf(stderr, "error: wrong primitive\n"); + + mib_ptr = (mib_ifEntry*) ((u_char*) ctrl_area + get_statistics_ack->dl_stat_offset); + + dataFrame.setTotalDataIn(mib_ptr->ifInOctets); + dataFrame.setTotalDataOut(mib_ptr->ifOutOctets); + + dataFrame.setTotalPacketsIn(mib_ptr->ifInUcastPkts + mib_ptr->ifInNUcastPkts); + dataFrame.setTotalPacketsOut(mib_ptr->ifOutUcastPkts + mib_ptr->ifOutNUcastPkts); + + dataFrame.setTotalErrorsIn(mib_ptr->ifInErrors); + dataFrame.setTotalErrorsOut(mib_ptr->ifOutErrors); + + dataFrame.setTotalDropsIn(mib_ptr->ifInDiscards); + dataFrame.setTotalDropsOut(mib_ptr->ifOutDiscards); + + dataFrame.setValid(true); + + } while(0); + + close(fd); +} + diff --git a/src/devreader-hpux.h b/src/devreader-hpux.h new file mode 100644 index 0000000..ad57105 --- /dev/null +++ b/src/devreader-hpux.h @@ -0,0 +1,39 @@ +/*************************************************************************** + devreader-hpux.h + ------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef DEVREADER_HPUX_H +#define DEVREADER_HPUX_H + +#include "devreader.h" + +#include <string> +#include <list> + +class DevReaderHpux : public DevReader +{ + public: + DevReaderHpux(const std::string& deviceName); + virtual ~DevReaderHpux(); + + static std::list<std::string> findAllDevices(); + + protected: + void readFromDevice(DataFrame& dataFrame); +}; + +#endif + diff --git a/src/devreader-linux-proc.cpp b/src/devreader-linux-proc.cpp new file mode 100644 index 0000000..2d698b7 --- /dev/null +++ b/src/devreader-linux-proc.cpp @@ -0,0 +1,156 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "devreader-linux-proc.h" +#include "stringutils.h" + +#include <fstream> +#include <list> +#include <string> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +using namespace std; + +DevReaderLinuxProc::DevReaderLinuxProc(const string& deviceName) + : DevReader(deviceName) +{ +} + +DevReaderLinuxProc::~DevReaderLinuxProc() +{ +} + +bool DevReaderLinuxProc::isAvailable() +{ + struct stat procStat; + if(stat("/proc/net/dev", &procStat) < 0 || ! S_ISREG(procStat.st_mode)) + return false; + + return true; +} + +list<string> DevReaderLinuxProc::findAllDevices() +{ + list<string> interfaceNames; + + ifstream fin("/proc/net/dev"); + if(!fin.is_open()) + return interfaceNames; + + // skip the two header lines + string line; + getline(fin, line); + getline(fin, line); + + if(!fin.good()) + return interfaceNames; + + // read all remaining lines and extract the device name + while(fin.good()) + { + getline(fin, line); + if(line.empty()) + continue; + + string::size_type posEnd = line.find(':'); + if(posEnd == string::npos) + continue; + + interfaceNames.push_back(trim(line.substr(0, posEnd))); + } + + return interfaceNames; +} + +void DevReaderLinuxProc::readFromDevice(DataFrame& dataFrame) +{ + if(m_deviceName.empty()) + return; + + ifstream fin("/proc/net/dev"); + if(!fin.is_open()) + return; + + // skip the two header lines + string line; + getline(fin, line); + getline(fin, line); + + if(!fin.good()) + return; + + // search for device + while(fin.good()) + { + getline(fin, line); + if(line.empty()) + continue; + + string::size_type posEnd = line.find(':'); + if(posEnd == string::npos) + continue; + + string interfaceName = trim(line.substr(0, posEnd)); + if(interfaceName.empty()) + continue; + + // check if it is the device we want + if(m_deviceName != interfaceName) + continue; + + // read device data + unsigned long long bytesIn = 0; + unsigned long long packetsIn = 0; + unsigned long long errorsIn = 0; + unsigned long long dropsIn = 0; + unsigned long long bytesOut = 0; + unsigned long long packetsOut = 0; + unsigned long long errorsOut = 0; + unsigned long long dropsOut = 0; + unsigned long long dummy = 0; + + istringstream sin(trim(line.substr(posEnd + 1))); + + sin >> bytesIn + >> packetsIn + >> errorsIn + >> dropsIn + >> dummy + >> dummy + >> dummy + >> dummy + >> bytesOut + >> packetsOut + >> errorsOut + >> dropsOut; + + if(sin.fail()) + break; + + dataFrame.setTotalDataIn(bytesIn); + dataFrame.setTotalDataOut(bytesOut); + + dataFrame.setTotalPacketsIn(packetsIn); + dataFrame.setTotalPacketsOut(packetsOut); + + dataFrame.setTotalErrorsIn(errorsIn); + dataFrame.setTotalErrorsOut(errorsOut); + + dataFrame.setTotalDropsIn(dropsIn); + dataFrame.setTotalDropsOut(dropsOut); + + dataFrame.setValid(true); + + break; + } +} + diff --git a/src/devreader-linux-proc.h b/src/devreader-linux-proc.h new file mode 100644 index 0000000..8e8def6 --- /dev/null +++ b/src/devreader-linux-proc.h @@ -0,0 +1,41 @@ +/*************************************************************************** + devreader-linux-proc.h + ---------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef DEVREADER_LINUX_PROC_H +#define DEVREADER_LINUX_PROC_H + +#include "devreader.h" + +#include <string> +#include <list> + +class DevReaderLinuxProc : public DevReader +{ + public: + DevReaderLinuxProc(const std::string& deviceName); + virtual ~DevReaderLinuxProc(); + + static bool isAvailable(); + static std::list<std::string> findAllDevices(); + + protected: + void readFromDevice(DataFrame& dataFrame); +}; + +#endif + + diff --git a/src/devreader-linux-sys.cpp b/src/devreader-linux-sys.cpp new file mode 100644 index 0000000..2fc81fe --- /dev/null +++ b/src/devreader-linux-sys.cpp @@ -0,0 +1,110 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "devreader-linux-sys.h" + +#include <fstream> +#include <string> +#include <list> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> + +using namespace std; + +DevReaderLinuxSys::DevReaderLinuxSys(const string& deviceName) + : DevReader(deviceName) +{ +} + +DevReaderLinuxSys::~DevReaderLinuxSys() +{ +} + +bool DevReaderLinuxSys::isAvailable() +{ + struct stat sysStat; + if(stat("/sys/class/net", &sysStat) < 0 || ! S_ISDIR(sysStat.st_mode)) + return false; + + return true; +} + +list<string> DevReaderLinuxSys::findAllDevices() +{ + list<string> interfaceNames; + DIR* sysDir = opendir("/sys/class/net"); + struct dirent* sysDirEntry = 0; + + if(!sysDir) + return interfaceNames; + + while((sysDirEntry = readdir(sysDir))) + { + string interfaceName(sysDirEntry->d_name); + + if(interfaceName[0] == '.') + continue; + + interfaceNames.push_back(interfaceName); + } + + closedir(sysDir); + + return interfaceNames; +} + +void DevReaderLinuxSys::readFromDevice(DataFrame& dataFrame) +{ + string devPath = "/sys/class/net/"; + devPath += m_deviceName; + + struct stat sysStat; + if(stat(devPath.c_str(), &sysStat) < 0 || ! S_ISDIR(sysStat.st_mode)) + return; + + dataFrame.setTotalDataIn(readULongSysEntry("statistics/rx_bytes")); + dataFrame.setTotalDataOut(readULongSysEntry("statistics/tx_bytes")); + + dataFrame.setTotalPacketsIn(readULongSysEntry("statistics/rx_packets")); + dataFrame.setTotalPacketsOut(readULongSysEntry("statistics/tx_packets")); + + dataFrame.setTotalErrorsIn(readULongSysEntry("statistics/rx_errors")); + dataFrame.setTotalErrorsOut(readULongSysEntry("statistics/tx_errors")); + + dataFrame.setTotalDropsIn(readULongSysEntry("statistics/rx_dropped")); + dataFrame.setTotalDropsOut(readULongSysEntry("statistics/tx_dropped")); + + dataFrame.setValid(true); +} + +unsigned long long DevReaderLinuxSys::readULongSysEntry(const string& entry) +{ + string sysEntryPath = "/sys/class/net/"; + sysEntryPath += m_deviceName; + sysEntryPath += '/'; + sysEntryPath += entry; + + ifstream sysEntry(sysEntryPath.c_str()); + if(!sysEntry.is_open()) + return 0; + + unsigned long long num = 0; + sysEntry >> num; + if(sysEntry.fail()) + return 0; + + return num; +} + + diff --git a/src/devreader-linux-sys.h b/src/devreader-linux-sys.h new file mode 100644 index 0000000..c945516 --- /dev/null +++ b/src/devreader-linux-sys.h @@ -0,0 +1,43 @@ +/*************************************************************************** + devreader-linux-sys.h + --------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef DEVREADER_LINUX_SYS_H +#define DEVREADER_LINUX_SYS_H + +#include "devreader.h" + +#include <string> +#include <list> + +class DevReaderLinuxSys : public DevReader +{ + public: + DevReaderLinuxSys(const std::string& deviceName); + virtual ~DevReaderLinuxSys(); + + static bool isAvailable(); + static std::list<std::string> findAllDevices(); + + protected: + void readFromDevice(DataFrame& dataFrame); + + private: + unsigned long long readULongSysEntry(const std::string& entry); +}; + +#endif + diff --git a/src/devreader-linux.cpp b/src/devreader-linux.cpp new file mode 100644 index 0000000..5b6e9eb --- /dev/null +++ b/src/devreader-linux.cpp @@ -0,0 +1,33 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "devreader-linux.h" +#include "devreader-linux-proc.h" +#include "devreader-linux-sys.h" + +#include <string> +#include <list> + +using namespace std; + +bool DevReaderLinux::isAvailable() +{ + return DevReaderLinuxSys::isAvailable() || DevReaderLinuxProc::isAvailable(); +} + +list<string> DevReaderLinux::findAllDevices() +{ + if(DevReaderLinuxSys::isAvailable()) + return DevReaderLinuxSys::findAllDevices(); + else if(DevReaderLinuxProc::isAvailable()) + return DevReaderLinuxProc::findAllDevices(); + else + return list<string>(); +} + diff --git a/src/devreader-linux.h b/src/devreader-linux.h new file mode 100644 index 0000000..4fea735 --- /dev/null +++ b/src/devreader-linux.h @@ -0,0 +1,32 @@ +/*************************************************************************** + devreader-linux.h + ------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef DEVREADER_LINUX_H +#define DEVREADER_LINUX_H + +#include <string> +#include <list> + +class DevReaderLinux +{ + public: + static bool isAvailable(); + static std::list<std::string> findAllDevices(); +}; + +#endif + diff --git a/src/devreader-solaris.cpp b/src/devreader-solaris.cpp new file mode 100644 index 0000000..478b3ca --- /dev/null +++ b/src/devreader-solaris.cpp @@ -0,0 +1,101 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +/*************************************************************************** + * Solaris specific network code taken out of gkrellm * + * Copyright by Bill Wilson <bill@gkrellm.net> * + * Solaris code by Daisuke Yabuki <dxy@acm.org> * + * adapted for nload by Roland Riegel <feedback@roland-riegel.de> * + ***************************************************************************/ + +#include "devreader-solaris.h" + +#include <string.h> +#include <kstat.h> +#include <sys/socket.h> +#include <net/if.h> + +#include <string> +#include <list> + +using namespace std; + +DevReaderSolaris::DevReaderSolaris(const string& deviceName) + : DevReader(deviceName) +{ +} + +DevReaderSolaris::~DevReaderSolaris() +{ +} + +list<string> DevReaderSolaris::findAllDevices() +{ + list<string> interfaceNames; + struct if_nameindex* interfaces = if_nameindex(); + + if(!interfaces) + return interfaceNames; + + int i = 0; + while(interfaces[i].if_name) + { + interfaceNames.push_back(string(interfaces[i].if_name)); + ++i; + } + + if_freenameindex(interfaces); + + return interfaceNames; +} + +void DevReaderSolaris::readFromDevice(DataFrame& dataFrame) +{ + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + char* devName = 0; + + if(m_deviceName.empty()) + return; + + devName = (char*) malloc(m_deviceName.length() + 1); + strncpy(devName, m_deviceName.c_str(), m_deviceName.length()); + devName[m_deviceName.length()] = '\0'; + + kc = kstat_open(); + ksp = kstat_lookup(kc, NULL, -1, devName); + if(ksp && kstat_read(kc, ksp, NULL) >= 0) + { + knp = (kstat_named_t *) kstat_data_lookup(ksp, "rbytes"); + dataFrame.setTotalDataIn(knp ? knp->value.ui32 : 0); + + knp = (kstat_named_t *) kstat_data_lookup(ksp, "obytes"); + dataFrame.setTotalDataOut(knp ? knp->value.ui32 : 0); + + knp = (kstat_named_t *) kstat_data_lookup(ksp, "ipackets"); + dataFrame.setTotalPacketsIn(knp ? knp->value.ui32 : 0); + + knp = (kstat_named_t *) kstat_data_lookup(ksp, "opackets"); + dataFrame.setTotalPacketsOut(knp ? knp->value.ui32 : 0); + + knp = (kstat_named_t *) kstat_data_lookup(ksp, "ierrors"); + dataFrame.setTotalErrorsIn(knp ? knp->value.ui32 : 0); + + knp = (kstat_named_t *) kstat_data_lookup(ksp, "oerrors"); + dataFrame.setTotalErrorsOut(knp ? knp->value.ui32 : 0); + + dataFrame.setValid(true); + } + + kstat_close(kc); + free(devName); + devName = 0; +} + diff --git a/src/devreader-solaris.h b/src/devreader-solaris.h new file mode 100644 index 0000000..027c7fa --- /dev/null +++ b/src/devreader-solaris.h @@ -0,0 +1,39 @@ +/*************************************************************************** + devreader-solaris.h + ------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef DEVREADER_SOLARIS_H +#define DEVREADER_SOLARIS_H + +#include "devreader.h" + +#include <string> +#include <list> + +class DevReaderSolaris : public DevReader +{ + public: + DevReaderSolaris(const std::string& deviceName); + virtual ~DevReaderSolaris(); + + static std::list<std::string> findAllDevices(); + + protected: + void readFromDevice(DataFrame& dataFrame); +}; + +#endif + diff --git a/src/devreader.cpp b/src/devreader.cpp new file mode 100644 index 0000000..5006309 --- /dev/null +++ b/src/devreader.cpp @@ -0,0 +1,106 @@ +/*************************************************************************** + devreader.cpp + ------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "devreader.h" + +#include <config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <time.h> +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <unistd.h> + +#ifdef HAVE_SOLARIS + #include <sys/sockio.h> +#endif + +using namespace std; + +DevReader::DevReader(const string& deviceName) + : m_deviceName(deviceName) +{ +} + +DevReader::~DevReader() +{ +} + +const string& DevReader::getDeviceName() const +{ + return m_deviceName; +} + +DataFrame DevReader::getNewDataFrame() +{ + DataFrame deviceData; + + struct timeval tv; + gettimeofday(&tv, 0); + + readFromDevice(deviceData); + + deviceData.setDeviceName(m_deviceName); + + deviceData.setTimeStampSeconds((unsigned long) tv.tv_sec); + deviceData.setTimeStampMicroseconds((unsigned long) tv.tv_usec); + + deviceData.setIpV4(getDeviceIp4Address()); + + return deviceData; +} + +string DevReader::getDeviceIp4Address() +{ + struct ifreq ifr; + int sk; + + string deviceIp = ""; + + if(m_deviceName.empty()) + return deviceIp; + + /* create a temporary socket: ioctl needs one */ + if((sk = socket(AF_INET, SOCK_STREAM, 0)) < 0) + return deviceIp; + + /* copy the device name into the ifreq structure */ + strncpy(ifr.ifr_name, m_deviceName.c_str(), IFNAMSIZ - 1); + ifr.ifr_name[IFNAMSIZ - 1] = 0; + + /* make the request */ + if(!ioctl(sk, SIOCGIFADDR, &ifr)) + { + struct sockaddr_in sin; + memcpy(&sin, &ifr.ifr_addr, sizeof(sin)); + + /* only use the IP number if the address family is really IPv4 */ + if(sin.sin_family == AF_INET) + deviceIp = inet_ntoa(sin.sin_addr); + } + + /* close the temporary socket */ + close(sk); + + return deviceIp; +} + diff --git a/src/devreader.h b/src/devreader.h new file mode 100644 index 0000000..c4631ce --- /dev/null +++ b/src/devreader.h @@ -0,0 +1,42 @@ +/*************************************************************************** + devreader.h + ------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef DEVREADER_H +#define DEVREADER_H + +#include <string> + +#include "dataframe.h" + +class DevReader +{ + public: + DevReader(const std::string& deviceName); + virtual ~DevReader(); + + const std::string& getDeviceName() const; + DataFrame getNewDataFrame(); + + protected: + virtual void readFromDevice(DataFrame& dataFrame) = 0; + std::string getDeviceIp4Address(); + + std::string m_deviceName; +}; + +#endif + diff --git a/src/devreaderfactory.cpp b/src/devreaderfactory.cpp new file mode 100644 index 0000000..c2fc656 --- /dev/null +++ b/src/devreaderfactory.cpp @@ -0,0 +1,128 @@ +/*************************************************************************** + devreaderfactory.cpp + -------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "devreaderfactory.h" + +#include "config.h" + +#include "devreader.h" +#include "devreader-bsd.h" +#include "devreader-hpux.h" +#include "devreader-linux-proc.h" +#include "devreader-linux-sys.h" +#include "devreader-linux.h" +#include "devreader-solaris.h" + +#include <string> +#include <list> +#include <map> + +using namespace std; + +map<string, DevReader*> DevReaderFactory::m_devReaders; +DevReaderFactory DevReaderFactory::m_instance; + +DevReaderFactory::DevReaderFactory() +{ +} + +DevReaderFactory::~DevReaderFactory() +{ + for(map<string, DevReader*>::const_iterator it = m_devReaders.begin(); it != m_devReaders.end(); ++it) + delete it->second; + + m_devReaders.clear(); +} + +int DevReaderFactory::findAllDevices() +{ +#if defined HAVE_BSD + list<string> interfaceNames = DevReaderBsd::findAllDevices(); +#elif defined HAVE_HPUX + list<string> interfaceNames = DevReaderHpux::findAllDevices(); +#elif defined HAVE_LINUX + list<string> interfaceNames = DevReaderLinux::findAllDevices(); +#elif defined HAVE_SOLARIS + list<string> interfaceNames = DevReaderSolaris::findAllDevices(); +#endif + + map<string, DevReader*>::iterator devReaderIt = m_devReaders.begin(); + while(devReaderIt != m_devReaders.end()) + { + list<string>::iterator interfaceIt = interfaceNames.begin(); + list<string>::iterator interfaceItEnd = interfaceNames.end(); + + while(*interfaceIt != devReaderIt->first && interfaceIt != interfaceItEnd) + ++interfaceIt; + + // delete all devices which disappeared + if(interfaceIt == interfaceItEnd) + { + delete devReaderIt->second; + m_devReaders.erase(devReaderIt++); + } + // delete all entries in the interface name list which we know of already + else + { + interfaceNames.erase(interfaceIt); + devReaderIt++; + } + } + + // the interface name list now contains only devices which just appeared in the system + for(list<string>::const_iterator it = interfaceNames.begin(); it != interfaceNames.end(); ++it) + { + DevReader* newReader = createDevReader(*it); + if(newReader) + m_devReaders[*it] = newReader; + } + + return m_devReaders.size(); +} + +int DevReaderFactory::getDeviceCount() +{ + return m_devReaders.size(); +} + +const map<string, DevReader*>& DevReaderFactory::getAllDevReaders() +{ + return m_devReaders; +} + +DevReader* DevReaderFactory::createDevReader(const string& deviceName) +{ + DevReader* reader = 0; + +#if defined HAVE_BSD + reader = new DevReaderBsd(deviceName); +#elif defined HAVE_HPUX + reader = new DevReaderHpux(deviceName); +#elif defined HAVE_LINUX + if(DevReaderLinuxSys::isAvailable()) + reader = new DevReaderLinuxSys(deviceName); + else if(DevReaderLinuxProc::isAvailable()) + reader = new DevReaderLinuxProc(deviceName); + else + reader = 0; +#elif defined HAVE_SOLARIS + reader = new DevReaderSolaris(deviceName); +#endif + + return reader; +} + diff --git a/src/devreaderfactory.h b/src/devreaderfactory.h new file mode 100644 index 0000000..d9d2e5c --- /dev/null +++ b/src/devreaderfactory.h @@ -0,0 +1,45 @@ +/*************************************************************************** + devreaderfactory.h + ------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef DEVREADERFACTORY_H +#define DEVREADERFACTORY_H + +#include <string> +#include <map> + +class DevReader; + +class DevReaderFactory +{ + public: + DevReaderFactory(); + ~DevReaderFactory(); + + static int findAllDevices(); + static int getDeviceCount(); + + static const std::map<std::string, DevReader*>& getAllDevReaders(); + + private: + static DevReader* createDevReader(const std::string& deviceName); + + static std::map<std::string, DevReader*> m_devReaders; + static DevReaderFactory m_instance; +}; + +#endif + diff --git a/src/form_field.cpp b/src/form_field.cpp new file mode 100644 index 0000000..03b70f7 --- /dev/null +++ b/src/form_field.cpp @@ -0,0 +1,237 @@ +/*************************************************************************** + form_field.cpp + ------------------- + begin : Tue Jul 30 2002 + copyright : (C) 2002 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "form_field.h" +#include "window.h" + +using namespace std; + +Field::Field(int x, int y, int width, int height) : m_field(0) +{ + m_field = new_field(height, width, y, x, 0, 0); + set_field_opts(m_field, field_opts(m_field) | O_BLANK | O_PASSOK); + + m_enumElementsArray = 0; +} + +Field::~Field() +{ + setEnumField(vector<string>()); + free_field(m_field); +} + +void Field::setText(const string& text) +{ + set_field_buffer(m_field, 0, text.c_str()); +} + +string Field::getText() +{ + return field_buffer(m_field, 0); +} + +void Field::move(int x, int y) +{ + move_field(m_field, y, x); +} + +void Field::setVisible(bool new_visible) +{ + set_field_opts(m_field, new_visible ? field_opts(m_field) | O_VISIBLE : field_opts(m_field) & ~O_VISIBLE); +} + +bool Field::isVisible() +{ + return (field_opts(m_field) & O_VISIBLE) == O_VISIBLE; +} + +void Field::setEnabled(bool new_enabled) +{ + set_field_opts(m_field, new_enabled ? field_opts(m_field) | O_ACTIVE : field_opts(m_field) & ~O_ACTIVE); +} + +bool Field::isEnabled() +{ + return (field_opts(m_field) & O_ACTIVE) == O_ACTIVE; +} + +void Field::setIntegerField(int min, int max) +{ + set_field_type(m_field, TYPE_INTEGER, 0, min, max); +} + +void Field::setEnumField(const vector<string>& elements) +{ + if(elements.empty()) + { + set_field_type(m_field, TYPE_ALNUM, 0); + + if(m_enumElementsArray) + delete[] m_enumElementsArray; + m_enumElementsArray = 0; + + m_enumElements.clear(); + + return; + } + + m_enumElements = elements; + + if(m_enumElementsArray) + delete[] m_enumElementsArray; + m_enumElementsArray = new const char*[m_enumElements.size() + 1]; + + for(vector<string>::const_iterator itElement = m_enumElements.begin(); itElement != m_enumElements.end(); ++itElement) + m_enumElementsArray[itElement - m_enumElements.begin()] = itElement->c_str(); + m_enumElementsArray[elements.size()] = 0; + + set_field_type(m_field, TYPE_ENUM, m_enumElementsArray, 0, 0); +} + +void Field::setFixed(bool new_fixed) +{ + set_field_opts(m_field, new_fixed ? field_opts(m_field) & ~O_EDIT : field_opts(m_field) | O_EDIT); +} + +bool Field::isFixed() +{ + return (field_opts(m_field) & O_EDIT) != O_EDIT; +} + +void Field::setFirstOnPage(bool new_newpage) +{ + set_new_page(m_field, new_newpage); +} + +bool Field::isFirstOnPage() +{ + return new_page(m_field); +} + +bool operator==(const Field& field1, const Field& field2) +{ + return field1.m_field == field2.m_field; +} + +bool operator==(const Field& field1, const FIELD* field2) +{ + return field1.m_field == field2; +} + + +Form::Form(Slots* slots) + : m_slots(slots), m_form(0), m_visible(false) +{ +} + +Form::~Form() +{ +} + +vector<Field*>& Form::fields() +{ + return m_fields; +} + +void Form::show(Window* main_window, SubWindow* sub_window) +{ + if(m_form) + return; + + m_curses_fields = new FIELD* [ m_fields.size() ]; + vector<Field*>::const_iterator r = m_fields.begin(); + int i = 0; + while(r != m_fields.end()) + { + m_curses_fields[i] = (*r)->m_field; + r++; i++; + } + + m_curses_fields[m_fields.size()] = 0; + m_form = new_form(m_curses_fields); + + if(!m_form) + return; + + set_form_userptr(m_form, this); + set_form_win(m_form, main_window->m_window); + set_form_sub(m_form, sub_window->m_window); + set_field_term(m_form, fieldChanged); + + post_form(m_form); + + m_visible = true; +} + +void Form::hide() +{ + if(!m_form) + return; + + unpost_form(m_form); + free_form(m_form); + m_form = 0; + + delete[] m_curses_fields; + m_curses_fields = 0; + + m_visible = false; +} + +bool Form::isVisible() +{ + return m_visible; +} + +void Form::processKey(int key) +{ + if(m_form) + form_driver(m_form, key); +} + +int Form::getPage() +{ + if(!m_form) + return 0; + return form_page(m_form); +} + +int Form::getPageCount() +{ + int pages = 0; + for(vector<Field*>::const_iterator i = m_fields.begin(); i != m_fields.end(); i++) + { + if((*i)->isFirstOnPage()) + pages++; + } + return pages; +} + +void Form::fieldChanged(FORM* form) +{ + Form* f = (Form*) form_userptr(form); + if(!f) + return; + + if(f->m_slots) + { + for(vector<Field*>::const_iterator i = f->m_fields.begin(); i != f->m_fields.end(); ++i) + if((*i)->m_field == current_field(form)) + f->m_slots->slot_fieldChanged(*i); + } +} + diff --git a/src/form_field.h b/src/form_field.h new file mode 100644 index 0000000..7ce2734 --- /dev/null +++ b/src/form_field.h @@ -0,0 +1,110 @@ +/*************************************************************************** + form_field.h + ------------------- + begin : Sat Jul 27 2002 + copyright : (C) 2002 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef FORM_FIELD_H +#define FORM_FIELD_H + +#include <curses.h> +#include <form.h> +#undef clear +#undef erase +#undef refresh + +#include <string> +#include <vector> + +class Window; +class SubWindow; +class Form; + +class Field +{ + public: + Field(int x, int y, int width, int height); + ~Field(); + + void setText(const std::string& text); + std::string getText(); + + void move(int x, int y); + + void setVisible(bool new_visible); + bool isVisible(); + + void setEnabled(bool new_enabled); + bool isEnabled(); + + void setIntegerField(int min, int max); + void setEnumField(const std::vector<std::string>& elements); + + void setFixed(bool new_fixed); + bool isFixed(); + + void setFirstOnPage(bool new_newpage); + bool isFirstOnPage(); + + friend bool operator==(const Field& field1, const Field& field2); + friend bool operator==(const Field& field1, const FIELD* field2); + + private: + friend class Form; + + FIELD* m_field; + std::vector<std::string> m_enumElements; + const char** m_enumElementsArray; +}; + +class Form +{ + public: + class Slots + { + public: + Slots() {} + virtual ~Slots() {} + virtual void slot_fieldChanged(Field* field) {} + }; + + Form(Slots* slots = 0); + ~Form(); + + std::vector<Field *>& fields(); + + void show(Window* main_window, SubWindow* sub_window); + void hide(); + + void processKey(int key); + + bool isVisible(); + + int getPage(); + int getPageCount(); + + private: + Slots* m_slots; + + FORM* m_form; + FIELD** m_curses_fields; + std::vector<Field *> m_fields; + + bool m_visible; + + static void fieldChanged(FORM* form); +}; + +#endif + diff --git a/src/graph.cpp b/src/graph.cpp new file mode 100644 index 0000000..f0b4e8b --- /dev/null +++ b/src/graph.cpp @@ -0,0 +1,110 @@ +/*************************************************************************** + graph.cpp + ------------------- + begin : Sat Sep 29 2001 + copyright : (C) 2001 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "graph.h" +#include "setting.h" +#include "settingstore.h" +#include "window.h" + +using namespace std; + +Graph::Graph() + : m_heightOfBars(5), m_maxDeflection(10 * 1024 * 1024 / 8) +{ +} + +Graph::~Graph() +{ +} + +// sets the number of the graph's vertical #-bars +void Graph::setNumOfBars(unsigned int numOfBars) +{ + // vertically resize the graph's value list + m_values.resize(numOfBars); +} + +// sets the height of the graph's vertical #-bars +void Graph::setHeightOfBars(unsigned int heightOfBars) +{ + m_heightOfBars = heightOfBars; +} + +void Graph::setMaxDeflection(unsigned long long maxDeflection) +{ + m_maxDeflection = maxDeflection; +} + +// new traffic measurement has been made => update the graph's value list +void Graph::update(unsigned long long value) +{ + // [new_value] = Bytes/s + + // put new value to the beginning of the list, it becomes the first #-bar + m_values.push_front(value); + + // delete the last #-bar of the list, but keep at least one + if(m_values.size() > 1) + m_values.pop_back(); +} + +// print the graph with the upper left corner at the coordinates (x, y) +void Graph::print(Window& window, int x, int y) +{ + window.setXY(x, y); + + // cycle through through the lines + for(unsigned int l = 0; l < m_heightOfBars; l++) + { + // for each line cycle through the rows + for(list<unsigned long long>::reverse_iterator r = m_values.rbegin(); r != m_values.rend() ; r++) + { + unsigned long long trafficPerLine = m_maxDeflection / m_heightOfBars; + unsigned long long lowerLimit = m_maxDeflection * (m_heightOfBars - l - 1) / m_heightOfBars; + + if(*r < lowerLimit) + { + window.print(' '); + } + else + { + unsigned long long restOfTraffic = *r - lowerLimit; + + if(restOfTraffic >= trafficPerLine) + window.print('#'); + else if(restOfTraffic >= trafficPerLine * 7 / 10) + window.print('|'); + else if(restOfTraffic >= trafficPerLine * 3 / 10) + window.print('.'); + else + window.print(' '); + } + } + window.print('\n'); + window.setX(x); + } + +} + +// reset all traffic values in the graph to zero +void Graph::resetTrafficData() +{ + int size = m_values.size(); + m_values.clear(); + m_values.resize(size); +} + diff --git a/src/graph.h b/src/graph.h new file mode 100644 index 0000000..1e493b3 --- /dev/null +++ b/src/graph.h @@ -0,0 +1,45 @@ +/*************************************************************************** + graph.h + ------------------- + begin : Sat Sep 29 2001 + copyright : (C) 2001 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef GRAPH_H +#define GRAPH_H + +#include <list> + +class Window; + +class Graph +{ + public: + Graph(); + ~Graph(); + + void setNumOfBars(unsigned int numOfBars); + void setHeightOfBars(unsigned int heightOfBars); + void setMaxDeflection(unsigned long long maxDeflection); + + void update(unsigned long long value); + void print(Window& window, int x, int y); + void resetTrafficData(); + + private: + unsigned int m_heightOfBars; + unsigned long long m_maxDeflection; + std::list<unsigned long long> m_values; +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..c53e142 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,583 @@ +/*************************************************************************** + main.cpp + ------------------- + begin : Wed Jul 25 2001 + copyright : (C) 2001 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +/* + * nload + * real time monitor for network traffic + * Copyright (C) 2001 - 2012 Roland Riegel <feedback@roland-riegel.de> + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include "device.h" +#include "devreader.h" +#include "devreaderfactory.h" +#include "graph.h" +#include "main.h" +#include "screen.h" +#include "setting.h" +#include "settingfilter.h" +#include "settingstore.h" + +#include <cstdlib> +#include <iostream> +#include <string> +#include <vector> + +#include <ctype.h> +#include <time.h> +#include <curses.h> +#include <signal.h> +#include <string.h> +#undef clear +#undef erase +#undef refresh + +#define STANDARD_AVERAGE_WINDOW 300 +#define STANDARD_DATA_FORMAT Statistics::humanReadableByte +#define STANDARD_HIDE_GRAPHS false +#define STANDARD_MAX_DEFLECTION 10240 +#define STANDARD_REFRESH_INTERVAL 500 +#define STANDARD_TRAFFIC_FORMAT Statistics::humanReadableBit + +using namespace std; + +static OptWindow m_optWindow; +static TrafficWindow m_mainWindow; + +static bool quit = false; + +int main(int argc, char *argv[]) +{ + SettingStore::add(Setting("AverageWindow", "Window length for average (s)", STANDARD_AVERAGE_WINDOW)); + SettingStore::add(Setting("BarMaxIn", "Max Incoming deflection (kBit/s)", STANDARD_MAX_DEFLECTION)); + SettingStore::add(Setting("BarMaxOut", "Max Outgoing deflection (kBit/s)", STANDARD_MAX_DEFLECTION)); + SettingStore::add(Setting("DataFormat", "Unit for data numbers", STANDARD_DATA_FORMAT)); + SettingStore::add(Setting("Devices", "Devices to show", "all")); + SettingStore::add(Setting("MultipleDevices", "Show multiple devices", STANDARD_HIDE_GRAPHS)); + SettingStore::add(Setting("RefreshInterval", "Refresh interval (ms)", STANDARD_REFRESH_INTERVAL)); + SettingStore::add(Setting("TrafficFormat", "Unit for traffic numbers", STANDARD_TRAFFIC_FORMAT)); + + SettingStore::get("AverageWindow").pushFilter(new SettingFilterMin(5)); + SettingStore::get("BarMaxIn").pushFilter(new SettingFilterMin(10)); + SettingStore::get("BarMaxOut").pushFilter(new SettingFilterMin(10)); + SettingStore::get("RefreshInterval").pushFilter(new SettingFilterMin(50)); + + SettingStore::get("Devices").pushFilter(new SettingFilterDefault("all")); + SettingStore::get("Devices").pushFilter(new SettingFilterExclusive("all")); + + map<string, string> valueMapping; + + valueMapping[toString(false)] = "[ ]"; + valueMapping[toString(true)] = "[x]"; + SettingStore::get("MultipleDevices").pushFilter(new SettingFilterMap(valueMapping)); + valueMapping.clear(); + + valueMapping[toString(Statistics::humanReadableBit)] = "Human Readable (Bit)"; + valueMapping[toString(Statistics::humanReadableByte)] = "Human Readable (Byte)"; + valueMapping[toString(Statistics::bit)] = "Bit"; + valueMapping[toString(Statistics::byte)] = "Byte"; + valueMapping[toString(Statistics::kiloBit)] = "kBit"; + valueMapping[toString(Statistics::kiloByte)] = "kByte"; + valueMapping[toString(Statistics::megaBit)] = "MBit"; + valueMapping[toString(Statistics::megaByte)] = "MByte"; + valueMapping[toString(Statistics::gigaBit)] = "GBit"; + valueMapping[toString(Statistics::gigaByte)] = "GByte"; + SettingStore::get("TrafficFormat").pushFilter(new SettingFilterMap(valueMapping)); + SettingStore::get("DataFormat").pushFilter(new SettingFilterMap(valueMapping)); + valueMapping.clear(); + + // retrieve home directory + const char* homeDirArray = getenv("HOME"); + if(!homeDirArray) + { + cerr << "Could not retrieve home directory." << endl; + exit(1); + } + + string homeDir = homeDirArray; + SettingStore::readFromFile(SYSCONFDIR "/nload.conf"); + SettingStore::readFromFile(homeDir + "/.nload"); + + // parse the command line + bool deleteDevicesRequested = true; + for(int i = 1; i < argc; i++) + { + // does the user want help? + if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) + { + printHelp(false); + exit(0); + } + // has the user set a non-default average time window? + else if(strcmp(argv[i], "-a") == 0) + { + Setting& setting = SettingStore::get("AverageWindow"); + + if(i < argc - 1 && isdigit(argv[ i + 1 ][0]) != 0) + { + setting = atoi(argv[ i + 1 ]); + if(setting < 1) + setting = STANDARD_AVERAGE_WINDOW; + + i++; + } + else + { + cerr << "Wrong argument for the -a parameter." << endl; + printHelp(true); + exit(1); + } + } + // has the user set a non-default 100% mark for + // the incoming bandwidth bar? + else if(strcmp(argv[i], "-i") == 0) + { + Setting& setting = SettingStore::get("BarMaxIn"); + + if(i < argc - 1 && isdigit(argv[ i + 1 ][0]) != 0) + { + setting = atol(argv[ i + 1 ]); + if(setting == 0) + setting = STANDARD_MAX_DEFLECTION; + + i++; + } + else + { + cerr << "Wrong argument for the -i parameter." << endl; + printHelp(true); + exit(1); + } + } + // has the user set a non-default 100% mark for + // the outgoing bandwidth bar? + else if(strcmp(argv[i], "-o") == 0) + { + Setting& setting = SettingStore::get("BarMaxOut"); + + if(i < argc - 1 && isdigit(argv[ i + 1 ][0]) != 0) + { + setting = atol(argv[ i + 1 ]); + if(setting == 0) + setting = STANDARD_MAX_DEFLECTION; + + i++; + } + else + { + cerr << "Wrong argument for the -o parameter." << endl; + printHelp(true); + exit(1); + } + } + // has the user set a non-default refresh interval? + else if(strcmp(argv[i], "-t") == 0) + { + Setting& setting = SettingStore::get("RefreshInterval"); + + if(i < argc - 1 && isdigit(argv[ i + 1 ][0]) != 0) + { + setting = atoi(argv[ i + 1 ]); + if(setting == 0) + setting = STANDARD_REFRESH_INTERVAL; + + i++; + } + else + { + cerr << "Wrong argument for the -t parameter." << endl; + printHelp(true); + exit(1); + } + } + // has the user set a non-default unit for traffic numbers? + else if(strcmp(argv[i], "-u") == 0) + { + Setting& setting = SettingStore::get("TrafficFormat"); + + if(i < argc - 1 && isalpha(argv[ i + 1 ][0]) != 0) + { + switch(argv[ i + 1 ][0]) + { + case 'H': + setting = Statistics::humanReadableByte; + break; + case 'h': + setting = Statistics::humanReadableBit; + break; + case 'B': + setting = Statistics::byte; + break; + case 'b': + setting = Statistics::bit; + break; + case 'K': + setting = Statistics::kiloByte; + break; + case 'k': + setting = Statistics::kiloBit; + break; + case 'M': + setting = Statistics::megaByte; + break; + case 'm': + setting = Statistics::megaBit; + break; + case 'G': + setting = Statistics::gigaByte; + break; + case 'g': + setting = Statistics::gigaBit; + break; + default: + cerr << "Wrong argument for the -u parameter." << endl; + printHelp(true); + exit(1); + } + + i++; + } + else + { + cerr << "Wrong argument for the -u parameter." << endl; + printHelp(true); + exit(1); + } + } + // has the user set a non-default unit for numbers of amount of data? + else if(strcmp(argv[i], "-U") == 0) + { + Setting& setting = SettingStore::get("DataFormat"); + + if(i < argc - 1 && isalpha(argv[ i + 1 ][0]) != 0) + { + switch(argv[ i + 1 ][0]) + { + case 'H': + setting = Statistics::humanReadableByte; + break; + case 'h': + setting = Statistics::humanReadableBit; + break; + case 'B': + setting = Statistics::byte; + break; + case 'b': + setting = Statistics::bit; + break; + case 'K': + setting = Statistics::kiloByte; + break; + case 'k': + setting = Statistics::kiloBit; + break; + case 'M': + setting = Statistics::megaByte; + break; + case 'm': + setting = Statistics::megaBit; + break; + case 'G': + setting = Statistics::gigaByte; + break; + case 'g': + setting = Statistics::gigaBit; + break; + default: + cerr << "Wrong argument for the -U parameter." << endl; + printHelp(true); + exit(1); + } + + i++; + } + else + { + cerr << "Wrong argument for the -U parameter." << endl; + printHelp(true); + exit(1); + } + + } + // has the user chosen to display multiple devices and thus not to display graphs? + else if(strcmp(argv[i], "-m") == 0) + { + SettingStore::get("MultipleDevices") = true; + } + // obsolete -b option + else if(strcmp(argv[i], "-b") == 0) + { + } + // obsolete -s option + else if(strcmp(argv[i], "-s") == 0) + { + } + // assume unknown parameter to be the network device + else + { + Setting& devices = SettingStore::get("Devices"); + + if(deleteDevicesRequested) + { + devices = ""; + deleteDevicesRequested = false; + } + + devices.setThroughFilter(trim(devices.getThroughFilter() + " " + argv[i])); + } + } + + // auto-detect network devices + DevReaderFactory::findAllDevices(); + const map<string, DevReader*>& deviceReaders = DevReaderFactory::getAllDevReaders(); + + // create one instance of the Device class per device + map<string, Device*> deviceHandlers; + for(map<string, DevReader*>::const_iterator itDevice = deviceReaders.begin(); itDevice != deviceReaders.end(); ++itDevice) + { + Device* device = new Device(*itDevice->second); + device->update(); + + deviceHandlers[itDevice->first] = device; + } + + init(); + + while(!quit) + { + // wait RefreshInterval milliseconds (in steps of 100 ms) + struct timespec wantedTime; + wantedTime.tv_sec = 0; + + int restOfRefreshInterval = SettingStore::get("RefreshInterval"); + + while(restOfRefreshInterval > 0 && !quit) + { + restOfRefreshInterval -= 100; + wantedTime.tv_nsec = (restOfRefreshInterval >= 0 ? 100 : 100 + restOfRefreshInterval) * 1000000L; + + nanosleep(&wantedTime, 0); + + // process keyboard + int key; + while((key = getch()) != ERR) + { + if(m_optWindow.isVisible()) + { + if(key == KEY_F(2)) + { + m_optWindow.hide(); + m_mainWindow.resize(0, 0, Screen::width(), Screen::height()); + restOfRefreshInterval = 0; // update the screen + } + else + { + m_optWindow.processKey(key); + } + } + else + { + switch(key) + { + case KEY_F(2): + m_mainWindow.resize(0, Screen::height() / 4, Screen::width(), Screen::height() - Screen::height() / 4); + m_optWindow.show(0, 0, Screen::width(), Screen::height() / 4); + restOfRefreshInterval = 0; // update the screen + break; + case KEY_F(5): + SettingStore::writeToFile(homeDir + "/.nload"); + break; + case KEY_F(6): + SettingStore::readFromFile("/etc/nload.conf"); + SettingStore::readFromFile(homeDir + "/.nload"); + break; + case 'q': + case 'Q': + quit = true; + break; + default: + m_mainWindow.processKey(key); + } + } + } + } + + if(quit) + break; + + vector<string> devicesRequested = split(trim(SettingStore::get("Devices").getThroughFilter()), " "); + vector<Device*> devicesToShow; + + if(!devicesRequested.empty() && devicesRequested.front() != "all") + { + // check if requested devices are available + for(vector<string>::const_iterator itRequested = devicesRequested.begin(); itRequested != devicesRequested.end(); ++itRequested) + { + map<string, Device*>::const_iterator itDetectedDevice = deviceHandlers.find(*itRequested); + if(itDetectedDevice != deviceHandlers.end()) + devicesToShow.push_back(itDetectedDevice->second); + } + } + + if(devicesToShow.empty()) + { + // use all detected devices + for(map<string, Device*>::const_iterator itDevice = deviceHandlers.begin(); itDevice != deviceHandlers.end(); ++itDevice) + devicesToShow.push_back(itDevice->second); + } + + // enumerate devices for display + unsigned int deviceIndex = 0; + for(vector<Device*>::const_iterator itDevice = devicesToShow.begin(); itDevice != devicesToShow.end(); ++itDevice) + { + (*itDevice)->setDeviceNumber(deviceIndex++); + (*itDevice)->setTotalNumberOfDevices(devicesToShow.size()); + } + + // update all devices + for(map<string, Device*>::const_iterator itDevice = deviceHandlers.begin(); itDevice != deviceHandlers.end(); ++itDevice) + itDevice->second->update(); + + // clear the screen + m_mainWindow.clear(); + + // print device data + m_mainWindow.printTraffic(devicesToShow); + + // refresh the screen + m_mainWindow.refresh(); + + if(m_optWindow.isVisible()) + m_optWindow.refresh(); // always show cursor in option dialog + + } + + finish(); + + for(map<string, Device*>::const_iterator itDevice = deviceHandlers.begin(); itDevice != deviceHandlers.end(); ++itDevice) + delete itDevice->second; + deviceHandlers.clear(); + + return 0; +} + +void init() +{ + // handle interrrupt signal + signal(SIGINT, end); + signal(SIGTERM, end); + signal(SIGWINCH, terminalResized); + + // initialize ncurses + initscr(); + keypad(stdscr, true); + nodelay(stdscr, true); + noecho(); + nonl(); + cbreak(); + + // create main window + m_mainWindow.show(0, 0, Screen::width(), Screen::height()); +} + +void finish() +{ + // destroy main window + m_mainWindow.hide(); + + // stop ncurses + endwin(); +} + +void end(int signal) +{ + quit = true; +} + +void terminalResized(int signal) +{ + bool optWindowWasVisible = m_optWindow.isVisible(); + + m_optWindow.hide(); + + finish(); + init(); + + if(optWindowWasVisible) + { + m_mainWindow.resize(0, Screen::height() / 4, Screen::width(), Screen::height() - Screen::height() / 4); + m_optWindow.show(0, 0, Screen::width(), Screen::height() / 4); + } +} + +void printHelp(bool error) +{ + // print disclaimer + (error ? cerr : cout) + << "\n" + << PACKAGE << " version " << VERSION << "\n" + << "Copyright (C) 2001 - 2012 by Roland Riegel <feedback@roland-riegel.de>\n" + << PACKAGE << " comes with ABSOLUTELY NO WARRANTY. This is free software, and you are\n" + << "welcome to redistribute it under certain conditions. For more details see the\n" + << "GNU General Public License Version 2 (http://www.gnu.org/copyleft/gpl.html).\n\n" + + << "Command line syntax:\n" + << PACKAGE << " [options] [devices]\n" + << PACKAGE << " --help|-h\n\n" + + << "Options:\n" + << "-a period Sets the length in seconds of the time window for average\n" + << " calculation.\n" + << " Default is " << STANDARD_AVERAGE_WINDOW << ".\n" + << "-i max_scaling Specifies the 100% mark in kBit/s of the graph indicating the\n" + << " incoming bandwidth usage. Ignored if max_scaling is 0 or the\n" + << " switch -m is given.\n" + << " Default is " << STANDARD_MAX_DEFLECTION << ".\n" + << "-m Show multiple devices at a time; no traffic graphs.\n" + << "-o max_scaling Same as -i but for the graph indicating the outgoing bandwidth\n" + << " usage.\n" + << " Default is " << STANDARD_MAX_DEFLECTION << ".\n" + << "-t interval Determines the refresh interval of the display in milliseconds.\n" + << " Default is " << STANDARD_REFRESH_INTERVAL << ".\n" + << "-u h|b|k|m|g Sets the type of unit used for the display of traffic numbers.\n" + << " H|B|K|M|G h: auto, b: Bit/s, k: kBit/s, m: MBit/s etc.\n" + << " H: auto, B: Byte/s, K: kByte/s, M: MByte/s etc.\n" + << " Default is h.\n" + << "-U h|b|k|m|g Same as -u, but for a total amount of data (without \"/s\").\n" + << " H|B|K|M|G Default is H.\n" + << "devices Network devices to use.\n" + << " Default is to use all auto-detected devices.\n" + << "--help\n" + << "-h Print this help.\n\n" + + << "example: " << PACKAGE << " -t 200 -i 1024 -o 128 -U M\n\n" + + << "The options above can also be changed at run time by pressing the 'F2' key.\n" + << endl; +} + diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..e92e878 --- /dev/null +++ b/src/main.h @@ -0,0 +1,34 @@ +/*************************************************************************** + main.h + ------------------- + begin : Wed Jul 25 2001 + copyright : (C) 2001 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef MAIN_H +#define MAIN_H + +#include "traffic_window.h" +#include "opt_window.h" + +int main(int argc, char *argv[]); + +void init(); +void finish(); +void end(int signal = 0); +void terminalResized(int signal); + +void printHelp(bool error); + +#endif + diff --git a/src/opt_window.cpp b/src/opt_window.cpp new file mode 100644 index 0000000..b8e1a9a --- /dev/null +++ b/src/opt_window.cpp @@ -0,0 +1,193 @@ +/*************************************************************************** + opt_window.cpp + ------------------- + begin : Thu Jan 17 2002 + copyright : (C) 2002 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "opt_window.h" +#include "setting.h" +#include "settingfilter.h" +#include "settingstore.h" +#include "stringutils.h" + +#define BORDER_LEFT 1 +#define BORDER_RIGHT 1 +#define BORDER_TOP 2 +#define BORDER_BOTTOM 1 + +using namespace std; + +OptWindow::OptWindow() + : Window(), Form::Slots(), m_subWindow(this), m_form(this) +{ +} + +OptWindow::~OptWindow() +{ + hide(); +} + +// create option window and display the current settings +void OptWindow::show(int x, int y, int width, int height) +{ + if(m_visible) + hide(); + + Window::show(x, y, width, height); + m_subWindow.show(BORDER_LEFT, BORDER_TOP, width - BORDER_LEFT - BORDER_RIGHT, height - BORDER_TOP - BORDER_BOTTOM); + + const int field_width = m_subWindow.getWidth() / 2; + int line = 0; + + map<string, Setting>& settings = SettingStore::getAll(); + + for(map<string, Setting>::const_iterator itSetting = settings.begin(); itSetting != settings.end(); ++itSetting) + { + Field* label = new Field(0, line, field_width, 1); + Field* field = new Field(field_width, line, field_width, 1); + + m_labels[label] = itSetting->first; + m_fields[field] = itSetting->first; + + m_form.fields().push_back(label); + m_form.fields().push_back(field); + + label->setEnabled(false); + label->setText((itSetting->second.getDescription() + ":").c_str()); + label->setFirstOnPage(line == 0); + + field->setText(itSetting->second.getThroughFilter().c_str()); + + const SettingFilterMap* mappingFilter = (SettingFilterMap*) itSetting->second.findFilterWithId("map"); + if(mappingFilter) + { + const map<string, string>& mapping = mappingFilter->getMap(); + + vector<string> elements; + for(map<string, string>::const_iterator itMapping = mapping.begin(); itMapping != mapping.end(); ++itMapping) + elements.push_back(itMapping->second); + + field->setEnumField(elements); + field->setFixed(true); + } + + ++line; + line %= m_subWindow.getHeight() < 1 ? 1 : m_subWindow.getHeight(); + } + + m_form.show(this, &m_subWindow); + + m_visible = true; +} + +// this function is called when a form field changes +void OptWindow::slot_fieldChanged(Field* field) +{ + map<Field*, string>::const_iterator itField = m_fields.find(field); + if(itField == m_fields.end()) + return; + + map<string, Setting>& settings = SettingStore::getAll(); + map<string, Setting>::iterator itSetting = settings.find(itField->second); + if(itSetting == settings.end()) + return; + + itSetting->second.setThroughFilter(trim(field->getText())); + field->setText(itSetting->second.getThroughFilter()); +} + +// hide window and destroy it +void OptWindow::hide() +{ + m_form.hide(); + m_form.fields().clear(); + m_subWindow.hide(); + Window::hide(); + + for(map<Field*, string>::const_iterator itLabel = m_labels.begin(); itLabel != m_labels.end(); ++itLabel) + delete itLabel->first; + for(map<Field*, string>::const_iterator itField = m_fields.begin(); itField != m_fields.end(); ++itField) + delete itField->first; + + m_labels.clear(); + m_fields.clear(); + + m_visible = false; +} + +// process key presses +void OptWindow::processKey(int request) +{ + if(m_visible) + { + switch(request) + { + case KEY_LEFT: + request = REQ_PREV_CHAR; + break; + case KEY_RIGHT: + request = REQ_NEXT_CHAR; + break; + case KEY_UP: + request = REQ_PREV_FIELD; + break; + case KEY_DOWN: + case KEY_ENTER: + case '\n': + case '\015': + request = REQ_NEXT_FIELD; + break; + case KEY_DC: + request = REQ_DEL_CHAR; + break; + case KEY_BACKSPACE: + request = REQ_DEL_PREV; + break; + case KEY_PPAGE: + request = REQ_PREV_CHOICE; + break; + case KEY_NPAGE: + case '\t': + request = REQ_NEXT_CHOICE; + break; + case KEY_HOME: + request = REQ_BEG_LINE; + break; + case KEY_END: + request = REQ_END_LINE; + break; + case '+': + request = REQ_NEXT_PAGE; + break; + case '-': + request = REQ_PREV_PAGE; + break; + } + m_form.processKey(request); + refresh(); + } +} + +void OptWindow::refresh() +{ + print(0, 0) << "Options:" << endl + << string(getWidth(), '='); + + string navigator = " <-- (-) page " + toString(m_form.getPage() + 1) + "/" + toString(m_form.getPageCount()) + " (+) --> "; + print(navigator, getWidth() - navigator.length() - 1, 1); + + wrefresh(m_window); + m_subWindow.refresh(); +} + diff --git a/src/opt_window.h b/src/opt_window.h new file mode 100644 index 0000000..01a320a --- /dev/null +++ b/src/opt_window.h @@ -0,0 +1,50 @@ +/*************************************************************************** + opt_window.h + ------------------- + begin : Thu Jan 17 2002 + copyright : (C) 2002 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef OPT_WINDOW_H +#define OPT_WINDOW_H + +#include "window.h" +#include "form_field.h" + +#include <map> +#include <string> + +class OptWindow : public Window, public Form::Slots +{ + public: + OptWindow(); + ~OptWindow(); + + void show(int x, int y, int width, int height); + void hide(); + + void refresh(); + + void processKey(int request); + void slot_fieldChanged(Field* field); + + private: + SubWindow m_subWindow; + Form m_form; + + std::map<Field*, std::string> m_labels; + std::map<Field*, std::string> m_fields; +}; + +#endif + diff --git a/src/screen.cpp b/src/screen.cpp new file mode 100644 index 0000000..05e8c00 --- /dev/null +++ b/src/screen.cpp @@ -0,0 +1,56 @@ +/*************************************************************************** + screen.cpp + ------------------- + begin : Thu Nov 25 2003 + copyright : (C) 2003 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "screen.h" + +#include <curses.h> +#undef clear +#undef erase +#undef refresh + +int Screen::width() +{ + int width; + int height; + getmaxyx(stdscr, height, width); + return width; +} + +int Screen::height() +{ + int width; + int height; + getmaxyx(stdscr, height, width); + return height; +} + +int Screen::x() +{ + int x; + int y; + getyx(stdscr, y, x); + return x; +} + +int Screen::y() +{ + int x; + int y; + getyx(stdscr, y, x); + return y; +} + diff --git a/src/screen.h b/src/screen.h new file mode 100644 index 0000000..cf502ca --- /dev/null +++ b/src/screen.h @@ -0,0 +1,32 @@ +/*************************************************************************** + screen.h + ------------------- + begin : Thu Jul 04 2002 + copyright : (C) 2002 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef SCREEN_H +#define SCREEN_H + +class Screen +{ + public: + static int width(); + static int height(); + + static int x(); + static int y(); +}; + +#endif + diff --git a/src/setting.cpp b/src/setting.cpp new file mode 100644 index 0000000..9e7ed70 --- /dev/null +++ b/src/setting.cpp @@ -0,0 +1,144 @@ +/*************************************************************************** + setting.cpp + ------------------- + begin : Tue Nov 06 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "setting.h" +#include "settingfilter.h" +#include "stringutils.h" + +#include <istream> +#include <ostream> +#include <sstream> + +using namespace std; + +Setting::~Setting() +{ + for(list<SettingFilter*>::const_iterator itFilter = m_filters.begin(); itFilter != m_filters.end(); ++itFilter) + delete *itFilter; + m_filters.clear(); +} + +void Setting::pushFilter(SettingFilter* filter) +{ + if(!filter) + return; + + m_filters.push_back(filter); +} + +void Setting::popFilter() +{ + if(m_filters.empty()) + return; + + delete m_filters.back(); + m_filters.pop_back(); +} + +SettingFilter* Setting::findFilterWithId(const string& id) +{ + for(list<SettingFilter*>::const_iterator itFilter = m_filters.begin(); itFilter != m_filters.end(); ++itFilter) + { + if((*itFilter)->getId() == id) + return *itFilter; + } + + return 0; +} + +const SettingFilter* Setting::findFilterWithId(const string& id) const +{ + for(list<SettingFilter*>::const_iterator itFilter = m_filters.begin(); itFilter != m_filters.end(); ++itFilter) + { + if((*itFilter)->getId() == id) + return *itFilter; + } + + return 0; +} + +string Setting::getThroughFilter() const +{ + string valueCopy = m_value; + + for(list<SettingFilter*>::const_reverse_iterator itFilter = m_filters.rbegin(); itFilter != m_filters.rend(); ++itFilter) + (*itFilter)->filterRead(valueCopy); + + return valueCopy; +} + +bool Setting::setThroughFilter(const string& value) +{ + string valueCopy = value; + + for(list<SettingFilter*>::iterator itFilter = m_filters.begin(); itFilter != m_filters.end(); ++itFilter) + { + if(!(*itFilter)->filterWrite(valueCopy)) + return false; + } + + m_value = valueCopy; + return true; +} + +istream& operator>>(istream& in, Setting& setting) +{ + while(!in.eof()) + { + // extract line from stream + string line; + getline(in, line); + + if(in.fail()) + return in; + + // strip whitespace + line = trim(line); + + // skip empty lines + if(line.empty()) + continue; + + // skip comments + if(line[0] == '#') + continue; + + // split line into id and value + vector<string> words = splitQuoted(line, "="); + + if(words.size() < 2 || words[0].empty()) + { + in.setstate(ios_base::failbit); + return in; + } + + setting.setId(words[0]); + setting.setThroughFilter(words[1]); + + break; + } + + return in; +} + +ostream& operator<<(ostream& out, const Setting& setting) +{ + out << setting.getId() << "=\"" << setting.getThroughFilter() << "\"" << endl; + return out; +} + + diff --git a/src/setting.h b/src/setting.h new file mode 100644 index 0000000..eef52f5 --- /dev/null +++ b/src/setting.h @@ -0,0 +1,88 @@ +/*************************************************************************** + setting.h + ------------------- + begin : Tue Nov 06 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef SETTING_H +#define SETTING_H + +#include "stringutils.h" + +#include <iosfwd> +#include <list> +#include <string> + +class SettingFilter; + +class Setting +{ + public: + Setting(const std::string& id = "", const std::string& description = "") + : m_id(id), m_description(description), m_value() {} + template<class T> + Setting(const std::string& id, const std::string& description, const T& value) + : m_id(id), m_description(description), m_value(toString(value)) {} + ~Setting(); + + const std::string& getId() const { return m_id; } + const std::string& getDescription() const { return m_description; } + const std::string& getValue() const { return m_value; } + + void setId(const std::string& id) { m_id = id; } + void setDescription(const std::string& description) { m_description = description; } + + void pushFilter(SettingFilter* filter); + void popFilter(); + SettingFilter* findFilterWithId(const std::string& id); + const SettingFilter* findFilterWithId(const std::string& id) const; + + std::string getThroughFilter() const; + bool setThroughFilter(const std::string& value); + + template<class T> + operator T() { return fromString<T>(m_value); } + + template<class T> + Setting& operator=(const T& t) { m_value = toString(t); return *this; } + + template<class T> + bool operator==(const T& t) const { return toString(t) == m_value; } + template<class T> + bool operator!=(const T& t) const { return toString(t) != m_value; } + template<class T> + bool operator<(const T& t) const { return fromString<T>(m_value) < t; } + template<class T> + bool operator>(const T& t) const { return fromString<T>(m_value) > t; } + template<class T> + bool operator<=(const T& t) const { return fromString<T>(m_value) <= t; } + template<class T> + bool operator>=(const T& t) const { return fromString<T>(m_value) >= t; } + + bool operator==(const Setting& s) const { return s.m_value == m_value; } + bool operator!=(const Setting& s) const { return s.m_value != m_value; } + + private: + std::string m_id; + std::string m_description; + std::string m_value; + + std::list<SettingFilter*> m_filters; +}; + +std::istream& operator>>(std::istream& in, Setting& setting); +std::ostream& operator<<(std::ostream& out, const Setting& setting); + +#endif + diff --git a/src/settingfilter.cpp b/src/settingfilter.cpp new file mode 100644 index 0000000..fb7df78 --- /dev/null +++ b/src/settingfilter.cpp @@ -0,0 +1,222 @@ +/*************************************************************************** + settingfilter.cpp + ------------------- + begin : Wed Nov 28 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "settingfilter.h" +#include "stringutils.h" + +using namespace std; + +SettingFilterDefault::SettingFilterDefault(const string& def) + : m_default(def) +{ +} + +SettingFilterDefault::~SettingFilterDefault() +{ +} + +string SettingFilterDefault::getId() const +{ + return "default"; +} + +void SettingFilterDefault::setDefault(const string& def) +{ + m_default = def; +} + +const string& SettingFilterDefault::getDefault() const +{ + return m_default; +} + +bool SettingFilterDefault::filterWrite(string& valueNew) +{ + if(valueNew.empty()) + valueNew = m_default; + + return true; +} + +void SettingFilterDefault::filterRead(string& value) +{ +} + +SettingFilterExclusive::SettingFilterExclusive(const string& exclusive) + : m_exclusive(exclusive) +{ +} + +SettingFilterExclusive::~SettingFilterExclusive() +{ +} + +string SettingFilterExclusive::getId() const +{ + return "exclusive"; +} + +void SettingFilterExclusive::setExclusive(const string& exclusive) +{ + m_exclusive = exclusive; +} + +const string& SettingFilterExclusive::getExclusive() const +{ + return m_exclusive; +} + +bool SettingFilterExclusive::filterWrite(string& valueNew) +{ + substituteExclusive(valueNew); + return true; +} + +void SettingFilterExclusive::filterRead(string& value) +{ + substituteExclusive(value); +} + +void SettingFilterExclusive::substituteExclusive(string& value) +{ + if(value.find(m_exclusive + " ") == 0 || + value.find(string(" ") + m_exclusive) == value.length() - (m_exclusive.length() + 1) || + value.find(string(" ") + m_exclusive + " ") != string::npos + ) + value = m_exclusive; +} + +SettingFilterMap::SettingFilterMap(const map<string, string>& filterMap) + : m_filterMap(filterMap) +{ +} + +SettingFilterMap::~SettingFilterMap() +{ +} + +string SettingFilterMap::getId() const +{ + return "map"; +} + +void SettingFilterMap::setMap(const map<string, string>& filterMap) +{ + m_filterMap = filterMap; +} + +const map<string, string>& SettingFilterMap::getMap() const +{ + return m_filterMap; +} + +bool SettingFilterMap::filterWrite(string& valueNew) +{ + for(map<string, string>::const_iterator itMapping = m_filterMap.begin(); itMapping != m_filterMap.end(); ++itMapping) + { + if(itMapping->second == valueNew) + { + valueNew = itMapping->first; + return true; + } + } + + return false; +} + +void SettingFilterMap::filterRead(string& value) +{ + if(m_filterMap.empty()) + return; + + map<string, string>::const_iterator itMapping = m_filterMap.find(value); + if(itMapping != m_filterMap.end()) + value = itMapping->second; +} + +SettingFilterMin::SettingFilterMin(int min) + : m_min(min) +{ +} + +SettingFilterMin::~SettingFilterMin() +{ +} + +string SettingFilterMin::getId() const +{ + return "min"; +} + +void SettingFilterMin::setMin(int min) +{ + m_min = min; +} + +int SettingFilterMin::getMin() const +{ + return m_min; +} + +bool SettingFilterMin::filterWrite(string& valueNew) +{ + if(fromString<int>(valueNew) < m_min) + valueNew = toString(m_min); + + return true; +} + +void SettingFilterMin::filterRead(string& value) +{ +} + +SettingFilterMax::SettingFilterMax(int max) + : m_max(max) +{ +} + +SettingFilterMax::~SettingFilterMax() +{ +} + +string SettingFilterMax::getId() const +{ + return "max"; +} + +void SettingFilterMax::setMax(int max) +{ + m_max = max; +} + +int SettingFilterMax::getMax() const +{ + return m_max; +} + +bool SettingFilterMax::filterWrite(string& valueNew) +{ + if(fromString<int>(valueNew) > m_max) + valueNew = toString(m_max); + + return true; +} + +void SettingFilterMax::filterRead(string& value) +{ +} + diff --git a/src/settingfilter.h b/src/settingfilter.h new file mode 100644 index 0000000..c306667 --- /dev/null +++ b/src/settingfilter.h @@ -0,0 +1,128 @@ +/*************************************************************************** + settingfilter.h + ------------------- + begin : Wed Nov 28 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef SETTINGFILTER_H +#define SETTINGFILTER_H + +#include <map> +#include <string> + +class SettingFilter +{ + public: + virtual ~SettingFilter() {} + + virtual std::string getId() const = 0; + + virtual bool filterWrite(std::string& valueNew) = 0; + virtual void filterRead(std::string& value) = 0; +}; + +class SettingFilterDefault : public SettingFilter +{ + public: + SettingFilterDefault(const std::string& def); + ~SettingFilterDefault(); + + std::string getId() const; + + void setDefault(const std::string& def); + const std::string& getDefault() const; + + bool filterWrite(std::string& valueNew); + void filterRead(std::string& value); + + private: + std::string m_default; +}; + +class SettingFilterExclusive : public SettingFilter +{ + public: + SettingFilterExclusive(const std::string& exclusive); + ~SettingFilterExclusive(); + + std::string getId() const; + + void setExclusive(const std::string& exclusive); + const std::string& getExclusive() const; + + bool filterWrite(std::string& valueNew); + void filterRead(std::string& value); + + private: + void substituteExclusive(std::string& value); + + std::string m_exclusive; +}; + +class SettingFilterMap : public SettingFilter +{ + public: + SettingFilterMap(const std::map<std::string, std::string>& filterMap); + ~SettingFilterMap(); + + std::string getId() const; + + void setMap(const std::map<std::string, std::string>& filterMap); + const std::map<std::string, std::string>& getMap() const; + + bool filterWrite(std::string& valueNew); + void filterRead(std::string& value); + + private: + std::map<std::string, std::string> m_filterMap; +}; + +class SettingFilterMin : public SettingFilter +{ + public: + SettingFilterMin(int min); + ~SettingFilterMin(); + + std::string getId() const; + + void setMin(int min); + int getMin() const; + + bool filterWrite(std::string& valueNew); + void filterRead(std::string& value); + + private: + int m_min; +}; + +class SettingFilterMax : public SettingFilter +{ + public: + SettingFilterMax(int max); + ~SettingFilterMax(); + + std::string getId() const; + + void setMax(int max); + int getMax() const; + + bool filterWrite(std::string& valueNew); + void filterRead(std::string& value); + + private: + int m_max; +}; + +#endif + diff --git a/src/settingstore.cpp b/src/settingstore.cpp new file mode 100644 index 0000000..1dcb626 --- /dev/null +++ b/src/settingstore.cpp @@ -0,0 +1,98 @@ +/*************************************************************************** + settingstore.cpp + ------------------- + begin : Tue Nov 06 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "setting.h" +#include "settingstore.h" + +#include <fstream> + +using namespace std; + +map<string, Setting> SettingStore::m_settings; + +Setting& SettingStore::get(const string& key) +{ + return m_settings[key]; +} + +void SettingStore::add(const Setting& setting) +{ + m_settings[setting.getId()] = setting; +} + +void SettingStore::remove(const string& key) +{ + m_settings.erase(key); +} + +bool SettingStore::exists(const string& key) +{ + return m_settings.find(key) != m_settings.end(); +} + +map<std::string, Setting>& SettingStore::getAll() +{ + return m_settings; +} + +bool SettingStore::readFromFile(const std::string& file) +{ + if(file.empty()) + return false; + + // open file + ifstream fin(file.c_str()); + if(!fin.is_open()) + return false; + + // parse file + while(fin.good()) + { + Setting setting; + + fin >> setting; + if(setting.getId().empty()) + break; + + if(exists(setting.getId())) + get(setting.getId()).setThroughFilter(setting.getValue()); + else + add(setting); + } + + return !fin.fail(); +} + +bool SettingStore::writeToFile(const std::string& file) +{ + if(file.empty()) + return false; + + // open file + ofstream fout(file.c_str()); + if(!fout.is_open()) + return false; + + fout << "Version=\"1\"\n"; + + // output settings + for(map<string, Setting>::const_iterator itSetting = m_settings.begin(); itSetting != m_settings.end(); ++itSetting) + fout << itSetting->second; + + return fout.good(); +} + diff --git a/src/settingstore.h b/src/settingstore.h new file mode 100644 index 0000000..4fc1ebb --- /dev/null +++ b/src/settingstore.h @@ -0,0 +1,44 @@ +/*************************************************************************** + settingstore.h + ------------------- + begin : Tue Nov 06 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef SETTINGSTORE_H +#define SETTINGSTORE_H + +#include <map> +#include <string> + +class Setting; + +class SettingStore +{ + public: + static Setting& get(const std::string& key); + static void add(const Setting& setting); + static void remove(const std::string& key); + static bool exists(const std::string& key); + + static std::map<std::string, Setting>& getAll(); + + static bool readFromFile(const std::string& file); + static bool writeToFile(const std::string& file); + + private: + static std::map<std::string, Setting> m_settings; +}; + +#endif + diff --git a/src/statistics.cpp b/src/statistics.cpp new file mode 100644 index 0000000..a983c9c --- /dev/null +++ b/src/statistics.cpp @@ -0,0 +1,216 @@ +/*************************************************************************** + statistics.cpp + ------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "setting.h" +#include "settingstore.h" +#include "statistics.h" + +using namespace std; + +void Statistics::insertDataFrame(const DataFrame& dataFrame) +{ + if(!dataFrame.isValid()) + return; + + m_dataFrames.push_back(dataFrame); + + unsigned int frameCount = m_dataFrames.size(); + if(frameCount < 2) + return; + + unsigned int averageCount = getAverageWindow(); + unsigned int secondCount = getSecondWindow(); + + if(frameCount > averageCount) + { + m_dataFrames.erase(m_dataFrames.begin(), m_dataFrames.begin() + (frameCount - averageCount)); + frameCount = averageCount; + } + + vector<DataFrame>::const_reverse_iterator itFrameSecond = m_dataFrames.rbegin(); + vector<DataFrame>::const_reverse_iterator itFrameAverage = m_dataFrames.rbegin(); + + if(frameCount > secondCount) + itFrameSecond += secondCount; + else + itFrameSecond += frameCount - 1; + + if(frameCount > averageCount) + itFrameAverage += averageCount; + else + itFrameAverage += frameCount - 1; + + calculateAverage(*itFrameSecond, m_dataFrames.back(), m_second); + calculateAverage(*itFrameAverage, m_dataFrames.back(), m_average); + + if(frameCount > 2) + calculateMinMax(m_second, m_min, m_max); + else + m_min = m_max = m_second; +} + +void Statistics::reset() +{ + m_second = DataFrame(); + m_average = DataFrame(); + m_min = DataFrame(); + m_max = DataFrame(); + + m_dataFrames.clear(); +} + +float Statistics::getUnitFactor(dataUnit unit, unsigned long long value) +{ + float factor = 1.0 / (unit % 2 == 0 ? 8 : 1); + + switch(unit) + { + case humanReadableBit: + case humanReadableByte: + for(int i = 0; i < 3; ++i) + { + if(value / factor < 1024) + return factor; + + factor *= 1024; + } + return factor; + case bit: + case byte: + return factor; + case kiloBit: + case kiloByte: + return factor * 1024; + case megaBit: + case megaByte: + return factor * 1024 * 1024; + case gigaBit: + case gigaByte: + return factor * 1024 * 1024 * 1024; + default: // should never be executed + return factor; + } +} + +string Statistics::getUnitString(dataUnit unit, unsigned long long value) +{ + const string description = (unit % 2 == 0 ? "Bit" : "Byte"); + const string units[] = { "", "k", "M", "G" }; + + switch(unit) + { + case humanReadableBit: + case humanReadableByte: + value *= (unit % 2 == 0 ? 8 : 1); + for(int i = 0; i < 3; ++i) + { + if(value < 1024) + return units[i] + description; + + value /= 1024; + } + return units[3] + description; + case bit: + case byte: + return description; + case kiloBit: + case kiloByte: + return 'k' + description; + case megaBit: + case megaByte: + return 'M' + description; + case gigaBit: + case gigaByte: + return 'G' + description; + default: // should never be executed + return description; + } +} + +void Statistics::calculateAverage(const DataFrame& dataFrameFrom, const DataFrame& dataFrameTo, DataFrame& result) +{ + float timeSpan = (dataFrameTo.getTimeStampSeconds() + dataFrameTo.getTimeStampMicroseconds() / 1000000.0) - + (dataFrameFrom.getTimeStampSeconds() + dataFrameFrom.getTimeStampMicroseconds() / 1000000.0); + + if(timeSpan <= 0) + return; + + result.setTotalDataIn((unsigned long long)((dataFrameTo.getTotalDataIn() - dataFrameFrom.getTotalDataIn()) / timeSpan)); + result.setTotalDataOut((unsigned long long)((dataFrameTo.getTotalDataOut() - dataFrameFrom.getTotalDataOut()) / timeSpan)); + result.setTotalPacketsIn((unsigned long long)((dataFrameTo.getTotalPacketsIn() - dataFrameFrom.getTotalPacketsIn()) / timeSpan)); + result.setTotalPacketsOut((unsigned long long)((dataFrameTo.getTotalPacketsOut() - dataFrameFrom.getTotalPacketsOut()) / timeSpan)); + result.setTotalErrorsIn((unsigned long long)((dataFrameTo.getTotalErrorsIn() - dataFrameFrom.getTotalErrorsIn()) / timeSpan)); + result.setTotalErrorsOut((unsigned long long)((dataFrameTo.getTotalErrorsOut() - dataFrameFrom.getTotalErrorsOut()) / timeSpan)); + result.setTotalDropsIn((unsigned long long)((dataFrameTo.getTotalDropsIn() - dataFrameFrom.getTotalDropsIn()) / timeSpan)); + result.setTotalDropsOut((unsigned long long)((dataFrameTo.getTotalDropsOut() - dataFrameFrom.getTotalDropsOut()) / timeSpan)); +} + +void Statistics::calculateMinMax(const DataFrame& dataFrame, DataFrame& min, DataFrame& max) +{ + if(dataFrame.getTotalDataIn() < min.getTotalDataIn()) + min.setTotalDataIn(dataFrame.getTotalDataIn()); + if(dataFrame.getTotalDataIn() > max.getTotalDataIn()) + max.setTotalDataIn(dataFrame.getTotalDataIn()); + if(dataFrame.getTotalDataOut() < min.getTotalDataOut()) + min.setTotalDataOut(dataFrame.getTotalDataOut()); + if(dataFrame.getTotalDataOut() > max.getTotalDataOut()) + max.setTotalDataOut(dataFrame.getTotalDataOut()); + + if(dataFrame.getTotalPacketsIn() < min.getTotalPacketsIn()) + min.setTotalPacketsIn(dataFrame.getTotalPacketsIn()); + if(dataFrame.getTotalPacketsIn() > max.getTotalPacketsIn()) + max.setTotalPacketsIn(dataFrame.getTotalPacketsIn()); + if(dataFrame.getTotalPacketsOut() < min.getTotalPacketsOut()) + min.setTotalPacketsOut(dataFrame.getTotalPacketsOut()); + if(dataFrame.getTotalPacketsOut() > max.getTotalPacketsOut()) + max.setTotalPacketsOut(dataFrame.getTotalPacketsOut()); + + if(dataFrame.getTotalErrorsIn() < min.getTotalErrorsIn()) + min.setTotalErrorsIn(dataFrame.getTotalErrorsIn()); + if(dataFrame.getTotalErrorsIn() > max.getTotalErrorsIn()) + max.setTotalErrorsIn(dataFrame.getTotalErrorsIn()); + if(dataFrame.getTotalErrorsOut() < min.getTotalErrorsOut()) + min.setTotalErrorsOut(dataFrame.getTotalErrorsOut()); + if(dataFrame.getTotalErrorsOut() > max.getTotalErrorsOut()) + max.setTotalErrorsOut(dataFrame.getTotalErrorsOut()); + + if(dataFrame.getTotalDropsIn() < min.getTotalDropsIn()) + min.setTotalDropsIn(dataFrame.getTotalDropsIn()); + if(dataFrame.getTotalDropsIn() > max.getTotalDropsIn()) + max.setTotalDropsIn(dataFrame.getTotalDropsIn()); + if(dataFrame.getTotalDropsOut() < min.getTotalDropsOut()) + min.setTotalDropsOut(dataFrame.getTotalDropsOut()); + if(dataFrame.getTotalDropsOut() > max.getTotalDropsOut()) + max.setTotalDropsOut(dataFrame.getTotalDropsOut()); +} + +unsigned int Statistics::getAverageWindow() +{ + unsigned int refreshInterval = SettingStore::get("RefreshInterval"); + unsigned int averageWindow = SettingStore::get("AverageWindow"); + + return (unsigned int) (1000.0 / refreshInterval * averageWindow); +} + +unsigned int Statistics::getSecondWindow() +{ + unsigned int refreshInterval = SettingStore::get("RefreshInterval"); + unsigned int secondWindow = (unsigned int) (1000.0 / refreshInterval); + + return secondWindow > 0 ? secondWindow : 1; +} + diff --git a/src/statistics.h b/src/statistics.h new file mode 100644 index 0000000..961b7e9 --- /dev/null +++ b/src/statistics.h @@ -0,0 +1,114 @@ +/*************************************************************************** + statistics.h + ------------------- + begin : Fri Nov 16 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef STATISTICS_H +#define STATISTICS_H + +#include "dataframe.h" + +#include <string> +#include <vector> + +class Statistics +{ + public: + enum dataUnit + { + humanReadableBit = -2, + humanReadableByte = -1, + bit = 0, + byte = 1, + kiloBit = 2, + kiloByte = 3, + megaBit = 4, + megaByte = 5, + gigaBit = 6, + gigaByte = 7 + }; + + Statistics() {} + ~Statistics() {} + + static float getUnitFactor(dataUnit unit, unsigned long long value); + static std::string getUnitString(dataUnit unit, unsigned long long value); + + void insertDataFrame(const DataFrame& dataFrame); + void reset(); + + bool isValid() const { return !m_dataFrames.empty(); } + + unsigned long long getDataInTotal() const { return m_dataFrames.empty() ? 0 : m_dataFrames.back().getTotalDataIn(); } + unsigned long long getDataOutTotal() const { return m_dataFrames.empty() ? 0 : m_dataFrames.back().getTotalDataOut(); } + unsigned long long getPacketsInTotal() const { return m_dataFrames.empty() ? 0 : m_dataFrames.back().getTotalPacketsIn(); } + unsigned long long getPacketsOutTotal() const { return m_dataFrames.empty() ? 0 : m_dataFrames.back().getTotalPacketsOut(); } + unsigned long long getErrorsInTotal() const { return m_dataFrames.empty() ? 0 : m_dataFrames.back().getTotalErrorsIn(); } + unsigned long long getErrorsOutTotal() const { return m_dataFrames.empty() ? 0 : m_dataFrames.back().getTotalErrorsOut(); } + unsigned long long getDropsInTotal() const { return m_dataFrames.empty() ? 0 : m_dataFrames.back().getTotalDropsIn(); } + unsigned long long getDropsOutTotal() const { return m_dataFrames.empty() ? 0 : m_dataFrames.back().getTotalDropsOut(); } + + unsigned long long getDataInPerSecond() const { return m_second.getTotalDataIn(); } + unsigned long long getDataOutPerSecond() const { return m_second.getTotalDataOut(); } + unsigned long long getPacketsInPerSecond() const { return m_second.getTotalPacketsIn(); } + unsigned long long getPacketsOutPerSecond() const { return m_second.getTotalPacketsOut(); } + unsigned long long getErrorsInPerSecond() const { return m_second.getTotalErrorsIn(); } + unsigned long long getErrorsOutPerSecond() const { return m_second.getTotalErrorsOut(); } + unsigned long long getDropsInPerSecond() const { return m_second.getTotalDropsIn(); } + unsigned long long getDropsOutPerSecond() const { return m_second.getTotalDropsOut(); } + + unsigned long long getDataInAverage() const { return m_average.getTotalDataIn(); } + unsigned long long getDataOutAverage() const { return m_average.getTotalDataOut(); } + unsigned long long getPacketsInAverage() const { return m_average.getTotalPacketsIn(); } + unsigned long long getPacketsOutAverage() const { return m_average.getTotalPacketsOut(); } + unsigned long long getErrorsInAverage() const { return m_average.getTotalErrorsIn(); } + unsigned long long getErrorsOutAverage() const { return m_average.getTotalErrorsOut(); } + unsigned long long getDropsInAverage() const { return m_average.getTotalDropsIn(); } + unsigned long long getDropsOutAverage() const { return m_average.getTotalDropsOut(); } + + unsigned long long getDataInMin() const { return m_min.getTotalDataIn(); } + unsigned long long getDataOutMin() const { return m_min.getTotalDataOut(); } + unsigned long long getPacketsInMin() const { return m_min.getTotalPacketsIn(); } + unsigned long long getPacketsOutMin() const { return m_min.getTotalPacketsOut(); } + unsigned long long getErrorsInMin() const { return m_min.getTotalErrorsIn(); } + unsigned long long getErrorsOutMin() const { return m_min.getTotalErrorsOut(); } + unsigned long long getDropsInMin() const { return m_min.getTotalDropsIn(); } + unsigned long long getDropsOutMin() const { return m_min.getTotalDropsOut(); } + + unsigned long long getDataInMax() const { return m_max.getTotalDataIn(); } + unsigned long long getDataOutMax() const { return m_max.getTotalDataOut(); } + unsigned long long getPacketsInMax() const { return m_max.getTotalPacketsIn(); } + unsigned long long getPacketsOutMax() const { return m_max.getTotalPacketsOut(); } + unsigned long long getErrorsInMax() const { return m_max.getTotalErrorsIn(); } + unsigned long long getErrorsOutMax() const { return m_max.getTotalErrorsOut(); } + unsigned long long getDropsInMax() const { return m_max.getTotalDropsIn(); } + unsigned long long getDropsOutMax() const { return m_max.getTotalDropsOut(); } + + private: + void calculateAverage(const DataFrame& dataFrameFrom, const DataFrame& dataFrameTo, DataFrame& result); + void calculateMinMax(const DataFrame& dataFrame, DataFrame& min, DataFrame& max); + unsigned int getAverageWindow(); + unsigned int getSecondWindow(); + + DataFrame m_second; + DataFrame m_average; + DataFrame m_min; + DataFrame m_max; + + std::vector<DataFrame> m_dataFrames; +}; + +#endif + diff --git a/src/stringutils.cpp b/src/stringutils.cpp new file mode 100644 index 0000000..3d30943 --- /dev/null +++ b/src/stringutils.cpp @@ -0,0 +1,97 @@ +/*************************************************************************** + stringutils.cpp + ------------------- + begin : Tue Nov 06 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "stringutils.h" + +using namespace std; + +string trim(const string& s) +{ + // find end of whitespace at the beginning + string::size_type posBegin = s.find_first_not_of(" \011\012\015"); + if(posBegin == string::npos) + return string(); + + // find beginning of whitespace at the end + string::size_type posEnd = s.find_last_not_of(" \011\012\015"); + + return s.substr(posBegin, posEnd - posBegin + 1); +} + +vector<string> split(const string& s, const string& separators) +{ + vector<string> words; + if(s.empty()) + return words; + + string::size_type pos = s.find_first_of(separators); + string::size_type posOld = 0; + while(pos != string::npos) + { + words.push_back(s.substr(posOld, pos - posOld)); + posOld = pos + 1; + + pos = s.find_first_of(separators, posOld); + } + + words.push_back(s.substr(posOld)); + + return words; +} + +vector<string> splitQuoted(const string& s, const string& separators, const string& quotes) +{ + if(s.empty()) + return vector<string>(); + + vector<string> words(1); + string::size_type pos = s.find_first_of(separators + quotes); + string::size_type posOld = 0; + bool quoted = false; + + while(true) + { + words.back() += s.substr(posOld, pos - posOld); + posOld = pos + 1; + + if(pos == string::npos) + return words; + + if(separators.find(s[pos]) != string::npos) + { + // separator found + + words.push_back(string()); + + pos = s.find_first_of(separators + quotes, posOld); + } + else + { + // quote found + + posOld = pos + 1; + + quoted = !quoted; + + if(quoted) + pos = s.find_first_of(quotes, posOld); + else + pos = s.find_first_of(separators + quotes, posOld); + } + } +} + diff --git a/src/stringutils.h b/src/stringutils.h new file mode 100644 index 0000000..b181b5e --- /dev/null +++ b/src/stringutils.h @@ -0,0 +1,49 @@ +/*************************************************************************** + stringutils.h + ------------------- + begin : Tue Nov 06 2007 + copyright : (C) 2007 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef STRINGUTILS_H +#define STRINGUTILS_H + +#include <sstream> +#include <string> +#include <vector> + +std::string trim(const std::string& s); +std::vector<std::string> split(const std::string& s, const std::string& separators); +std::vector<std::string> splitQuoted(const std::string& s, const std::string& separators, const std::string& quotes = "\""); + +template<class T> +std::string toString(const T& t) +{ + std::ostringstream stream; + stream << t; + + return stream.str(); +} + +template<class T> +T fromString(const std::string& s) +{ + std::istringstream stream(s); + T t = T(); + stream >> t; + + return t; +} + +#endif + diff --git a/src/templates/cpp_template b/src/templates/cpp_template new file mode 100644 index 0000000..6afef5d --- /dev/null +++ b/src/templates/cpp_template @@ -0,0 +1,16 @@ +/*************************************************************************** + |FILENAME| - description + ------------------- + begin : |DATE| + copyright : (C) |YEAR| by |AUTHOR| + email : |EMAIL| + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ diff --git a/src/templates/header_template b/src/templates/header_template new file mode 100644 index 0000000..6afef5d --- /dev/null +++ b/src/templates/header_template @@ -0,0 +1,16 @@ +/*************************************************************************** + |FILENAME| - description + ------------------- + begin : |DATE| + copyright : (C) |YEAR| by |AUTHOR| + email : |EMAIL| + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ diff --git a/src/traffic_window.cpp b/src/traffic_window.cpp new file mode 100644 index 0000000..7296db5 --- /dev/null +++ b/src/traffic_window.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** + traffic_window.cpp + ------------------- + begin : Thu Jul 04 2002 + copyright : (C) 2002 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "device.h" +#include "setting.h" +#include "settingstore.h" +#include "traffic_window.h" + +using namespace std; + +TrafficWindow::TrafficWindow() + : Window(), m_curDev(0) +{ +} + +TrafficWindow::~TrafficWindow() +{ +} + +void TrafficWindow::processKey(int key) +{ + switch(key) + { + case KEY_RIGHT: + case KEY_DOWN: + case KEY_NPAGE: + case KEY_ENTER: + case '\n': + case '\t': + case '\015': + m_curDev += showMultipleDevices() ? getHeight() / 9 : 1; + break; + case KEY_LEFT: + case KEY_UP: + case KEY_PPAGE: + m_curDev -= showMultipleDevices() ? getHeight() / 9 : 1; + break; + } +} + +void TrafficWindow::printTraffic(const vector<Device*>& devices) +{ + if((unsigned int) m_curDev >= devices.size() || m_curDev < 0) + m_curDev = 0; + + // print data of the current device(s) + if(!showMultipleDevices()) + { + devices[m_curDev]->print(*this); + } + else + { + if((unsigned int) getHeight() / 9 >= devices.size()) + m_curDev = 0; + + int i = m_curDev; + while(getHeight() - getY() >= 9) + { + devices[i++]->print(*this); + + if((unsigned int) i >= devices.size()) + break; + } + } +} + +bool TrafficWindow::showMultipleDevices() +{ + return SettingStore::get("MultipleDevices"); +} + diff --git a/src/traffic_window.h b/src/traffic_window.h new file mode 100644 index 0000000..1baa246 --- /dev/null +++ b/src/traffic_window.h @@ -0,0 +1,43 @@ +/*************************************************************************** + traffic_window.h + ------------------- + begin : Thu Jul 04 2002 + copyright : (C) 2002 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef TRAFFIC_WINDOW_H +#define TRAFFIC_WINDOW_H + +#include "window.h" + +#include <vector> + +class Device; + +class TrafficWindow : public Window +{ + public: + TrafficWindow(); + ~TrafficWindow(); + + void processKey(int key); + void printTraffic(const std::vector<Device*>& devices); + + private: + bool showMultipleDevices(); + + int m_curDev; +}; + +#endif + diff --git a/src/window.cpp b/src/window.cpp new file mode 100644 index 0000000..bfa7701 --- /dev/null +++ b/src/window.cpp @@ -0,0 +1,289 @@ +/*************************************************************************** + window.cpp + ------------------- + begin : Thu Nov 25 2003 + copyright : (C) 2003 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "window.h" + +using namespace std; + +Window::WindowStreamBuf::WindowStreamBuf(Window& window) + : m_window(window) +{ +} + +Window::WindowStreamBuf::~WindowStreamBuf() +{ +} + +streamsize Window::WindowStreamBuf::xsputn(const char_type* str, streamsize n) +{ + m_window.print(string(str, n)); + return n; +} + +Window::WindowStreamBuf::int_type Window::WindowStreamBuf::overflow(int_type c) +{ + if(c == traits_type::eof()) + return c; + + m_window.print((char) c); + return c; +} + +Window::WindowStream::WindowStream(Window& window) + : basic_ostream<char>(new WindowStreamBuf(window)) +{ +} + +Window::WindowStream::~WindowStream() +{ + delete rdbuf(); +} + +Window::Window() + : m_visible(false), m_window(0), m_stream(*this) +{ +} + +Window::~Window() +{ + hide(); +} + +// create window and display it +void Window::show(int x, int y, int width, int height) +{ + if(m_window) + return; + + m_window = newwin(height, width, y, x); + clear(); + refresh(); + + m_visible = true; +} + +// hide window and destroy it +void Window::hide() +{ + if(!m_window) + return; + + clear(); + refresh(); + delwin(m_window); + + m_window = 0; + + m_visible = false; +} + +// is the window currently visible? +bool Window::isVisible() +{ + return m_visible; +} + +// refresh window +void Window::refresh() +{ + if(m_window) + wrefresh(m_window); +} + +// clear the content of the window +void Window::clear() +{ + if(m_window) + wclear(m_window); +} + +// move and resize window +void Window::resize(int x, int y, int width, int height) +{ + if(!m_window) + return; + + wresize(m_window, height, width); + mvwin(m_window, y, x); +} + +// return current window width +int Window::getWidth() +{ + if(!m_window) + return 0; + + int width, height; + getmaxyx(m_window, height, width); + + return width; +} + +// return current window height +int Window::getHeight() +{ + if(!m_window) + return 0; + + int width, height; + getmaxyx(m_window, height, width); + + return height; +} + +// return current distance to left screen edge +int Window::getLeft() +{ + if(!m_window) + return 0; + + int x, y; + getbegyx(m_window, y, x); + + return x; +} + +// return current distance to top screen edge +int Window::getTop() +{ + if(!m_window) + return 0; + + int x, y; + getbegyx(m_window, y, x); + + return y; +} + +// return current cursor position on the x-axis +int Window::getX() +{ + if(!m_window) + return 0; + + int x, y; + getyx(m_window, y, x); + + return x; +} + +// return current cursor position on the y-axis +int Window::getY() +{ + if(!m_window) + return 0; + + int x, y; + getyx(m_window, y, x); + + return y; +} + +// set current cursor x position +void Window::setX(int new_x) +{ + if(!m_window) + return; + + wmove(m_window, getY(), new_x); +} + +// set current cursor y position +void Window::setY(int new_y) +{ + if(!m_window) + return; + + wmove(m_window, new_y, getX()); +} + +// set current cursor position +void Window::setXY(int new_x, int new_y) +{ + if(!m_window) + return; + + wmove(m_window, new_y, new_x); +} + +// print some text to the window +void Window::print(const string& text, int new_x, int new_y) +{ + if(!m_window) + return; + if(new_x <= -1) + new_x = getX(); + if(new_y <= -1) + new_y = getY(); + + mvwaddstr(m_window, new_y, new_x, text.c_str()); +} + +// print a char to the window +void Window::print(char text, int new_x, int new_y) +{ + if(!m_window) + return; + if(new_x <= -1) + new_x = getX(); + if(new_y <= -1) + new_y = getY(); + + mvwaddch(m_window, new_y, new_x, text); +} + +// print via stream to window +Window::WindowStream& Window::print(int x, int y) +{ + if(x <= -1) + x = getX(); + if(y <= -1) + y = getY(); + setXY(x, y); + + return m_stream; +} + +SubWindow::SubWindow(Window* parent) + : Window(), m_parent(parent) +{ +} + +SubWindow::~SubWindow() +{ + hide(); +} + +// return parent window +Window* SubWindow::getParent() +{ + return m_parent; +} + +// create window and display it +void SubWindow::show(int x, int y, int width, int height) +{ + if(m_window) + return; + + m_window = derwin(m_parent->m_window, height, width, y, x); + clear(); + refresh(); + + m_visible = true; +} + diff --git a/src/window.h b/src/window.h new file mode 100644 index 0000000..fb36b08 --- /dev/null +++ b/src/window.h @@ -0,0 +1,142 @@ +/*************************************************************************** + window.h + ------------------- + begin : Thu Jul 04 2002 + copyright : (C) 2002 - 2012 by Roland Riegel + email : feedback@roland-riegel.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef WINDOW_H +#define WINDOW_H + +#include <ostream> +#include <streambuf> +#include <string> + +#include <curses.h> +#undef clear +#undef erase +#undef refresh + +class Form; + +class Window +{ + public: + class WindowStreamBuf : public std::basic_streambuf<char> + { + public: + WindowStreamBuf(Window& window); + ~WindowStreamBuf(); + + protected: + std::streamsize xsputn(const char_type* str, std::streamsize n); + int_type overflow(int_type c = traits_type::eof()); + + private: + Window& m_window; + }; + + class WindowStream : public std::basic_ostream<char> + { + public: + WindowStream(Window& window); + ~WindowStream(); + }; + + Window(); + virtual ~Window(); + + // create window and display it + virtual void show(int x, int y, int width, int height); + + // hide window and destroy it + virtual void hide(); + + // is the window currently visible? + virtual bool isVisible(); + + // refresh window + virtual void refresh(); + + // clear the content of the window + virtual void clear(); + + // move and resize window + virtual void resize(int x, int y, int width, int height); + + // return current window width + virtual int getWidth(); + + // return current window height + virtual int getHeight(); + + // return current distance to left screen edge + virtual int getLeft(); + + // return current distance to top screen edge + virtual int getTop(); + + // return current cursor position on the x-axis + virtual int getX(); + + // return current cursor position on the y-axis + virtual int getY(); + + // set current cursor x position + virtual void setX(int new_x); + + // set current cursor y position + virtual void setY(int new_y); + + // set current cursor position + virtual void setXY(int new_x, int new_y); + + // print some text to the window + virtual void print(const std::string& text, int new_x = -1, int new_y = -1); + + // print a char to the window + virtual void print(char text, int new_x = -1, int new_y = -1); + + // print via stream to the window + virtual WindowStream& print(int x = -1, int y = -1); + + protected: + friend class SubWindow; + friend class Form; + + bool m_visible; + WINDOW* m_window; + + WindowStream m_stream; +}; + +class SubWindow : public Window +{ + public: + SubWindow( Window* parent ); + ~SubWindow(); + + // return parent window + Window* getParent(); + + // create window and display it + virtual void show(int x, int y, int width, int height); + + private: + friend class Form; + + Window* m_parent; +}; + +#endif + |