diff --git a/Makefile.in b/Makefile.in deleted file mode 100644 index f101354c3d..0000000000 --- a/Makefile.in +++ /dev/null @@ -1,682 +0,0 @@ -# Makefile.in generated by automake 1.11 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 = : -subdir = . -DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in $(srcdir)/config.h.in \ - $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ - depcomp install-sh missing -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -SOURCES = -DIST_SOURCES = -RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ - html-recursive info-recursive install-data-recursive \ - install-dvi-recursive install-exec-recursive \ - install-html-recursive install-info-recursive \ - install-pdf-recursive install-ps-recursive install-recursive \ - installcheck-recursive installdirs-recursive pdf-recursive \ - ps-recursive uninstall-recursive -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ - $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ - distdir dist dist-all distcheck -ETAGS = etags -CTAGS = ctags -DIST_SUBDIRS = $(SUBDIRS) -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -distdir = $(PACKAGE)-$(VERSION) -top_distdir = $(distdir) -am__remove_distdir = \ - { test ! -d "$(distdir)" \ - || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ - && rm -fr "$(distdir)"; }; } -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -DIST_ARCHIVES = $(distdir).tar.gz -GZIP_ENV = --best -distuninstallcheck_listfiles = find . -type f -print -distcleancheck_listfiles = find . -type f -print -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@ -GTEST_INCLUDES = @GTEST_INCLUDES@ -GTEST_LDADD = @GTEST_LDADD@ -GTEST_LDFLAGS = @GTEST_LDFLAGS@ -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@ -RANLIB = @RANLIB@ -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_alias = @build_alias@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host_alias = @host_alias@ -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@ -SUBDIRS = src -all: config.h - $(MAKE) $(AM_MAKEFLAGS) all-recursive - -.SUFFIXES: -am--refresh: - @: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ - $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: $(am__configure_deps) - $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) -$(am__aclocal_m4_deps): - -config.h: stamp-h1 - @if test ! -f $@; then \ - rm -f stamp-h1; \ - $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ - else :; fi - -stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status - @rm -f stamp-h1 - cd $(top_builddir) && $(SHELL) ./config.status config.h -$(srcdir)/config.h.in: $(am__configure_deps) - ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) - rm -f stamp-h1 - touch $@ - -distclean-hdr: - -rm -f config.h stamp-h1 - -# This directory's subdirectories are mostly independent; you can cd -# into them and run `make' without going through this Makefile. -# To change the values of `make' variables: instead of editing Makefiles, -# (1) if the variable is set in `config.status', edit `config.status' -# (which will cause the Makefiles to be regenerated when you run `make'); -# (2) otherwise, pass the desired values on the `make' command line. -$(RECURSIVE_TARGETS): - @failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -$(RECURSIVE_CLEAN_TARGETS): - @failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - rev=''; for subdir in $$list; do \ - if test "$$subdir" = "."; then :; else \ - rev="$$subdir $$rev"; \ - fi; \ - done; \ - rev="$$rev ."; \ - target=`echo $@ | sed s/-recursive//`; \ - for subdir in $$rev; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done && test -z "$$fail" -tags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ - done -ctags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ - done - -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: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - list='$(SOURCES) $(HEADERS) config.h.in $(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: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) config.h.in $(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) - $(am__remove_distdir) - test -d "$(distdir)" || mkdir "$(distdir)" - @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 - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done - -test -n "$(am__skip_mode_fix)" \ - || find "$(distdir)" -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ - ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ - || chmod -R a+r "$(distdir)" -dist-gzip: distdir - tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - $(am__remove_distdir) - -dist-bzip2: distdir - tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 - $(am__remove_distdir) - -dist-lzma: distdir - tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma - $(am__remove_distdir) - -dist-xz: distdir - tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz - $(am__remove_distdir) - -dist-tarZ: distdir - tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z - $(am__remove_distdir) - -dist-shar: distdir - shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz - $(am__remove_distdir) - -dist-zip: distdir - -rm -f $(distdir).zip - zip -rq $(distdir).zip $(distdir) - $(am__remove_distdir) - -dist dist-all: distdir - tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - $(am__remove_distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - case '$(DIST_ARCHIVES)' in \ - *.tar.gz*) \ - GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ - *.tar.bz2*) \ - bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ - *.tar.lzma*) \ - unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ - *.tar.xz*) \ - xz -dc $(distdir).tar.xz | $(am__untar) ;;\ - *.tar.Z*) \ - uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ - *.shar.gz*) \ - GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ - *.zip*) \ - unzip $(distdir).zip ;;\ - esac - chmod -R a-w $(distdir); chmod a+w $(distdir) - mkdir $(distdir)/_build - mkdir $(distdir)/_inst - chmod a-w $(distdir) - test -d $(distdir)/_build || exit 0; \ - dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ - && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ - && am__cwd=`pwd` \ - && $(am__cd) $(distdir)/_build \ - && ../configure --srcdir=.. --prefix="$$dc_install_base" \ - $(DISTCHECK_CONFIGURE_FLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ - distuninstallcheck \ - && chmod -R a-w "$$dc_install_base" \ - && ({ \ - (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ - distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ - } || { rm -rf "$$dc_destdir"; exit 1; }) \ - && rm -rf "$$dc_destdir" \ - && $(MAKE) $(AM_MAKEFLAGS) dist \ - && rm -rf $(DIST_ARCHIVES) \ - && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ - && cd "$$am__cwd" \ - || exit 1 - $(am__remove_distdir) - @(echo "$(distdir) archives ready for distribution: "; \ - list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ - sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' -distuninstallcheck: - @$(am__cd) '$(distuninstallcheck_dir)' \ - && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ - || { echo "ERROR: files left after uninstall:" ; \ - if test -n "$(DESTDIR)"; then \ - echo " (check DESTDIR support)"; \ - fi ; \ - $(distuninstallcheck_listfiles) ; \ - exit 1; } >&2 -distcleancheck: distclean - @if test '$(srcdir)' = . ; then \ - echo "ERROR: distcleancheck can only run from a VPATH build" ; \ - exit 1 ; \ - fi - @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left in build directory after distclean:" ; \ - $(distcleancheck_listfiles) ; \ - exit 1; } >&2 -check-am: all-am -check: check-recursive -all-am: Makefile config.h -installdirs: installdirs-recursive -installdirs-am: -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -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-recursive - -clean-am: clean-generic mostlyclean-am - -distclean: distclean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-hdr distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-generic - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: - -.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \ - ctags-recursive install-am install-strip tags-recursive - -.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ - all all-am am--refresh check check-am clean clean-generic \ - ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \ - dist-lzma dist-shar dist-tarZ dist-xz dist-zip distcheck \ - distclean distclean-generic distclean-hdr distclean-tags \ - distcleancheck distdir distuninstallcheck dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs installdirs-am maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ - pdf-am ps ps-am tags tags-recursive uninstall uninstall-am - - -# 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/aclocal.m4 b/aclocal.m4 deleted file mode 100644 index 9e6e22d5e9..0000000000 --- a/aclocal.m4 +++ /dev/null @@ -1,951 +0,0 @@ -# generated automatically by aclocal 1.11 -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. -# This file 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. - -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.64],, -[m4_warning([this file was generated for autoconf 2.64. -You have another version of autoconf. It may work, but is not guaranteed to. -If you have problems, you may need to regenerate the build system entirely. -To do so, use the procedure documented by the package, typically `autoreconf'.])]) - -# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. -# -# This file 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. - -# AM_AUTOMAKE_VERSION(VERSION) -# ---------------------------- -# Automake X.Y traces this macro to ensure aclocal.m4 has been -# generated from the m4 files accompanying Automake X.Y. -# (This private macro should not be called outside this file.) -AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.11' -dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to -dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.11], [], - [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl -]) - -# _AM_AUTOCONF_VERSION(VERSION) -# ----------------------------- -# aclocal traces this macro to find the Autoconf version. -# This is a private macro too. Using m4_define simplifies -# the logic in aclocal, which can simply ignore this definition. -m4_define([_AM_AUTOCONF_VERSION], []) - -# AM_SET_CURRENT_AUTOMAKE_VERSION -# ------------------------------- -# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. -# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. -AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.11])dnl -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) - -# AM_AUX_DIR_EXPAND -*- Autoconf -*- - -# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. -# -# This file 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. - -# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets -# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to -# `$srcdir', `$srcdir/..', or `$srcdir/../..'. -# -# Of course, Automake must honor this variable whenever it calls a -# tool from the auxiliary directory. The problem is that $srcdir (and -# therefore $ac_aux_dir as well) can be either absolute or relative, -# depending on how configure is run. This is pretty annoying, since -# it makes $ac_aux_dir quite unusable in subdirectories: in the top -# source directory, any form will work fine, but in subdirectories a -# relative path needs to be adjusted first. -# -# $ac_aux_dir/missing -# fails when called from a subdirectory if $ac_aux_dir is relative -# $top_srcdir/$ac_aux_dir/missing -# fails if $ac_aux_dir is absolute, -# fails when called from a subdirectory in a VPATH build with -# a relative $ac_aux_dir -# -# The reason of the latter failure is that $top_srcdir and $ac_aux_dir -# are both prefixed by $srcdir. In an in-source build this is usually -# harmless because $srcdir is `.', but things will broke when you -# start a VPATH build or use an absolute $srcdir. -# -# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, -# iff we strip the leading $srcdir from $ac_aux_dir. That would be: -# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` -# and then we would define $MISSING as -# MISSING="\${SHELL} $am_aux_dir/missing" -# This will work as long as MISSING is not called from configure, because -# unfortunately $(top_srcdir) has no meaning in configure. -# However there are other variables, like CC, which are often used in -# configure, and could therefore not use this "fixed" $ac_aux_dir. -# -# Another solution, used here, is to always expand $ac_aux_dir to an -# absolute PATH. The drawback is that using absolute paths prevent a -# configured tree to be moved without reconfiguration. - -AC_DEFUN([AM_AUX_DIR_EXPAND], -[dnl Rely on autoconf to set up CDPATH properly. -AC_PREREQ([2.50])dnl -# expand $ac_aux_dir to an absolute path -am_aux_dir=`cd $ac_aux_dir && pwd` -]) - -# AM_CONDITIONAL -*- Autoconf -*- - -# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 -# Free Software Foundation, Inc. -# -# This file 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. - -# serial 9 - -# AM_CONDITIONAL(NAME, SHELL-CONDITION) -# ------------------------------------- -# Define a conditional. -AC_DEFUN([AM_CONDITIONAL], -[AC_PREREQ(2.52)dnl - ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], - [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl -AC_SUBST([$1_TRUE])dnl -AC_SUBST([$1_FALSE])dnl -_AM_SUBST_NOTMAKE([$1_TRUE])dnl -_AM_SUBST_NOTMAKE([$1_FALSE])dnl -m4_define([_AM_COND_VALUE_$1], [$2])dnl -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi -AC_CONFIG_COMMANDS_PRE( -[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([[conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]]) -fi])]) - -# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 -# Free Software Foundation, Inc. -# -# This file 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. - -# serial 10 - -# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be -# written in clear, in which case automake, when reading aclocal.m4, -# will think it sees a *use*, and therefore will trigger all it's -# C support machinery. Also note that it means that autoscan, seeing -# CC etc. in the Makefile, will ask for an AC_PROG_CC use... - - -# _AM_DEPENDENCIES(NAME) -# ---------------------- -# See how the compiler implements dependency checking. -# NAME is "CC", "CXX", "GCJ", or "OBJC". -# We try a few techniques and use that to set a single cache variable. -# -# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was -# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular -# dependency, and given that the user is not expected to run this macro, -# just rely on AC_PROG_CC. -AC_DEFUN([_AM_DEPENDENCIES], -[AC_REQUIRE([AM_SET_DEPDIR])dnl -AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl -AC_REQUIRE([AM_MAKE_INCLUDE])dnl -AC_REQUIRE([AM_DEP_TRACK])dnl - -ifelse([$1], CC, [depcc="$CC" am_compiler_list=], - [$1], CXX, [depcc="$CXX" am_compiler_list=], - [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], - [$1], UPC, [depcc="$UPC" am_compiler_list=], - [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], - [depcc="$$1" am_compiler_list=]) - -AC_CACHE_CHECK([dependency style of $depcc], - [am_cv_$1_dependencies_compiler_type], -[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named `D' -- because `-MD' means `put the output - # in D'. - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_$1_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` - fi - am__universal=false - m4_case([$1], [CC], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac], - [CXX], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac]) - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with - # Solaris 8's {/usr,}/bin/sh. - touch sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with `-c' and `-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle `-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # after this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvisualcpp | msvcmsys) - # This compiler won't grok `-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_$1_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_$1_dependencies_compiler_type=none -fi -]) -AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) -AM_CONDITIONAL([am__fastdep$1], [ - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) -]) - - -# AM_SET_DEPDIR -# ------------- -# Choose a directory name for dependency files. -# This macro is AC_REQUIREd in _AM_DEPENDENCIES -AC_DEFUN([AM_SET_DEPDIR], -[AC_REQUIRE([AM_SET_LEADING_DOT])dnl -AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl -]) - - -# AM_DEP_TRACK -# ------------ -AC_DEFUN([AM_DEP_TRACK], -[AC_ARG_ENABLE(dependency-tracking, -[ --disable-dependency-tracking speeds up one-time build - --enable-dependency-tracking do not reject slow dependency extractors]) -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' -fi -AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) -AC_SUBST([AMDEPBACKSLASH])dnl -_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl -]) - -# Generate code to set up dependency tracking. -*- Autoconf -*- - -# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 -# Free Software Foundation, Inc. -# -# This file 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. - -#serial 5 - -# _AM_OUTPUT_DEPENDENCY_COMMANDS -# ------------------------------ -AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], -[{ - # Autoconf 2.62 quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - case $CONFIG_FILES in - *\'*) eval set x "$CONFIG_FILES" ;; - *) set x $CONFIG_FILES ;; - esac - shift - for mf - do - # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named `Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then - dirpart=`AS_DIRNAME("$mf")` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running `make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # When using ansi2knr, U may be empty or an underscore; expand it - U=`sed -n 's/^U = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`AS_DIRNAME(["$file"])` - AS_MKDIR_P([$dirpart/$fdir]) - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done - done -} -])# _AM_OUTPUT_DEPENDENCY_COMMANDS - - -# AM_OUTPUT_DEPENDENCY_COMMANDS -# ----------------------------- -# This macro should only be invoked once -- use via AC_REQUIRE. -# -# This code is only required when automatic dependency tracking -# is enabled. FIXME. This creates each `.P' file that we will -# need in order to bootstrap the dependency handling code. -AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], -[AC_CONFIG_COMMANDS([depfiles], - [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], - [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) -]) - -# Do all the work for Automake. -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. -# -# This file 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. - -# serial 16 - -# This macro actually does too much. Some checks are only needed if -# your package does certain things. But this isn't really a big deal. - -# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) -# AM_INIT_AUTOMAKE([OPTIONS]) -# ----------------------------------------------- -# The call with PACKAGE and VERSION arguments is the old style -# call (pre autoconf-2.50), which is being phased out. PACKAGE -# and VERSION should now be passed to AC_INIT and removed from -# the call to AM_INIT_AUTOMAKE. -# We support both call styles for the transition. After -# the next Automake release, Autoconf can make the AC_INIT -# arguments mandatory, and then we can depend on a new Autoconf -# release and drop the old call support. -AC_DEFUN([AM_INIT_AUTOMAKE], -[AC_PREREQ([2.62])dnl -dnl Autoconf wants to disallow AM_ names. We explicitly allow -dnl the ones we care about. -m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl -AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl -AC_REQUIRE([AC_PROG_INSTALL])dnl -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi -AC_SUBST([CYGPATH_W]) - -# Define the identity of the package. -dnl Distinguish between old-style and new-style calls. -m4_ifval([$2], -[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl - AC_SUBST([PACKAGE], [$1])dnl - AC_SUBST([VERSION], [$2])], -[_AM_SET_OPTIONS([$1])dnl -dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. -m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, - [m4_fatal([AC_INIT should be called with package and version arguments])])dnl - AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl - AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl - -_AM_IF_OPTION([no-define],, -[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) - AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl - -# Some tools Automake needs. -AC_REQUIRE([AM_SANITY_CHECK])dnl -AC_REQUIRE([AC_ARG_PROGRAM])dnl -AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) -AM_MISSING_PROG(AUTOCONF, autoconf) -AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) -AM_MISSING_PROG(AUTOHEADER, autoheader) -AM_MISSING_PROG(MAKEINFO, makeinfo) -AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl -AC_REQUIRE([AM_PROG_MKDIR_P])dnl -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. -AC_REQUIRE([AC_PROG_AWK])dnl -AC_REQUIRE([AC_PROG_MAKE_SET])dnl -AC_REQUIRE([AM_SET_LEADING_DOT])dnl -_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_PROG_TAR([v7])])]) -_AM_IF_OPTION([no-dependencies],, -[AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES(CC)], - [define([AC_PROG_CC], - defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl -AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES(CXX)], - [define([AC_PROG_CXX], - defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJC], - [_AM_DEPENDENCIES(OBJC)], - [define([AC_PROG_OBJC], - defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl -]) -_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl -dnl The `parallel-tests' driver may need to know about EXEEXT, so add the -dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro -dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. -AC_CONFIG_COMMANDS_PRE(dnl -[m4_provide_if([_AM_COMPILER_EXEEXT], - [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl -]) - -dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not -dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further -dnl mangled by Autoconf and run in a shell conditional statement. -m4_define([_AC_COMPILER_EXEEXT], -m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) - - -# When config.status generates a header, we must update the stamp-h file. -# This file resides in the same directory as the config header -# that is generated. The stamp files are numbered to have different names. - -# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the -# loop where config.status creates the headers, so we can generate -# our stamp files there. -AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], -[# Compute $1's index in $config_headers. -_am_arg=$1 -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) - -# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. -# -# This file 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. - -# AM_PROG_INSTALL_SH -# ------------------ -# Define $install_sh. -AC_DEFUN([AM_PROG_INSTALL_SH], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi -AC_SUBST(install_sh)]) - -# Copyright (C) 2003, 2005 Free Software Foundation, Inc. -# -# This file 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. - -# serial 2 - -# Check whether the underlying file-system supports filenames -# with a leading dot. For instance MS-DOS doesn't. -AC_DEFUN([AM_SET_LEADING_DOT], -[rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null -AC_SUBST([am__leading_dot])]) - -# Check to see how 'make' treats includes. -*- Autoconf -*- - -# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. -# -# This file 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. - -# serial 4 - -# AM_MAKE_INCLUDE() -# ----------------- -# Check to see how make treats includes. -AC_DEFUN([AM_MAKE_INCLUDE], -[am_make=${MAKE-make} -cat > confinc << 'END' -am__doit: - @echo this is the am__doit target -.PHONY: am__doit -END -# If we don't find an include directive, just comment out the code. -AC_MSG_CHECKING([for style of include used by $am_make]) -am__include="#" -am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# Ignore all kinds of additional output from `make'. -case `$am_make -s -f confmf 2> /dev/null` in #( -*the\ am__doit\ target*) - am__include=include - am__quote= - _am_result=GNU - ;; -esac -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - case `$am_make -s -f confmf 2> /dev/null` in #( - *the\ am__doit\ target*) - am__include=.include - am__quote="\"" - _am_result=BSD - ;; - esac -fi -AC_SUBST([am__include]) -AC_SUBST([am__quote]) -AC_MSG_RESULT([$_am_result]) -rm -f confinc confmf -]) - -# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- - -# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 -# Free Software Foundation, Inc. -# -# This file 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. - -# serial 6 - -# AM_MISSING_PROG(NAME, PROGRAM) -# ------------------------------ -AC_DEFUN([AM_MISSING_PROG], -[AC_REQUIRE([AM_MISSING_HAS_RUN]) -$1=${$1-"${am_missing_run}$2"} -AC_SUBST($1)]) - - -# AM_MISSING_HAS_RUN -# ------------------ -# Define MISSING if not defined so far and test if it supports --run. -# If it does, set am_missing_run to use it, otherwise, to nothing. -AC_DEFUN([AM_MISSING_HAS_RUN], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([missing])dnl -if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac -fi -# Use eval to expand $SHELL -if eval "$MISSING --run true"; then - am_missing_run="$MISSING --run " -else - am_missing_run= - AC_MSG_WARN([`missing' script is too old or missing]) -fi -]) - -# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. -# -# This file 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. - -# AM_PROG_MKDIR_P -# --------------- -# Check for `mkdir -p'. -AC_DEFUN([AM_PROG_MKDIR_P], -[AC_PREREQ([2.60])dnl -AC_REQUIRE([AC_PROG_MKDIR_P])dnl -dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, -dnl while keeping a definition of mkdir_p for backward compatibility. -dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. -dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of -dnl Makefile.ins that do not define MKDIR_P, so we do our own -dnl adjustment using top_builddir (which is defined more often than -dnl MKDIR_P). -AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl -case $mkdir_p in - [[\\/$]]* | ?:[[\\/]]*) ;; - */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; -esac -]) - -# Helper functions for option handling. -*- Autoconf -*- - -# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. -# -# This file 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. - -# serial 4 - -# _AM_MANGLE_OPTION(NAME) -# ----------------------- -AC_DEFUN([_AM_MANGLE_OPTION], -[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) - -# _AM_SET_OPTION(NAME) -# ------------------------------ -# Set option NAME. Presently that only means defining a flag for this option. -AC_DEFUN([_AM_SET_OPTION], -[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) - -# _AM_SET_OPTIONS(OPTIONS) -# ---------------------------------- -# OPTIONS is a space-separated list of Automake options. -AC_DEFUN([_AM_SET_OPTIONS], -[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) - -# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) -# ------------------------------------------- -# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. -AC_DEFUN([_AM_IF_OPTION], -[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) - -# Check to make sure that the build environment is sane. -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 -# Free Software Foundation, Inc. -# -# This file 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. - -# serial 5 - -# AM_SANITY_CHECK -# --------------- -AC_DEFUN([AM_SANITY_CHECK], -[AC_MSG_CHECKING([whether build environment is sane]) -# Just in case -sleep 1 -echo timestamp > conftest.file -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[[\\\"\#\$\&\'\`$am_lf]]*) - AC_MSG_ERROR([unsafe absolute working directory name]);; -esac -case $srcdir in - *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) - AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; -esac - -# Do `set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$[*]" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - rm -f conftest.file - if test "$[*]" != "X $srcdir/configure conftest.file" \ - && test "$[*]" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken -alias in your environment]) - fi - - test "$[2]" = conftest.file - ) -then - # Ok. - : -else - AC_MSG_ERROR([newly created file is older than distributed files! -Check your system clock]) -fi -AC_MSG_RESULT(yes)]) - -# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. -# -# This file 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. - -# AM_PROG_INSTALL_STRIP -# --------------------- -# One issue with vendor `install' (even GNU) is that you can't -# specify the program used to strip binaries. This is especially -# annoying in cross-compiling environments, where the build's strip -# is unlikely to handle the host's binaries. -# Fortunately install-sh will honor a STRIPPROG variable, so we -# always use install-sh in `make install-strip', and initialize -# STRIPPROG with the value of the STRIP variable (set by the user). -AC_DEFUN([AM_PROG_INSTALL_STRIP], -[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -# Installed binaries are usually stripped using `strip' when the user -# run `make install-strip'. However `strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the `STRIP' environment variable to overrule this program. -dnl Don't test for $cross_compiling = yes, because it might be `maybe'. -if test "$cross_compiling" != no; then - AC_CHECK_TOOL([STRIP], [strip], :) -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" -AC_SUBST([INSTALL_STRIP_PROGRAM])]) - -# Copyright (C) 2006, 2008 Free Software Foundation, Inc. -# -# This file 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. - -# serial 2 - -# _AM_SUBST_NOTMAKE(VARIABLE) -# --------------------------- -# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. -# This macro is traced by Automake. -AC_DEFUN([_AM_SUBST_NOTMAKE]) - -# AM_SUBST_NOTMAKE(VARIABLE) -# --------------------------- -# Public sister of _AM_SUBST_NOTMAKE. -AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) - -# Check how to create a tarball. -*- Autoconf -*- - -# Copyright (C) 2004, 2005 Free Software Foundation, Inc. -# -# This file 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. - -# serial 2 - -# _AM_PROG_TAR(FORMAT) -# -------------------- -# Check how to create a tarball in format FORMAT. -# FORMAT should be one of `v7', `ustar', or `pax'. -# -# Substitute a variable $(am__tar) that is a command -# writing to stdout a FORMAT-tarball containing the directory -# $tardir. -# tardir=directory && $(am__tar) > result.tar -# -# Substitute a variable $(am__untar) that extract such -# a tarball read from stdin. -# $(am__untar) < result.tar -AC_DEFUN([_AM_PROG_TAR], -[# Always define AMTAR for backward compatibility. -AM_MISSING_PROG([AMTAR], [tar]) -m4_if([$1], [v7], - [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], - [m4_case([$1], [ustar],, [pax],, - [m4_fatal([Unknown tar format])]) -AC_MSG_CHECKING([how to create a $1 tar archive]) -# Loop over all known methods to create a tar archive until one works. -_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' -_am_tools=${am_cv_prog_tar_$1-$_am_tools} -# Do not fold the above two line into one, because Tru64 sh and -# Solaris sh will not grok spaces in the rhs of `-'. -for _am_tool in $_am_tools -do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; - do - AM_RUN_LOG([$_am_tar --version]) && break - done - am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x $1 -w "$$tardir"' - am__tar_='pax -L -x $1 -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H $1 -L' - am__tar_='find "$tardir" -print | cpio -o -H $1 -L' - am__untar='cpio -i -H $1 -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_$1}" && break - - # tar/untar a dummy directory, and stop if the command works - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) - rm -rf conftest.dir - if test -s conftest.tar; then - AM_RUN_LOG([$am__untar /dev/null 2>&1 && break - fi -done -rm -rf conftest.dir - -AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) -AC_MSG_RESULT([$am_cv_prog_tar_$1])]) -AC_SUBST([am__tar]) -AC_SUBST([am__untar]) -]) # _AM_PROG_TAR - diff --git a/config.h.in b/config.h.in deleted file mode 100644 index ff9b343dea..0000000000 --- a/config.h.in +++ /dev/null @@ -1,64 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if stdbool.h conforms to C99. */ -#undef HAVE_STDBOOL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if the system has the type `_Bool'. */ -#undef HAVE__BOOL - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Version number of package */ -#undef VERSION - -/* Define to `unsigned int' if does not define. */ -#undef size_t diff --git a/configure.ac b/configure.ac index 3be7a0f45e..7ce8218ad2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. -AC_PREREQ([2.64]) +AC_PREREQ([2.59]) AC_INIT(bind, 10.0.0, bind10-bugs@isc.org) AC_CONFIG_SRCDIR(README) AM_INIT_AUTOMAKE @@ -10,8 +10,11 @@ AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CXX AC_PROG_CC +AM_CONDITIONAL(GCC, test "$GCC" = yes) AC_PROG_RANLIB +AC_PROG_LIBTOOL + # Checks for libraries. # Checks for header files. @@ -20,6 +23,18 @@ AC_PROG_RANLIB AC_HEADER_STDBOOL AC_TYPE_SIZE_T +# default compiler warning settings +if test "X$GCC" = "Xyes"; then +CXXFLAGS="-g -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare" +fi + +# produce PIC unless we disable share libraries. need this for python bindings. +if test $enable_shared != "no" -a "X$GCC" = "Xyes"; then + CXXFLAGS="$CXXFLAGS -fPIC" +fi + +AC_SUBST(CXXFLAGS) + # # Check availablity of gtest, which will be used for unit tests. # @@ -28,9 +43,17 @@ AC_ARG_WITH(gtest, gtest_path="$withval", gtest_path="no") if test "$gtest_path" != "no" then - GTEST_INCLUDES="-I${gtest_path}/include" - GTEST_LDFLAGS="-L${gtest_path}/lib" - GTEST_LDADD="-lgtest" + if test "$gtest_path" != "yes" + then + GTEST_INCLUDES="-I${gtest_path}/include" + GTEST_LDFLAGS="-L${gtest_path}/lib" + GTEST_LDADD="-lgtest" + else + # todo: check for default paths (/usr and /usr/local?) + GTEST_INCLUDE="-I/usr/include" + GTEST_LDFLAGS="-L/usr/lib" + GTEST_LDADD="-lgtest" + fi else GTEST_INCLUDES= GTEST_LDFLAGS= diff --git a/doc/Doxyfile b/doc/Doxyfile index 34d3e2c973..422e2e367a 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -611,7 +611,7 @@ EXCLUDE_SYMLINKS = NO # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* -EXCLUDE_PATTERNS = *unittest.h +EXCLUDE_PATTERNS = *unittest*.h # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the diff --git a/src/Makefile.in b/src/Makefile.in deleted file mode 100644 index 82d2172fb0..0000000000 --- a/src/Makefile.in +++ /dev/null @@ -1,524 +0,0 @@ -# Makefile.in generated by automake 1.11 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 = : -subdir = src -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac -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 = -SOURCES = -DIST_SOURCES = -RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ - html-recursive info-recursive install-data-recursive \ - install-dvi-recursive install-exec-recursive \ - install-html-recursive install-info-recursive \ - install-pdf-recursive install-ps-recursive install-recursive \ - installcheck-recursive installdirs-recursive pdf-recursive \ - ps-recursive uninstall-recursive -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ - $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ - distdir -ETAGS = etags -CTAGS = ctags -DIST_SUBDIRS = $(SUBDIRS) -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -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@ -GTEST_INCLUDES = @GTEST_INCLUDES@ -GTEST_LDADD = @GTEST_LDADD@ -GTEST_LDFLAGS = @GTEST_LDFLAGS@ -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@ -RANLIB = @RANLIB@ -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_alias = @build_alias@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host_alias = @host_alias@ -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@ -SUBDIRS = lib -all: all-recursive - -.SUFFIXES: -$(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) --foreign src/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign 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): - -# This directory's subdirectories are mostly independent; you can cd -# into them and run `make' without going through this Makefile. -# To change the values of `make' variables: instead of editing Makefiles, -# (1) if the variable is set in `config.status', edit `config.status' -# (which will cause the Makefiles to be regenerated when you run `make'); -# (2) otherwise, pass the desired values on the `make' command line. -$(RECURSIVE_TARGETS): - @failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -$(RECURSIVE_CLEAN_TARGETS): - @failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - rev=''; for subdir in $$list; do \ - if test "$$subdir" = "."; then :; else \ - rev="$$subdir $$rev"; \ - fi; \ - done; \ - rev="$$rev ."; \ - target=`echo $@ | sed s/-recursive//`; \ - for subdir in $$rev; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done && test -z "$$fail" -tags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ - done -ctags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ - done - -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: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - 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: ctags-recursive $(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 - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-recursive -all-am: Makefile -installdirs: installdirs-recursive -installdirs-am: -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -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-recursive - -clean-am: clean-generic mostlyclean-am - -distclean: distclean-recursive - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-generic - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: - -.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ - install-am install-strip tags-recursive - -.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ - all all-am check check-am clean clean-generic ctags \ - ctags-recursive distclean distclean-generic distclean-tags \ - distdir dvi dvi-am html html-am info info-am install \ - install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags \ - tags-recursive uninstall uninstall-am - - -# 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/lib/Makefile.in b/src/lib/Makefile.in deleted file mode 100644 index c994f80e80..0000000000 --- a/src/lib/Makefile.in +++ /dev/null @@ -1,524 +0,0 @@ -# Makefile.in generated by automake 1.11 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 = : -subdir = src/lib -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac -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 = -SOURCES = -DIST_SOURCES = -RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ - html-recursive info-recursive install-data-recursive \ - install-dvi-recursive install-exec-recursive \ - install-html-recursive install-info-recursive \ - install-pdf-recursive install-ps-recursive install-recursive \ - installcheck-recursive installdirs-recursive pdf-recursive \ - ps-recursive uninstall-recursive -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ - $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ - distdir -ETAGS = etags -CTAGS = ctags -DIST_SUBDIRS = $(SUBDIRS) -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -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@ -GTEST_INCLUDES = @GTEST_INCLUDES@ -GTEST_LDADD = @GTEST_LDADD@ -GTEST_LDFLAGS = @GTEST_LDFLAGS@ -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@ -RANLIB = @RANLIB@ -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_alias = @build_alias@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host_alias = @host_alias@ -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@ -SUBDIRS = dns -all: all-recursive - -.SUFFIXES: -$(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) --foreign src/lib/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign src/lib/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): - -# This directory's subdirectories are mostly independent; you can cd -# into them and run `make' without going through this Makefile. -# To change the values of `make' variables: instead of editing Makefiles, -# (1) if the variable is set in `config.status', edit `config.status' -# (which will cause the Makefiles to be regenerated when you run `make'); -# (2) otherwise, pass the desired values on the `make' command line. -$(RECURSIVE_TARGETS): - @failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -$(RECURSIVE_CLEAN_TARGETS): - @failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - rev=''; for subdir in $$list; do \ - if test "$$subdir" = "."; then :; else \ - rev="$$subdir $$rev"; \ - fi; \ - done; \ - rev="$$rev ."; \ - target=`echo $@ | sed s/-recursive//`; \ - for subdir in $$rev; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done && test -z "$$fail" -tags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ - done -ctags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ - done - -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: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - 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: ctags-recursive $(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 - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-recursive -all-am: Makefile -installdirs: installdirs-recursive -installdirs-am: -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -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-recursive - -clean-am: clean-generic mostlyclean-am - -distclean: distclean-recursive - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-generic - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: - -.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ - install-am install-strip tags-recursive - -.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ - all all-am check check-am clean clean-generic ctags \ - ctags-recursive distclean distclean-generic distclean-tags \ - distdir dvi dvi-am html html-am info info-am install \ - install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags \ - tags-recursive uninstall uninstall-am - - -# 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/lib/dns/cpp/Makefile.am b/src/lib/dns/cpp/Makefile.am index bb777d28e6..36b0499a1d 100644 --- a/src/lib/dns/cpp/Makefile.am +++ b/src/lib/dns/cpp/Makefile.am @@ -1,13 +1,17 @@ -lib_LIBRARIES = libdns.a -libdns_a_SOURCES = name.cc name.h +lib_LTLIBRARIES = libdns.la +libdns_la_SOURCES = buffer.h name.cc name.h messagerenderer.h messagerenderer.cc +libdns_la_SOURCES += exceptions.h exceptions.cc TESTS = if HAVE_GTEST TESTS += run_unittests -run_unittests_SOURCES = run_unittests.cc +run_unittests_SOURCES = unittest_util.h unittest_util.cc +run_unittests_SOURCES += buffer_unittest.cc name_unittest.cc +run_unittests_SOURCES += messagerenderer_unittest.cc exceptions_unittest.cc +run_unittests_SOURCES += run_unittests.cc run_unittests_CPPFLAGS = $(GTEST_INCLUDES) run_unittests_LDFLAGS = $(GTEST_LDFLAGS) -run_unittests_LDADD = ./libdns.a $(GTEST_LDADD) +run_unittests_LDADD = .libs/libdns.a $(GTEST_LDADD) endif noinst_PROGRAMS = $(TESTS) diff --git a/src/lib/dns/cpp/buffer.h b/src/lib/dns/cpp/buffer.h new file mode 100644 index 0000000000..b2a79b4103 --- /dev/null +++ b/src/lib/dns/cpp/buffer.h @@ -0,0 +1,401 @@ +// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// $Id$ + +#ifndef __BUFFER_H +#define __BUFFER_H 1 + +#include + +#include + +#include + +#include "exceptions.h" + +namespace isc { +namespace dns { + +/// +/// \brief A standard DNS module exception that is thrown if an out-of-range +/// buffer operation is being performed. +/// +class InvalidBufferPosition : public Exception { +public: + InvalidBufferPosition(const char* file, size_t line, const char* what) : + isc::dns::Exception(file, line, what) {} +}; + +///\brief The \c InputBuffer class is a buffer abstraction for manipulating +/// read-only data. +/// +/// The main purpose of this class is to provide a safe placeholder for +/// examining wire-format data received from a network. +/// +/// Applications normally use this class only in a limited situation: as an +/// interface between legacy I/O operation (such as receiving data from a BSD +/// socket) and the rest of the BIND10 DNS library. One common usage of this +/// class for an application would therefore be something like this: +/// +/// \code unsigned char buf[1024]; +/// struct sockaddr addr; +/// socklen_t addrlen = sizeof(addr); +/// int cc = recvfrom(s, buf, sizeof(buf), 0, &addr, &addrlen); +/// InputBuffer buffer(buf, cc); +/// // pass the buffer to a DNS message object to parse the message \endcode +/// +/// Other BIND10 DNS classes will then use methods of this class to get access +/// to the data, but the application normally doesn't have to care about the +/// details. +/// +/// An \c InputBuffer object internally holds a reference to the given data, +/// rather than make a local copy of the data. Also, it does not have an +/// ownership of the given data. It is application's responsibility to ensure +/// the data remains valid throughout the lifetime of the \c InputBuffer +/// object. Likewise, this object generally assumes the data isn't modified +/// throughout its lifetime; if the application modifies the data while this +/// object retains a reference to it, the result is undefined. The application +/// will also be responsible for releasing the data when it's not needed if it +/// was dynamically acquired. +/// +/// This is a deliberate design choice: although it's safer to make a local +/// copy of the given data on construction, it would cause unacceptable +/// performance overhead, especially considering that a DNS message can be +/// as large as a few KB. Alternatively, we could allow the object to allocate +/// memory internally and expose it to the application to store network data +/// in it. This is also a bad design, however, in that we would effectively +/// break the abstraction employed in the class, and do so by publishing +/// "read-only" stuff as a writable memory region. Since there doesn't seem to +/// be a perfect solution, we have adopted what we thought a "least bad" one. +/// +/// Methods for reading data from the buffer generally work like an input +/// stream: it begins with the head of the data, and once some length of data +/// is read from the buffer, the next read operation will take place from the +/// head of the unread data. An object of this class internally holds (a +/// notion of) where the next read operation should start. We call it the +/// read position in this document. +class InputBuffer { +public: + /// + /// \name Constructors and Destructor + //@{ + /// \brief Constructor from variable length of data. + /// + /// It is caller's responsibility to ensure that the data is valid as long + /// as the buffer exists. + /// \param data A pointer to the data stored in the buffer. + /// \param len The length of the data in bytes. + InputBuffer(const void* data, size_t len) : + position_(0), data_(static_cast(data)), len_(len) {} + //@} + + /// + /// \name Getter Methods + //@{ + /// \brief Return the length of the data stored in the buffer. + size_t getLength() const { return (len_); } + /// \brief Return the current read position. + size_t getPosition() const { return (position_); } + //@} + + /// + /// \name Setter Methods + /// + //@{ + /// \brief Set the read position of the buffer to the given value. + /// + /// The new position must be in the valid range of the buffer; otherwise + /// an exception of class \c isc::dns::InvalidBufferPosition will be thrown. + /// \param position The new position (offset from the beginning of the + /// buffer). + void setPosition(size_t position) + { + if (position > len_) + dns_throw(InvalidBufferPosition, "position is too large"); + position_ = position; + } + //@} + + /// + /// \name Methods for reading data from the buffer. + //@{ + /// \brief Read an unsigned 8-bit integer from the buffer and return it. + /// + /// If the remaining length of the buffer is smaller than 8-bit, an + /// exception of class \c isc::dns::InvalidBufferPosition will be thrown. + uint8_t readUint8() + { + if (position_ + sizeof(uint8_t) > len_) { + dns_throw(InvalidBufferPosition, "read beyond end of buffer"); + } + + return (data_[position_++]); + } + /// \brief Read an unsigned 16-bit integer in network byte order from the + /// buffer, convert it to host byte order, and return it. + /// + /// If the remaining length of the buffer is smaller than 16-bit, an + /// exception of class \c isc::dns::InvalidBufferPosition will be thrown. + uint16_t readUint16() + { + uint16_t data; + const uint8_t* cp; + + if (position_ + sizeof(data) > len_) { + dns_throw(InvalidBufferPosition, "read beyond end of buffer"); + } + + cp = &data_[position_]; + data = ((unsigned int)(cp[0])) << 8; + data |= ((unsigned int)(cp[1])); + position_ += sizeof(data); + + return (data); + } + /// \brief Read an unsigned 32-bit integer in network byte order from the + /// buffer, convert it to host byte order, and return it. + /// + /// If the remaining length of the buffer is smaller than 32-bit, an + /// exception of class \c isc::dns::InvalidBufferPosition will be thrown. + uint32_t readUint32() + { + uint32_t data; + const uint8_t* cp; + + if (position_ + sizeof(data) > len_) { + dns_throw(InvalidBufferPosition, "read beyond end of buffer"); + } + + cp = &data_[position_]; + data = ((unsigned int)(cp[0])) << 24; + data |= ((unsigned int)(cp[1])) << 16; + data |= ((unsigned int)(cp[2])) << 8; + data |= ((unsigned int)(cp[3])); + position_ += sizeof(data); + + return (data); + } + /// \brief Read data of the specified length from the buffer and copy it to + /// the caller supplied buffer. + /// + /// The data is copied as stored in the buffer; no conversion is performed. + /// If the remaining length of the buffer is smaller than the specified + /// length, an exception of class \c isc::dns::InvalidBufferPosition will + /// be thrown. + void readData(void* data, size_t len) + { + if (position_ + len > len_) { + dns_throw(InvalidBufferPosition, "read beyond end of buffer"); + } + + memcpy(data, &data_[position_], len); + position_ += len; + } + //@} + +private: + size_t position_; + const uint8_t* data_; + size_t len_; +}; + +/// +///\brief The \c OutputBuffer class is a buffer abstraction for manipulating +/// mutable data. +/// +/// The main purpose of this class is to provide a safe workplace for +/// constructing wire-format data to be sent out to a network. Here, +/// safe means that it automatically allocates necessary memory and +/// avoid buffer overrun. +/// +/// Like for the \c InputBuffer class, applications normally use this class only +/// in a limited situation. One common usage of this class for an application +/// would be something like this: +/// +/// \code OutputBuffer buffer(4096); // give a sufficiently large initial size +/// // pass the buffer to a DNS message object to construct a wire-format +/// // DNS message. +/// struct sockaddr to; +/// sendto(s, buffer.getData(), buffer.getLength(), 0, &to, sizeof(to)); +/// \endcode +/// +/// where the \c getData() method gives a reference to the internal memory +/// region stored in the \c buffer object. This is a suboptimal design in that +/// it exposes an encapsulated "handle" of an object to its user. +/// Unfortunately, there is no easy way to avoid this without involving +/// expensive data copy if we want to use this object with a legacy API such as +/// a BSD socket interface. And, indeed, this is one major purpose for this +/// object. Applications should use this method only under such a special +/// circumstance. It should also be noted that the memory region returned by +/// \c getData() may be invalidated after a subsequent write operation. +/// +/// An \c OutputBuffer class object automatically extends its memory region when +/// data is written beyond the end of the current buffer. However, it will +/// involve performance overhead such as reallocating more memory and copying +/// data. It is therefore recommended to construct the buffer object with a +/// sufficiently large initial size. +/// The \c getCapacity() method provides the current maximum size of data +/// (including the portion already written) that can be written into the buffer +/// without causing memory reallocation. +/// +/// Methods for writing data into the buffer generally work like an output +/// stream: it begins with the head of the buffer, and once some length of data +/// is written into the buffer, the next write operation will take place from +/// the end of the buffer. Other methods to emulate "random access" are also +/// provided (e.g., \c writeUint16At()). The normal write operations are +/// normally exception-free as this class automatically extends the buffer +/// when necessary. However, in extreme cases such as an attempt of writing +/// multi-GB data, a separate exception (e.g., \c std::bad_alloc) may be thrown +/// by the system. This also applies to the constructor with a very large +/// initial size. +/// +/// Note to developers: it may make more sense to introduce an abstract base +/// class for the \c OutputBuffer and define the simple implementation as a +/// a concrete derived class. That way we can provide flexibility for future +/// extension such as more efficient buffer implementation or allowing users +/// to have their own customized version without modifying the source code. +/// We in fact considered that option, but at the moment chose the simpler +/// approach with a single concrete class because it may make the +/// implementation unnecessarily complicated while we were still not certain +/// if we really want that flexibility. We may revisit the class design as +/// we see more applications of the class. The same considerations apply to +/// the \c InputBuffer and \c MessageRenderer classes. +class OutputBuffer { +public: + /// + /// \name Constructors and Destructor + /// + //@{ + /// \brief Constructor from the initial size of the buffer. + /// + /// \param len The initial length of the buffer in bytes. + OutputBuffer(size_t len) { data_.reserve(len); } + //@} + + /// + /// \name Getter Methods + /// + //@{ + /// \brief Return the current capacity of the buffer. + size_t getCapacity() const { return (data_.capacity()); } + /// \brief Return a pointer to the head of the data stored in the buffer. + /// + /// The caller can assume that the subsequent \c getLength() bytes are + /// identical to the stored data of the buffer. + /// + /// Note: The pointer returned by this method may be invalidated after a + /// subsequent write operation. + const void* getData() const { return (&data_[0]); } + /// \brief Return the length of data written in the buffer. + size_t getLength() const { return (data_.size()); } + /// \brief Return the value of the buffer at the specified position. + /// + /// \c pos must specify the valid position of the buffer; otherwise an + /// exception class of \c InvalidBufferPosition will be thrown. + /// + /// \param pos The position in the buffer to be returned. + uint8_t operator[](size_t pos) const + { + if (pos >= data_.size()) { + dns_throw(InvalidBufferPosition, "read at invalid position"); + } + return (data_[pos]); + } + //@} + + /// + /// \name Methods for writing data into the buffer. + /// + //@{ + /// \brief Insert a specified length of gap at the end of the buffer. + /// + /// The caller should not assume any particular value to be inserted. + /// This method is provided as a shortcut to make a hole in the buffer + /// that is to be filled in later, e.g, by \ref writeUint16At(). + /// \param len The length of the gap to be inserted in bytes. + void skip(size_t len) { data_.insert(data_.end(), len, 0); } + /// \brief Clear buffer content. + /// + /// This method can be used to re-initialize and reuse the buffer without + /// constructing a new one. + void clear() { data_.clear(); } + /// \brief Write an unsigned 8-bit integer into the buffer. + /// + /// \param data The 8-bit integer to be written into the buffer. + void writeUint8(uint8_t data) { data_.push_back(data); } + + /// \brief Write an unsigned 16-bit integer in host byte order into the + /// buffer in network byte order. + /// + /// \param data The 16-bit integer to be written into the buffer. + void writeUint16(uint16_t data) + { + data_.push_back(static_cast((data & 0xff00U) >> 8)); + data_.push_back(static_cast(data & 0x00ffU)); + } + /// \brief Write an unsigned 16-bit integer in host byte order at the + /// specified position of the buffer in network byte order. + /// + /// The buffer must have a sufficient room to store the given data at the + /// given position, that is, pos + 2 < getLength(); + /// otherwise an exception of class \c isc::dns::InvalidBufferPosition will + /// be thrown. + /// Note also that this method never extends the buffer. + /// + /// \param data The 16-bit integer to be written into the buffer. + /// \param pos The beginning position in the buffer to write the data. + void writeUint16At(uint16_t data, size_t pos) + { + if (pos + sizeof(data) >= data_.size()) { + dns_throw(InvalidBufferPosition, "write at invalid position"); + } + + data_[pos] = static_cast((data & 0xff00U) >> 8); + data_[pos + 1] = static_cast(data & 0x00ffU); + } + /// \brief Write an unsigned 32-bit integer in host byte order + /// into the buffer in network byte order. + /// + /// \param data The 32-bit integer to be written into the buffer. + void writeUint32(uint32_t data) + { + data_.push_back(static_cast((data & 0xff000000) >> 24)); + data_.push_back(static_cast((data & 0x00ff0000) >> 16)); + data_.push_back(static_cast((data & 0x0000ff00) >> 8)); + data_.push_back(static_cast(data & 0x000000ff)); + } + /// \brief Copy an arbitrary length of data into the buffer. + /// + /// No conversion on the copied data is performed. + /// + /// \param data A pointer to the data to be copied into the buffer. + /// \param len The length of the data in bytes. + void writeData(const void *data, size_t len) + { + const uint8_t* cp = static_cast(data); + data_.insert(data_.end(), cp, cp + len); + } + //@} + +private: + std::vector data_; +}; +} +} +#endif // __BUFFER_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/cpp/buffer_unittest.cc b/src/lib/dns/cpp/buffer_unittest.cc new file mode 100644 index 0000000000..91babaa5d3 --- /dev/null +++ b/src/lib/dns/cpp/buffer_unittest.cc @@ -0,0 +1,167 @@ +// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// $Id$ + +#include "buffer.h" + +#include + +namespace { + +using isc::dns::InputBuffer; +using isc::dns::OutputBuffer; + +class BufferTest : public ::testing::Test { +protected: + BufferTest() : ibuffer(testdata, sizeof(testdata)), obuffer(0), + expected_size(0) + { + data16 = (2 << 8) | 3; + data32 = (4 << 24) | (5 << 16) | (6 << 8) | 7; + } + + InputBuffer ibuffer; + OutputBuffer obuffer; + static const uint8_t testdata[5]; + uint8_t vdata[sizeof(testdata)]; + size_t expected_size; + uint16_t data16; + uint32_t data32; +}; + +const uint8_t BufferTest::testdata[5] = {1, 2, 3, 4, 5}; + +TEST_F(BufferTest, input_buffer_read) +{ + EXPECT_EQ(5, ibuffer.getLength()); + EXPECT_EQ(1, ibuffer.readUint8()); + EXPECT_EQ(1, ibuffer.getPosition()); + data16 = ibuffer.readUint16(); + EXPECT_EQ((2 << 8) | 3, data16); + EXPECT_EQ(3, ibuffer.getPosition()); + ibuffer.setPosition(1); + EXPECT_EQ(1, ibuffer.getPosition()); + data32 = ibuffer.readUint32(); + EXPECT_EQ((2 << 24) | (3 << 16) | (4 << 8) | 5, data32); + ibuffer.setPosition(0); + memset(vdata, 0, sizeof(vdata)); + ibuffer.readData(vdata, sizeof(vdata)); + EXPECT_EQ(0, memcmp(vdata, testdata, sizeof(testdata))); +} + +TEST_F(BufferTest, input_buffer_exception) +{ + EXPECT_THROW(ibuffer.setPosition(6), isc::dns::InvalidBufferPosition); + + ibuffer.setPosition(sizeof(testdata)); + EXPECT_THROW(ibuffer.readUint8(), isc::dns::InvalidBufferPosition); + + ibuffer.setPosition(sizeof(testdata) - 1); + EXPECT_THROW(ibuffer.readUint16(), isc::dns::InvalidBufferPosition); + + ibuffer.setPosition(sizeof(testdata) - 3); + EXPECT_THROW(ibuffer.readUint32(), isc::dns::InvalidBufferPosition); + + ibuffer.setPosition(sizeof(testdata) - 4); + EXPECT_THROW(ibuffer.readData(vdata, sizeof(vdata)), + isc::dns::InvalidBufferPosition); +} + +TEST_F(BufferTest, output_buffer_extend) +{ + EXPECT_EQ(0, obuffer.getCapacity()); + EXPECT_EQ(0, obuffer.getLength()); + obuffer.writeUint8(10); + EXPECT_LT(0, obuffer.getCapacity()); + EXPECT_EQ(1, obuffer.getLength()); +} + +TEST_F(BufferTest, output_buffer_write) +{ + const uint8_t* cp; + + obuffer.writeUint8(1); + expected_size += sizeof(uint8_t); + EXPECT_EQ(expected_size, obuffer.getLength()); + cp = static_cast(obuffer.getData()); + EXPECT_EQ(1, *cp); + + obuffer.writeUint16(data16); + expected_size += sizeof(data16); + cp = static_cast(obuffer.getData()); + EXPECT_EQ(expected_size, obuffer.getLength()); + EXPECT_EQ(2, *(cp + 1)); + EXPECT_EQ(3, *(cp + 2)); + + obuffer.writeUint32(data32); + expected_size += sizeof(data32); + cp = static_cast(obuffer.getData()); + EXPECT_EQ(expected_size, obuffer.getLength()); + EXPECT_EQ(4, *(cp + 3)); + EXPECT_EQ(5, *(cp + 4)); + EXPECT_EQ(6, *(cp + 5)); + EXPECT_EQ(7, *(cp + 6)); + + obuffer.writeData(testdata, sizeof(testdata)); + expected_size += sizeof(testdata); + EXPECT_EQ(expected_size, obuffer.getLength()); + cp = static_cast(obuffer.getData()); + EXPECT_EQ(0, memcmp(cp + 7, testdata, sizeof(testdata))); +} + +TEST_F(BufferTest, output_buffer_writeat) +{ + obuffer.writeUint32(data32); + expected_size += sizeof(data32); + obuffer.writeUint16At(data16, 1); + EXPECT_EQ(expected_size, obuffer.getLength()); // length shouldn't change + + const uint8_t* cp = static_cast(obuffer.getData()); + EXPECT_EQ(2, *(cp + 1)); + EXPECT_EQ(3, *(cp + 2)); + + EXPECT_THROW(obuffer.writeUint16At(data16, 3), + isc::dns::InvalidBufferPosition); + EXPECT_THROW(obuffer.writeUint16At(data16, 4), + isc::dns::InvalidBufferPosition); + EXPECT_THROW(obuffer.writeUint16At(data16, 5), + isc::dns::InvalidBufferPosition); +} + +TEST_F(BufferTest, output_buffer_skip) +{ + obuffer.skip(4); + EXPECT_EQ(4, obuffer.getLength()); + + obuffer.skip(2); + EXPECT_EQ(6, obuffer.getLength()); +} + +TEST_F(BufferTest, output_buffer_readat) +{ + obuffer.writeData(testdata, sizeof(testdata)); + for (int i = 0; i < sizeof(testdata); i ++) { + EXPECT_EQ(testdata[i], obuffer[i]); + } + EXPECT_THROW(obuffer[sizeof(testdata)], isc::dns::InvalidBufferPosition); +} + +TEST_F(BufferTest, output_buffer_clear) +{ + obuffer.writeData(testdata, sizeof(testdata)); + obuffer.clear(); + EXPECT_EQ(0, obuffer.getLength()); +} +} diff --git a/src/lib/dns/cpp/exceptions.cc b/src/lib/dns/cpp/exceptions.cc new file mode 100644 index 0000000000..cc6ffc8d90 --- /dev/null +++ b/src/lib/dns/cpp/exceptions.cc @@ -0,0 +1,45 @@ +// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// $Id$ + +#include + +#include "exceptions.h" + +using isc::dns::Exception; + +namespace isc { +namespace dns { + +const char* +Exception::what() const throw() +{ + const char* whatstr = "isc::dns::Exception"; + + // XXX: even though it's very unlikely that c_str() throws an exception, + // it's still not 100% guaranteed. To meet the exception specification + // of this function, we catch any unexpected exception and fall back to + // the pre-defined constant. + try { + whatstr = what_.c_str(); + } catch (...) { + // no exception handling is necessary. just have to catch exceptions. + } + + return (whatstr); +} + +} +} diff --git a/src/lib/dns/cpp/exceptions.h b/src/lib/dns/cpp/exceptions.h new file mode 100644 index 0000000000..a7cdcf24fa --- /dev/null +++ b/src/lib/dns/cpp/exceptions.h @@ -0,0 +1,117 @@ +// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// $Id$ + +#ifndef __EXCEPTIONS_H +#define __EXCEPTIONS_H 1 + +#include +#include + +namespace isc { +namespace dns { + +/// +/// This is a base class for exceptions thrown from the DNS library module. +/// Normally, the exceptions are thrown via a convenient shortcut macro, +/// @ref dns_throw, which automatically gives trivial parameters for the +/// exception such as the file name and line number where the exception is +/// triggered. +/// +class Exception : public std::exception { +public: + /// + /// \name Constructors and Destructor + /// + //@{ + /// \brief Constructor for a given type for exceptions with file name and + /// file line number. + /// + /// @param file the file name where the exception was thrown. + /// @param line the line in @ref file where the exception was thrown. + /// @param what a description (type) of the exception. + Exception(const char* file, size_t line, const char* what) : + file_(file), line_(line), what_(what) {} + /// The destructor + virtual ~Exception() throw() {} + //@} +private: + /// + /// The assignment operator is intentionally disabled. + /// + void operator=(const Exception& src); + +public: + /// + /// \name Methods Reimplemented against the Standard Exception Class + /// + //@{ + /// \brief Returns a C-style character string of the cause of the exception. + /// + /// Note: we normally don't use exception specifications, but this is an + /// "exception" to that policy as it's enforced by the base class. + /// + /// @return A C-style character string of the exception cause. + virtual const char* what() const throw(); + //@} + + /// + /// \name Getter Methods + /// + //@{ + /// \brief Gets a string describing the cause of the exception. + /// + /// @return the cause string. + const std::string& getMessage() const { return (what_); } + + /// \brief Gets the file name where the exception was thrown. + /// + /// @return a C-style string of the file name. + const char* getFile() const { return (file_); } + + /// \brief Gets the line number of the file where the exception was thrown. + /// + /// @return an integer specifying the line number. + size_t getLine() const { return (line_); } + //@} + +private: + const char* const file_; + size_t line_; + const std::string what_; +}; + +/// +/// \brief A standard DNS module exception that is thrown if a parameter give +/// to a method would refer to or modify out-of-range data. +/// +class OutOfRange : public Exception { +public: + OutOfRange(const char* file, size_t line, const char* what) : + isc::dns::Exception(file, line, what) {} +}; + +/// +/// A shortcut macro to insert known values into exception arguments. +/// +#define dns_throw(type, args...) throw type(__FILE__, __LINE__, args) + +} +} +#endif // __EXCEPTIONS_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/cpp/exceptions_unittest.cc b/src/lib/dns/cpp/exceptions_unittest.cc new file mode 100644 index 0000000000..258886738a --- /dev/null +++ b/src/lib/dns/cpp/exceptions_unittest.cc @@ -0,0 +1,52 @@ +// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// $Id$ + +#include +#include + +#include "exceptions.h" + +#include + +using isc::dns::Exception; + +namespace { + +class ExceptionTest : public ::testing::Test { +protected: + ExceptionTest() : teststring("test") {} + const char* teststring; +}; + +TEST_F(ExceptionTest, BasicMethods) { + try { + dns_throw(Exception, teststring); + } catch (Exception& ex) { + EXPECT_EQ(ex.getMessage(), std::string(teststring)); + EXPECT_EQ(ex.getFile(), std::string(__FILE__)); + EXPECT_EQ(ex.getLine(), __LINE__ - 4); + } +} + +// Test to see if it works as a proper derived class of std::exception. +TEST_F(ExceptionTest, StdInheritance) { + try { + dns_throw(Exception, teststring); + } catch (std::exception& ex) { + EXPECT_EQ(std::string(ex.what()), std::string(teststring)); + } +} +} diff --git a/src/lib/dns/cpp/messagerenderer.cc b/src/lib/dns/cpp/messagerenderer.cc new file mode 100644 index 0000000000..303ad7fc4e --- /dev/null +++ b/src/lib/dns/cpp/messagerenderer.cc @@ -0,0 +1,210 @@ +// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// $Id$ + +#include +#include +#include + +#include "buffer.h" +#include "name.h" +#include "messagerenderer.h" + +namespace isc { +namespace dns { + +namespace { // hide internal-only names from the public namespaces +/// +/// \brief The \c NameCompressNode class represents a pointer to a name +/// rendered in the internal buffer for the \c MessageRendererImpl object. +/// +/// A \c MessageRendererImpl object maintains a set of the \c NameCompressNode +/// objects, and searches the set for the position of the longest match +/// (ancestor) name against each new name to be rendered into the buffer. +struct NameCompressNode { + NameCompressNode(const OutputBuffer& buffer, size_t pos, size_t len) : + buffer_(buffer), pos_(pos), len_(len) {} + /// The buffer in which the corresponding name is rendered. + const OutputBuffer& buffer_; + /// The position (offset from the beginning) in the buffer where the + /// name starts. + uint16_t pos_; + /// The length of the corresponding name. + uint16_t len_; +}; + +/// +/// \brief The \c NameCompare class is a functor that gives ordering among +/// \c NameCompressNode objects stored in \c MessageRendererImpl::nodeset_. +/// +/// Its only public method as a functor, \c operator(), gives the ordering +/// between two \c NameCompressNode objects in terms of equivalence, that is, +/// returns whether one is "less than" the other. +/// For our purpose we only need to distinguish two different names, so the +/// ordering is different from the canonical DNS name order used in DNSSEC; +/// basically, it gives the case-insensitive ordering of the two names as their +/// textual representation. +struct NameCompare : public std::binary_function { + /// + /// Returns true if n1 < n2 as a result of case-insensitive comparison; + /// otherwise return false. + /// + /// The name corresponding to \c n1 or \c n2 may be compressed, in which + /// case we must follow the compression pointer in the associated buffer. + /// The helper private method \c nextPosition() gives the position in the + /// buffer for the next character, taking into account compression. + /// + bool operator()(const NameCompressNode& n1, + const NameCompressNode& n2) const + { + if (n1.len_ < n2.len_) { + return (true); + } else if (n1.len_ > n2.len_) { + return (false); + } + + uint16_t pos1 = n1.pos_; + uint16_t pos2 = n2.pos_; + uint16_t l1 = 0; + uint16_t l2 = 0; + for (uint16_t i = 0; i < n1.len_; i++, pos1++, pos2++) { + pos1 = nextPosition(n1.buffer_, pos1, l1); + pos2 = nextPosition(n2.buffer_, pos2, l2); + if (tolower(n1.buffer_[pos1]) < tolower(n2.buffer_[pos2])) { + return (true); + } else if (tolower(n1.buffer_[pos1]) > tolower(n2.buffer_[pos2])) { + return (false); + } + } + + return (false); + } + +private: + uint16_t nextPosition(const OutputBuffer& buffer, + uint16_t pos, uint16_t& llen) const + { + if (llen == 0) { + int i = 0; + + while ((buffer[pos] & Name::COMPRESS_POINTER_MARK8) == + Name::COMPRESS_POINTER_MARK8) { + pos = (buffer[pos] & ~Name::COMPRESS_POINTER_MARK8) * + 256 + buffer[pos + 1]; + + // This loop should stop as long as the buffer has been + // constructed validly and the search/insert argument is based + // on a valid name, which is an assumption for this class. + // But we'll abort if a bug could cause an infinite loop. + i += 2; + assert(i < Name::MAX_WIRE); + } + llen = buffer[pos]; + } else { + --llen; + } + return (pos); + } +}; +} + +/// +/// \brief The \c MessageRendererImpl class is the actual implementation of +/// \c MessageRenderer. +/// +/// The implementation is hidden from applications. We can refer to specific +/// members of this class only within this file. +/// +struct MessageRendererImpl { + /// \brief Constructor from an output buffer. + /// + /// \param buffer An \c OutputBuffer object to which wire format data is + /// written. + MessageRendererImpl(OutputBuffer& buffer) : + buffer_(buffer), nbuffer_(Name::MAX_WIRE) {} + /// The buffer that holds the entire DNS message. + OutputBuffer& buffer_; + /// A local working buffer to convert each given name into wire format. + /// This could be a local variable of the \c writeName() method, but + /// we keep it in the class so that we can reuse it and avoid construction + /// overhead. + OutputBuffer nbuffer_; + /// A set of compression pointers. + std::set nodeset_; +}; + +MessageRenderer::MessageRenderer(OutputBuffer& buffer) : + impl_(new MessageRendererImpl(buffer)) +{} + +MessageRenderer::~MessageRenderer() +{ + delete impl_; +} + +void +MessageRenderer::writeName(const Name& name, bool compress) +{ + impl_->nbuffer_.clear(); + name.toWire(impl_->nbuffer_); + + unsigned int i; + std::set::const_iterator n; + + // Find the longest ancestor name in the rendered set that matches the + // given name. + for (i = 0; i < impl_->nbuffer_.getLength(); i += impl_->nbuffer_[i] + 1) { + // skip the trailing null label + if (impl_->nbuffer_[i] == 0) { + continue; + } + n = impl_->nodeset_.find(NameCompressNode(impl_->nbuffer_, i, + impl_->nbuffer_.getLength() - + i)); + if (n != impl_->nodeset_.end()) { + break; + } + } + + // Record the current offset before extending the buffer. + size_t offset = impl_->buffer_.getLength(); + // Write uncompress part... + impl_->buffer_.writeData(impl_->nbuffer_.getData(), + compress ? i : impl_->nbuffer_.getLength()); + if (compress && n != impl_->nodeset_.end()) { + // ...and compression pointer if available. + uint16_t pointer = (*n).pos_; + pointer |= Name::COMPRESS_POINTER_MARK16; + impl_->buffer_.writeUint16(pointer); + } + + // Finally, add to the set the newly rendered name and its ancestors that + // have not been in the set. + for (unsigned int j = 0; j < i; j += impl_->nbuffer_[j] + 1) { + if (impl_->nbuffer_[j] == 0) { + continue; + } + if (offset + j > Name::MAX_COMPRESS_POINTER) { + break; + } + impl_->nodeset_.insert(NameCompressNode(impl_->buffer_, offset + j, + impl_->nbuffer_.getLength() - + j)); + } +} +} +} diff --git a/src/lib/dns/cpp/messagerenderer.h b/src/lib/dns/cpp/messagerenderer.h new file mode 100644 index 0000000000..87ce196f86 --- /dev/null +++ b/src/lib/dns/cpp/messagerenderer.h @@ -0,0 +1,118 @@ +// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// $Id$ + +#ifndef __MESSAGERENDERER_H +#define __MESSAGERENDERER_H 1 + +namespace isc { +namespace dns { +// forward declarations +class OutputBuffer; +class Name; +class MessageRendererImpl; + +/// +/// \brief The \c MessageRenderer class encapsulates implementation details +/// of rendering a DNS message into a buffer in wire format. +/// +/// In effect, it's simply responsible for name compression at least in the +/// current implementation. A \c MessageRenderer class object manages the +/// positions of names rendered in a buffer and uses that information to render +/// subsequent names with compression. +/// +/// This class is mainly intended to be used as a helper for a more +/// comprehensive \c Message class internally; normal applications won't have +/// to care about this class. +/// +/// A \c MessageRenderer class object is constructed with a \c OutputBuffer +/// object, which is the buffer into which the rendered data will be written. +/// Normally the buffer is expected to be empty on construction, but it doesn't +/// have to be so; the \c MessageRenderer object will start rendering from the +/// end of the buffer at the time of construction. However, if the +/// pre-existing portion of the buffer contains DNS names, these names won't +/// be considered for name compression. +/// +/// Once a \c MessageRenderer object is constructed with a buffer, it is +/// generally expected that all rendering operations are performed via the +/// \c MessageRenderer object. If the application modifies the buffer in +/// parallel with the \c MessageRenderer, the result will be undefined. +/// +/// Note to developers: we introduced a separate class for name compression +/// because previous benchmark with BIND9 showed compression affects overall +/// response performance very much. By having a separate class dedicated for +/// this purpose, we'll be able to change the internal implementation of name +/// compression in the future without affecting other part of the API and +/// implementation. For the same reason, we adopt the "pimpl" idiom in the +/// class definition (i.e., using a pointer to a \c MessageRendererImpl class, +/// which is defined with the class implementation, not in the header file): +/// we may want to modify the compression implementation without modifying the +/// header file thereby requesting rebuild the package. +/// +/// Furthermore, we may eventually want to allow other developers to develop +/// and use their own compression implementation. Should such a case become +/// realistic, we may want to make the \c MessageRendererImpl class an abstract +/// base class and let concrete derived classes have their own implementations. +/// At the moment we don't the strong need for it, so we rather avoid over +/// abstraction and keep the definition simpler. +class MessageRenderer { +public: + /// + /// \name Constructors and Destructor + //@{ + /// \brief Constructor from an output buffer. + /// + /// \param buffer An \c OutputBuffer object to which wire format data is + /// written. + MessageRenderer(OutputBuffer& buffer); + /// \brief The default destructor. + /// + /// The destructor does nothing on the given \c buffer on construction; + /// in fact, it is expected that the user will use the resulting buffer + /// for some post rendering purposes (e.g., send the data to the network). + /// It's user's responsibility to do any necessary cleanup for the + /// \c buffer. + ~MessageRenderer(); + //@} + + /// + /// \name Rendering Methods + /// + //@{ + /// \brief Write a \c Name object into the internal buffer in wire format, + /// with or without name compression. + /// + /// If the optional parameter \c compress is \c true, this method tries to + /// compress the \c name if possible, searching the entire message that has + /// been rendered. Otherwise name compression is omitted. Its default + /// value is \c true. + /// + /// Note: even if \c compress is \c true, the position of the \c name (and + /// possibly its ancestor names) in the message is recorded and may be used + /// for compressing subsequent names. + /// + /// \param name A \c Name object to be written. + /// \param compress A boolean indicating whether to enable name compression. + void writeName(const Name& name, bool compress = true); +private: + MessageRendererImpl* impl_; +}; +} +} +#endif // __MESSAGERENDERER_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/dns/cpp/messagerenderer_unittest.cc b/src/lib/dns/cpp/messagerenderer_unittest.cc new file mode 100644 index 0000000000..103a614712 --- /dev/null +++ b/src/lib/dns/cpp/messagerenderer_unittest.cc @@ -0,0 +1,96 @@ +// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// $Id$ + +#include + +#include "buffer.h" +#include "name.h" +#include "messagerenderer.h" + +#include "unittest_util.h" + +#include + +using isc::UnitTestUtil; +using isc::dns::OutputBuffer; +using isc::dns::Name; +using isc::dns::MessageRenderer; + +namespace { +class MessageRendererTest : public ::testing::Test { +protected: + MessageRendererTest() : buffer(0), renderer(buffer) {} + OutputBuffer buffer; + MessageRenderer renderer; + std::vector data; +}; + +TEST_F(MessageRendererTest, toWire) +{ + UnitTestUtil::readWireData("testdata/name_toWire1", data); + renderer.writeName(Name("a.example.com.")); + renderer.writeName(Name("b.example.com.")); + renderer.writeName(Name("a.example.org.")); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(), + buffer.getLength(), &data[0], data.size()); +} + +TEST_F(MessageRendererTest, toWireInLargeBuffer) +{ + size_t offset = 0x3fff; + buffer.skip(offset); + + UnitTestUtil::readWireData("testdata/name_toWire2", data); + renderer.writeName(Name("a.example.com.")); + renderer.writeName(Name("a.example.com.")); + renderer.writeName(Name("b.example.com.")); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, + static_cast(buffer.getData()) + offset, + buffer.getLength() - offset, + &data[0], data.size()); +} + +TEST_F(MessageRendererTest, toWireWithUncompressed) +{ + UnitTestUtil::readWireData("testdata/name_toWire3", data); + renderer.writeName(Name("a.example.com.")); + renderer.writeName(Name("b.example.com."), false); + renderer.writeName(Name("b.example.com.")); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(), + buffer.getLength(), &data[0], data.size()); +} + +TEST_F(MessageRendererTest, toWirePointerChain) +{ + UnitTestUtil::readWireData("testdata/name_toWire4", data); + renderer.writeName(Name("a.example.com.")); + renderer.writeName(Name("b.example.com.")); + renderer.writeName(Name("b.example.com.")); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(), + buffer.getLength(), &data[0], data.size()); +} + +TEST_F(MessageRendererTest, toWireCaseCompress) +{ + UnitTestUtil::readWireData("testdata/name_toWire1", data); + renderer.writeName(Name("a.example.com.")); + // this should match the first name in terms of compression: + renderer.writeName(Name("b.exAmple.CoM.")); + renderer.writeName(Name("a.example.org.")); + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(), + buffer.getLength(), &data[0], data.size()); +} +} diff --git a/src/lib/dns/cpp/name.cc b/src/lib/dns/cpp/name.cc index ff0007ae50..5a2c557628 100644 --- a/src/lib/dns/cpp/name.cc +++ b/src/lib/dns/cpp/name.cc @@ -14,421 +14,681 @@ // $Id$ -#include +#include +#include +#include +#include +#include + +#include "buffer.h" #include "name.h" +#include "messagerenderer.h" -using namespace std; -using namespace ISC::DNS; +using isc::dns::NameComparisonResult; +using isc::dns::MessageRenderer; -// quick hack exception classes: should be moved to an appropriate place soon. -class ISCException {}; -class ISCUnexpected : public ISCException {}; -class ISCNoSpace : public ISCException {}; +namespace isc { +namespace dns { -class DNSException {}; -class DNSEmptyLabel : public DNSException {}; -class DNSLabelTooLong : public DNSException {}; -class DNSBadEscape : public DNSException {}; -class DNSBadLabelType : public DNSException {}; +namespace { +/// +/// These are shortcut arrays for efficient character conversion. +/// digitvalue converts a digit character to the corresponding integer. +/// maptolower convert uppercase alphabets to their lowercase counterparts. +/// A helper class and its only instance will initialize the arrays at startup +/// time. +/// +static char digitvalue[256]; +static unsigned char maptolower[256]; +class Initializer { +public: + Initializer() + { + for (unsigned int i = 0; i < 256; i++) { + if (i >= '0' && i<= '9') { + digitvalue[i] = i - '0'; + } else { + digitvalue[i] = -1; + } + } + for (unsigned int i = 0; i < 256; i++) { + if (i >= 'A' && i <= 'Z') { + maptolower[i] = i - ('A' - 'a'); + } else { + maptolower[i] = i; + } + } + } +}; +/// This object is defined only to call its constructor. +static Initializer initialier; +} +namespace { +/// +/// Textual name parser states. +/// typedef enum { - ft_init = 0, - ft_start, - ft_ordinary, - ft_initialescape, - ft_escape, - ft_escdecimal, - ft_at + ft_init = 0, // begin of the name + ft_start, // begin of a label + ft_ordinary, // parsing an ordinary label + ft_initialescape, // just found '\' + ft_escape, // begin of handling a '\'-escaped sequence + ft_escdecimal, // parsing a '\DDD' octet. + + // Unused at this moment. We'll revisit this when we support master file + // parser where @ is used to mean an origin name. + ft_at } ft_state; +} -typedef enum { - fw_start = 0, - fw_ordinary, - fw_copy, - fw_newcurrent -} fw_state; - -static char digitvalue[256] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16 - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ -}; - -static unsigned char maptolower[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff -}; - -void -Name::from_string(const string &namestring) +Name::Name(const std::string &namestring, bool downcase) { - char c; - ft_state state; - unsigned int value, count, pos, lpos; - unsigned int n1, n2, tlen, nrem, nused, digits, labels, tused; - bool done; - - offsets_.reserve(128); - offsets_[0] = 0; - // // Initialize things to make the compiler happy; they're not required. // - n1 = 0; - n2 = 0; - digits = 0; - value = 0; - count = 0; + unsigned int digits = 0; + unsigned int value = 0; + unsigned int count = 0; // // Set up the state machine. // - pos = 0; - tlen = namestring.length(); - tused = 0; - nrem = 255; - nused = 0; - labels = 0; - done = false; - state = ft_init; + std::string::const_iterator s = namestring.begin(); + std::string::const_iterator send = namestring.end(); + bool done = false; + bool is_root = false; + ft_state state = ft_init; - while (nrem > 0 && tlen > 0 && !done) { - c = namestring[pos++]; - tlen--; - tused++; + std::vector offsets; + offsets.reserve(Name::MAX_LABELS); + offsets.push_back(0); + + std::string ndata; + ndata.reserve(Name::MAX_WIRE); + + // should we refactor this code using, e.g, the state pattern? Probably + // not at this point, as this is based on proved code (derived from BIND9) + // and it's less likely that we'll have more variations in the domain name + // syntax. If this ever happens next time, we should consider refactor + // the code, rather than adding more states and cases below. + while (ndata.size() < Name::MAX_WIRE && s != send && !done) { + unsigned char c = *s++; switch (state) { case ft_init: - /* - * Is this the root name? - */ + // + // Is this the root name? + // if (c == '.') { - if (tlen != 0) - throw DNSEmptyLabel(); - labels++; - ndata_.push_back(0); - nrem--; - nused++; + if (s != send) { + dns_throw(EmptyLabel, "non terminating empty label"); + } + is_root = true; + } else if (c == '@' && s == send) { + // handle a single '@' as the root name. + is_root = true; + } + + if (is_root) { + ndata.push_back(0); done = true; break; } - if (c == '@' && tlen == 0) { - state = ft_at; - break; - } - /* FALLTHROUGH */ + // FALLTHROUGH case ft_start: - ndata_.push_back(0); // dummy data - nrem--; - lpos = nused; - nused++; + ndata.push_back(0); // placeholder for the label length field count = 0; if (c == '\\') { state = ft_initialescape; break; } state = ft_ordinary; - if (nrem == 0) - throw ISCNoSpace(); - /* FALLTHROUGH */ + assert(ndata.size() < Name::MAX_WIRE); + // FALLTHROUGH case ft_ordinary: if (c == '.') { - if (count == 0) - throw DNSEmptyLabel(); - ndata_[lpos] = count; - labels++; - //INSIST(labels <= 127); - offsets_[labels] = nused; - if (tlen == 0) { - labels++; - ndata_.push_back(0); - nrem--; - nused++; + if (count == 0) { + dns_throw(EmptyLabel, "duplicate period"); + } + ndata.at(offsets.back()) = count; + offsets.push_back(ndata.size()); + if (s == send) { + ndata.push_back(0); done = true; } state = ft_start; } else if (c == '\\') { state = ft_escape; } else { - if (count >= 63) - throw DNSLabelTooLong(); - count++; - ndata_.push_back(c); - nrem--; - nused++; + if (++count > MAX_LABELLEN) { + dns_throw(TooLongLabel, "label is too long"); + } + ndata.push_back(downcase ? maptolower[c] : c); } break; case ft_initialescape: if (c == '[') { - /* - * This looks like a bitstring label, which - * was deprecated. Intentionally drop it. - */ - throw DNSBadLabelType(); + // This looks like a bitstring label, which was deprecated. + // Intentionally drop it. + dns_throw(BadLabelType, "invalid label type"); } state = ft_escape; - /* FALLTHROUGH */ + // FALLTHROUGH case ft_escape: if (!isdigit(c & 0xff)) { - if (count >= 63) - throw DNSLabelTooLong(); - count++; - ndata_.push_back(c); - nrem--; - nused++; + if (++count > MAX_LABELLEN) { + dns_throw(TooLongLabel, "label is too long"); + } + ndata.push_back(downcase ? maptolower[c] : c); state = ft_ordinary; break; } digits = 0; value = 0; state = ft_escdecimal; - /* FALLTHROUGH */ + // FALLTHROUGH case ft_escdecimal: - if (!isdigit(c & 0xff)) - throw DNSBadEscape(); + if (!isdigit(c & 0xff)) { + dns_throw(BadEscape, "mixture of escaped digit and non-digit"); + } value *= 10; - value += digitvalue[(int)c]; + value += digitvalue[c]; digits++; if (digits == 3) { - if (value > 255) - throw DNSBadEscape(); - if (count >= 63) - throw DNSLabelTooLong(); - count++; - ndata_.push_back(value); - nrem--; - nused++; + if (value > 255) { + dns_throw(BadEscape, "escaped decimal is too large"); + } + if (++count > MAX_LABELLEN) { + dns_throw(TooLongLabel, "label is too long"); + } + ndata.push_back(downcase ? maptolower[value] : value); state = ft_ordinary; } break; default: - throw runtime_error("Unexpected state " + state); + // impossible case + assert(false); + } + } + + if (!done) { // no trailing '.' was found. + if (ndata.size() == Name::MAX_WIRE) { + dns_throw(TooLongName, "name is too long for termination"); + } + assert(s == send); + if (state != ft_ordinary && state != ft_at) { + dns_throw(IncompleteName, "incomplete textual name"); + } + if (state == ft_ordinary) { + assert(count != 0); + ndata.at(offsets.back()) = count; + + offsets.push_back(ndata.size()); + // add a trailing \0 + ndata.push_back('\0'); + } + } + + labelcount_ = offsets.size(); + assert(labelcount_ > 0 && labelcount_ <= Name::MAX_LABELS); + ndata_.assign(ndata.data(), ndata.size()); + length_ = ndata_.size(); + offsets_.assign(offsets.begin(), offsets.end()); +} + +namespace { +/// +/// Wire-format name parser states. +/// +typedef enum { + fw_start = 0, // beginning of a label + fw_ordinary, // inside an ordinary (non compressed) label + fw_newcurrent // beginning of a compression pointer +} fw_state; +} + +Name::Name(InputBuffer& buffer, bool downcase) +{ + std::vector offsets; + offsets.reserve(Name::MAX_LABELS); + + /* + * Initialize things to make the compiler happy; they're not required. + */ + unsigned int n = 0; + + // + // Set up. + // + bool done = false; + unsigned int nused = 0; + bool seen_pointer = false; + fw_state state = fw_start; + + unsigned int cused = 0; // Bytes of compressed name data used + unsigned int current = buffer.getPosition(); + unsigned int pos_begin = current; + unsigned int biggest_pointer = current; + + // Make the compiler happy; this is not required. + // XXX: bad style in that we initialize it with a dummy value and define + // it far from where it's used. But alternatives seemed even worse. + unsigned int new_current = 0; + + // + // Note: The following code is not optimized for speed, but + // rather for correctness. Speed will be addressed in the future. + // + while (current < buffer.getLength() && !done) { + unsigned int c = buffer.readUint8(); + current++; + if (!seen_pointer) { + cused++; + } + + switch (state) { + case fw_start: + if (c <= MAX_LABELLEN) { + offsets.push_back(nused); + if (nused + c + 1 > Name::MAX_WIRE) { + dns_throw(TooLongName, "wire name is too long"); + } + nused += c + 1; + ndata_.push_back(c); + if (c == 0) { + done = true; + } + n = c; + state = fw_ordinary; + } else if ((c & COMPRESS_POINTER_MARK8) == COMPRESS_POINTER_MARK8) { + // + // Ordinary 14-bit pointer. + // + new_current = c & ~COMPRESS_POINTER_MARK8; + n = 1; + state = fw_newcurrent; + } else { + // this case includes local compression pointer, which hasn't + // been standardized. + dns_throw(BadLabelType, "unknown label character"); + } + break; + case fw_ordinary: + if (downcase) { + c = maptolower[c]; + } + ndata_.push_back(c); + if (--n == 0) { + state = fw_start; + } + break; + case fw_newcurrent: + new_current *= 256; + new_current += c; + if (--n != 0) { + break; + } + if (new_current >= biggest_pointer) { + dns_throw(BadPointer, "bad compression pointer: out of range"); + } + biggest_pointer = new_current; + current = new_current; + buffer.setPosition(current); + seen_pointer = true; + state = fw_start; + break; + default: + assert(false); } } if (!done) { - if (nrem == 0) - throw ISCNoSpace(); - //INSIST(tlen == 0); - if (state != ft_ordinary && state != ft_at) - throw runtime_error("Unexpected state " + state); - if (state == ft_ordinary) { - //INSIST(count != 0); - ndata_[lpos] = count; - labels++; - //INSIST(labels <= 127); - offsets_[labels] = nused; - - // added a trailing \0 - ndata_.push_back('\0'); - ++labels; - ++nused; - offsets_[labels] = nused; - } + dns_throw(IncompleteName, "incomplete wire-format name"); } - labels_ = labels; + labelcount_ = offsets.size(); length_ = nused; + offsets_.assign(offsets.begin(), offsets.end()); + buffer.setPosition(pos_begin + cused); } -string -Name::to_text(bool omit_final_dot) const +void +Name::toWire(OutputBuffer& buffer) const { - string tdata; - unsigned int nlen; - unsigned char c; - unsigned int count; - unsigned int labels; - bool saw_root = false; - string::const_iterator iter_ndata; + buffer.writeData(ndata_.data(), ndata_.size()); +} - /* - * This function assumes the name is in proper uncompressed - * wire format. - */ - iter_ndata = ndata_.begin(); - nlen = length_; - labels = labels_; +void +Name::toWire(MessageRenderer& renderer) const +{ + renderer.writeName(*this); +} - if (labels == 0 && nlen == 0) { - /* - * Special handling for an empty name. - */ - - /* - * The names of these booleans are misleading in this case. - * This empty name is not necessarily from the root node of - * the DNS root zone, nor is a final dot going to be included. - * They need to be set this way, though, to keep the "@" - * from being trounced. - */ - saw_root = true; - omit_final_dot = false; - tdata.push_back('@'); - - /* - * Skip the while() loop. - */ - nlen = 0; - } else if (nlen == 1 && labels == 1 && *iter_ndata == '\0') { - /* - * Special handling for the root label. - */ - saw_root = true; - omit_final_dot = false; - tdata.push_back('.'); - - /* - * Skip the while() loop. - */ - nlen = 0; +std::string +Name::toText(bool omit_final_dot) const +{ + if (length_ == 1) { + // + // Special handling for the root label. We ignore omit_final_dot. + // + assert(labelcount_ == 1 && ndata_[0] == '\0'); + return ("."); } - while (labels > 0 && nlen > 0) { + std::string::const_iterator np = ndata_.begin(); + std::string::const_iterator np_end = ndata_.end(); + unsigned int labels = labelcount_; // use for integrity check + // init with an impossible value to catch error cases in the end: + unsigned int count = MAX_LABELLEN + 1; + + // result string: it will roughly have the same length as the wire format + // name data. reserve that length to minimize reallocation. + std::string result; + result.reserve(length_); + + while (np != np_end) { labels--; - count = *iter_ndata++; - nlen--; + count = *np++; + if (count == 0) { - saw_root = true; + if (!omit_final_dot) { + result.push_back('.'); + } break; } - if (count < 64) { - //INSIST(nlen >= count); - while (count > 0) { - c = *iter_ndata; + + if (count <= MAX_LABELLEN) { + assert(np_end - np >= count); + + if (!result.empty()) { + // just after a non-empty label. add a separating dot. + result.push_back('.'); + } + + while (count-- > 0) { + unsigned char c = *np++; switch (c) { - case 0x22: /* '"' */ - case 0x28: /* '(' */ - case 0x29: /* ')' */ - case 0x2E: /* '.' */ - case 0x3B: /* ';' */ - case 0x5C: /* '\\' */ - /* Special modifiers in zone files. */ - case 0x40: /* '@' */ - case 0x24: /* '$' */ - tdata.push_back('\\'); - tdata.push_back(c); - iter_ndata++; - nlen--; + case 0x22: // '"' + case 0x28: // '(' + case 0x29: // ')' + case 0x2E: // '.' + case 0x3B: // ';' + case 0x5C: // '\\' + // Special modifiers in zone files. + case 0x40: // '@' + case 0x24: // '$' + result.push_back('\\'); + result.push_back(c); break; default: if (c > 0x20 && c < 0x7f) { - tdata.push_back(c); - iter_ndata++; - nlen--; + // append printable characters intact + result.push_back(c); } else { - tdata.push_back(0x5c); - tdata.push_back(0x30 + ((c / 100) % 10)); - tdata.push_back(0x30 + ((c / 10) % 10)); - tdata.push_back(0x30 + (c % 10)); - iter_ndata++; - nlen--; + // encode non-printable characters in the form of \DDD + result.push_back(0x5c); + result.push_back(0x30 + ((c / 100) % 10)); + result.push_back(0x30 + ((c / 10) % 10)); + result.push_back(0x30 + (c % 10)); } } - count--; } - } else - throw runtime_error("Unexpected label type " + count); - // The following assumes names are absolute. If not, we - // fix things up later. Note that this means that in some - // cases one more byte of text buffer is required than is - // needed in the final output. - tdata.push_back('.'); + } else { + dns_throw(BadLabelType, "unknown label type in name data"); + } } - if (nlen != 0) - throw ISCNoSpace(); + assert(labels == 0); + assert(count == 0); // a valid name must end with a 'dot'. - if (!saw_root || omit_final_dot) - tdata.erase(tdata.end() - 1); - - return (tdata); + return (result); } -// Are 'this' name and 'other' equal? -bool -Name::operator==(const Name& other) const +NameComparisonResult +Name::compare(const Name& other) const { - unsigned int l; - unsigned char c, count; - string::const_iterator label1, label2; + // Determine the relative ordering under the DNSSEC order relation of + // 'this' and 'other', and also determine the hierarchical relationship + // of the names. - if (length_ != other.length_) - return (false); + unsigned int nlabels = 0; + unsigned int l1 = labelcount_; + unsigned int l2 = other.labelcount_; + int ldiff = (int)l1 - (int)l2; + unsigned int l = (ldiff < 0) ? l1 : l2; - l = labels_; - - if (l != other.labels_) - return (false); - - label1 = ndata_.begin(); - label2 = other.ndata_.begin(); while (l > 0) { - l--; - count = *label1++; - if (count != *label2++) - return (false); + --l; + --l1; + --l2; + size_t pos1 = offsets_[l1]; + size_t pos2 = other.offsets_[l2]; + unsigned int count1 = ndata_[pos1++]; + unsigned int count2 = other.ndata_[pos2++]; + + // We don't support any extended label types including now-obsolete + // bitstring labels. + assert(count1 <= MAX_LABELLEN && count2 <= MAX_LABELLEN); + + int cdiff = (int)count1 - (int)count2; + unsigned int count = (cdiff < 0) ? count1 : count2; while (count > 0) { - count--; - c = maptolower[(unsigned char)*label1++]; // XXX should avoid cast - if (c != maptolower[(unsigned char)*label2++]) + unsigned char label1 = ndata_[pos1]; + unsigned char label2 = other.ndata_[pos2]; + + int chdiff = (int)maptolower[label1] - (int)maptolower[label2]; + if (chdiff != 0) { + return (NameComparisonResult(chdiff, nlabels, + NameComparisonResult::COMMONANCESTOR)); + } + --count; + ++pos1; + ++pos2; + } + if (cdiff != 0) { + return (NameComparisonResult(cdiff, nlabels, + NameComparisonResult::COMMONANCESTOR)); + } + ++nlabels; + } + + if (ldiff < 0) { + return (NameComparisonResult(ldiff, nlabels, + NameComparisonResult::SUPERDOMAIN)); + } else if (ldiff > 0) { + return (NameComparisonResult(ldiff, nlabels, + NameComparisonResult::SUBDOMAIN)); + } + + return (NameComparisonResult(ldiff, nlabels, NameComparisonResult::EQUAL)); +} + +bool +Name::equals(const Name& other) const +{ + if (length_ != other.length_ || labelcount_ != other.labelcount_) { + return (false); + } + + for (unsigned int l = labelcount_, pos = 0; l > 0; --l) { + unsigned char count = ndata_[pos]; + if (count != other.ndata_[pos]) { + return (false); + } + ++pos; + + while (count-- > 0) { + unsigned char label1 = ndata_[pos]; + unsigned char label2 = other.ndata_[pos]; + + if (maptolower[label1] != maptolower[label2]) { return (false); + } + ++pos; } } return (true); } -ostream& -operator<<(ostream& os, const Name& name) +bool +Name::leq(const Name& other) const { - os << name.to_text(); + return (compare(other).getOrder() <= 0); +} + +bool +Name::geq(const Name& other) const +{ + return (compare(other).getOrder() >= 0); +} + +bool +Name::lthan(const Name& other) const +{ + return (compare(other).getOrder() < 0); +} + +bool +Name::gthan(const Name& other) const +{ + return (compare(other).getOrder() > 0); +} + +bool +Name::isWildcard() const +{ + return (length_ >= 2 && ndata_[0] == 1 && ndata_[1] == '*'); +} + +namespace { // hide the local class +/// +/// A helper functor class to add an additional offset to an offset vector. +/// +struct OffsetAdjuster : public std::binary_function { + unsigned char operator()(unsigned char ch, int offset) const + { + return (ch + offset); + } +}; +} + +Name +Name::concatenate(const Name& suffix) const +{ + assert(this->length_ > 0 && suffix.length_ > 0); + assert(this->labelcount_ > 0 && suffix.labelcount_ > 0); + + unsigned int length = this->length_ + suffix.length_ - 1; + if (length > Name::MAX_WIRE) { + dns_throw(TooLongName, "names are too long to concatenate"); + } + + Name retname; + retname.ndata_.reserve(length); + retname.ndata_.assign(this->ndata_, 0, this->length_ - 1); + retname.ndata_.insert(retname.ndata_.end(), + suffix.ndata_.begin(), suffix.ndata_.end()); + assert(retname.ndata_.size() == length); + retname.length_ = length; + + // + // Setup the offsets vector. Copy the offsets of this (prefix) name, + // excluding that for the trailing dot, and append the offsets of the + // suffix name with the additional offset of the length of the prefix. + // + unsigned int labels = this->labelcount_ + suffix.labelcount_ - 1; + assert(labels <= Name::MAX_LABELS); + retname.offsets_.reserve(labels); + retname.offsets_.assign(&this->offsets_[0], + &this->offsets_[0] + this->labelcount_ - 1); + transform(suffix.offsets_.begin(), suffix.offsets_.end(), + back_inserter(retname.offsets_), + bind2nd(OffsetAdjuster(), this->length_ - 1)); + assert(retname.offsets_.size() == labels); + retname.labelcount_ = labels; + + return (retname); +} + +Name +Name::split(unsigned int first, unsigned int n) const +{ + if (n == 0 || first + n > labelcount_) { + dns_throw(OutOfRange, "Name::split: invalid split range"); + } + + Name retname; + // If the specified range doesn't include the trailing dot, we need one + // more label for that. + unsigned int newlabels = (first + n == labelcount_) ? n : n + 1; + + // + // Set up offsets: copy the corresponding range of the original offsets + // with subtracting an offset of the prefix length. + // + retname.offsets_.reserve(newlabels); + transform(offsets_.begin() + first, offsets_.begin() + first + newlabels, + back_inserter(retname.offsets_), + bind2nd(OffsetAdjuster(), -offsets_[first])); + + // + // Set up the new name. At this point the tail of the new offsets specifies + // the position of the trailing dot, which should be equal to the length of + // the extracted portion excluding the dot. First copy that part from the + // original name, and append the trailing dot explicitly. + // + retname.ndata_.reserve(retname.offsets_.back() + 1); + retname.ndata_.assign(ndata_, offsets_[first], retname.offsets_.back()); + retname.ndata_.push_back(0); + + retname.length_ = retname.ndata_.size(); + retname.labelcount_ = retname.offsets_.size(); + assert(retname.labelcount_ == newlabels); + + return (retname); +} + +Name& +Name::downcase() +{ + unsigned int nlen = length_; + unsigned int labels = labelcount_; + unsigned int pos = 0; + + while (labels > 0 && nlen > 0) { + --labels; + --nlen; + + // we assume a valid name, and do abort() if the assumption fails + // rather than throwing an exception. + unsigned int count = ndata_.at(pos++); + assert(count <= MAX_LABELLEN); + assert(nlen >= count); + + while (count > 0) { + ndata_.at(pos) = + maptolower[static_cast(ndata_.at(pos))]; + ++pos; + --nlen; + --count; + } + } + + return (*this); +} + +std::ostream& +operator<<(std::ostream& os, const Name& name) +{ + os << name.toText(); return (os); } +} +} diff --git a/src/lib/dns/cpp/name.h b/src/lib/dns/cpp/name.h index 349c550181..f0b4794520 100644 --- a/src/lib/dns/cpp/name.h +++ b/src/lib/dns/cpp/name.h @@ -17,81 +17,561 @@ #ifndef __NAME_H #define __NAME_H 1 +#include + #include #include -namespace ISC { -namespace DNS { -class Buffer; -class NameCompressor; -class NameDecompressor; +#include "exceptions.h" +namespace isc { +namespace dns { +class InputBuffer; +class OutputBuffer; +class MessageRenderer; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// encounters an empty label in the middle of a name. +/// +class EmptyLabel : public Exception { +public: + EmptyLabel(const char* file, size_t line, const char* what) : + isc::dns::Exception(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// encounters too long a name. +/// +class TooLongName : public Exception { +public: + TooLongName(const char* file, size_t line, const char* what) : + isc::dns::Exception(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// encounters too long a label. +/// +class TooLongLabel : public Exception { +public: + TooLongLabel(const char* file, size_t line, const char* what) : + isc::dns::Exception(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// encounters an obsolete or incomplete label type. In effect "obsolete" only +/// applies to bitstring labels, which would begin with "\[". Incomplete cases +/// include an incomplete escaped sequence such as "\12". +/// +class BadLabelType : public Exception { +public: + BadLabelType(const char* file, size_t line, const char* what) : + isc::dns::Exception(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// fails to decode a "\"-escaped sequence. +/// +class BadEscape : public Exception { +public: + BadEscape(const char* file, size_t line, const char* what) : + isc::dns::Exception(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if the wire-format +/// name contains an invalid compression pointer. +/// +class BadPointer : public Exception { +public: + BadPointer(const char* file, size_t line, const char* what) : + isc::dns::Exception(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// finds the input (string or wire-format data) is incomplete. +/// +/// An attempt of constructing a name from an empty string will trigger this +/// exception. +/// +class IncompleteName : public Exception { +public: + IncompleteName(const char* file, size_t line, const char* what) : + isc::dns::Exception(file, line, what) {} +}; + +/// +/// This is a supplemental class used only as a return value of Name::compare(). +/// It encapsulate a tuple of the comparison: ordering, number of common labels, +/// and relationship as follows: +/// - ordering: relative ordering under the DNSSEC order relation +/// - labels: the number of common significant labels of the two names being +/// compared +/// - relationship: see NameComparisonResult::NameRelation +/// class NameComparisonResult { public: + /// The relation of two names under comparison. + /// Its semantics for the case of + /// name1->compare(name2) (where name1 and name2 are instances + /// of the Name class) is as follows: + /// - SUPERDOMAIN: name1 properly contains name2; name2 is a proper + /// subdomain of name1 + /// - SUBDOMAIN: name1 is a proper subdomain of name2 + /// - EQUAL: name1 and name2 are equal + /// - COMMONANCESTOR: name1 and name2 share a common ancestor + /// + /// Note that in our implementation there's always a hierarchical + /// relationship between any two names since all names are absolute and + /// they at least share the trailing empty label. + /// So, for example, the relationship between "com." and "net." is + /// "commonancestor". This may be counter intuitive and inconvenient, but + /// we'll keep this design at the moment until we decide whether and how to + /// handle "non absolute" names (see the description of the \c Name class). + /// If we want to (re)introduce the notion of non absolute names, we'll + /// want to distinguish "com" and "com.", and the current definition would + /// be more compatible for that purpose. + /// If, on the other hand, we finally decide we really don't need that + /// notion, we'll probably reconsider the design here, too. enum NameRelation { - none = 0, - contains = 1, - subdomain = 2, - equal = 3, - commonancestor = 4 + SUPERDOMAIN = 0, + SUBDOMAIN = 1, + EQUAL = 2, + COMMONANCESTOR = 3 }; - explicit NameComparisonResult(int order, int nlabels, + /// + /// \name Constructors and Destructor + /// + //@{ + /// \brief Constructor from a comparison tuple + /// + /// This constructor simply initializes the object in the straightforward + /// way. + explicit NameComparisonResult(int order, unsigned int nlabels, NameRelation relation) : order_(order), nlabels_(nlabels), relation_(relation) {} - int get_order() const { return (order_); } - int get_common_labels() const { return (nlabels_); } - NameRelation get_relation() const { return (relation_); } + //@} + + /// + /// \name Getter Methods + /// + //@{ + /// Returns the ordering of the comparison result + int getOrder() const { return (order_); } + /// Returns the number of common labels of the comparison result + unsigned int getCommonLabels() const { return (nlabels_); } + /// Returns the NameRelation of the comparison result + NameRelation getRelation() const { return (relation_); } + //@} private: int order_; - int nlabels_; + unsigned int nlabels_; NameRelation relation_; }; +/// +/// The \c Name class encapsulates DNS names. +/// +/// It provides interfaces to construct a name from string or wire-format data, +/// transform a name into a string or wire-format data, compare two names, get +/// access to various properties of a name, etc. +/// +/// Notes to developers: Internally, a name object maintains the name data +/// in wire format as an instance of \c std::string. Since many string +/// implementations adopt copy-on-write data sharing, we expect this approach +/// will make copying a name less expensive in typical cases. If this is +/// found to be a significant performance bottleneck later, we may reconsider +/// the internal representation or perhaps the API. +/// +/// A name object also maintains a vector of offsets (\c offsets_ member), +/// each of which is the offset to a label of the name: The n-th element of +/// the vector specifies the offset to the n-th label. For example, if the +/// object represents "www.example.com", the elements of the offsets vector +/// are 0, 4, 12, and 16. Note that the offset to the trailing dot (16) is +/// included. In the BIND9 DNS library from which this implementation is +/// derived, the offsets are optional, probably due to performance +/// considerations (in fact, offsets can always be calculated from the name +/// data, and in that sense are redundant). In our implementation, however, +/// we always build and maintain the offsets. We believe we need more low +/// level, specialized data structure and interface where we really need to +/// pursue performance, and would rather keep this generic API and +/// implementation simpler. +/// +/// While many other DNS APIs introduce an "absolute or relative" +/// attribute of names as defined in RFC1035, names are always "absolute" in +/// the initial design of this API. +/// In fact, separating absolute and relative would confuse API users +/// unnecessarily. For example, it's not so intuitive to consider the +/// comparison result of an absolute name with a relative name. +/// We've looked into how the concept of absolute names is used in BIND9, +/// and found that in many cases names are generally absolute. +/// The only reasonable case of separating absolute and relative is in a master +/// file parser, where a relative name must be a complete name with an "origin" +/// name, which must be absolute. So, in this initial design, we chose a +/// simpler approach: the API generally handles names as absolute; when we +/// introduce a parser of master files, we'll introduce the notion of relative +/// names as a special case. +/// class Name { + /// + /// \name Constructors and Destructor + /// + //@{ +private: + /// The default constructor + /// + /// This is used internally in the class implementation, but at least at + /// the moment defined as private because it will construct an incomplete + /// object in that it doesn't have any labels. We may reconsider this + /// design choice as we see more applications of the class. + Name() : length_(0), labelcount_(0) {} public: - Name() : length_(0), labels_(0) {} - explicit Name(const std::string& namestr) : length_(0), labels_(0) - { from_string(namestr); } - explicit Name(NameDecompressor& decompressor, Buffer& buffer); - // copy constructor (default cp-ctor should work fine) - //Name(const Name& orig); - // destructor (default dtor should work fine) - //~Name(); + /// Constructor from a string + /// + /// If the given string does not represent a valid DNS name, an exception + /// of class \c EmptyLabel, \c TooLongLabel, \c BadLabelType, \c BadEscape, + /// \c TooLongName, or \c IncompleteName will be thrown. + /// In addition, if resource allocation for the new name fails, a + /// corresponding standard exception will be thrown. + /// + /// \param namestr A string representation of the name to be constructed. + /// \param downcase Whether to convert upper case alphabets to lower case. + explicit Name(const std::string& namestr, bool downcase = false); + /// Constructor from wire-format data. + /// + /// The \c buffer parameter normally stores a complete DNS message + /// containing the name to be constructed. The current read position of + /// the buffer points to the head of the name. + /// + /// The input data may or may not be compressed; if it's compressed, this + /// method will automatically decompress it. + /// + /// If the given data does not represent a valid DNS name, an exception + /// of class \c TooLongName, \c BadLabelType, \c BadPointer, or + /// \c IncompleteName will be thrown. + /// In addition, if resource allocation for the new name fails, a + /// corresponding standard exception will be thrown. + /// + /// \param buffer A buffer storing the wire format data. + /// \param downcase Whether to convert upper case alphabets to lower case. + explicit Name(InputBuffer& buffer, bool downcase = false); + //@} - std::string to_text(bool omit_final_dot = false) const; - void to_wire(Buffer& buffer, NameCompressor& compressor) const; - size_t get_length() const { return (length_); } - unsigned int get_labels() const { return (labels_); } + /// + /// \name Getter Methods + /// + //@{ + /// \brief Gets the length of the Name in its wire format. + /// + /// This method never throws an exception. + /// + /// \return the length (the number of octets in wire format) of the + /// Name + size_t getLength() const { return (length_); } + + /// \brief Returns the number of labels contained in the Name. + /// + /// Note that an empty label (corresponding to a trailing '.') is counted + /// as a single label, so the return value of this method must be >0. + /// + /// This method never throws an exception. + /// + /// \return the number of labels + unsigned int getLabelCount() const { return (labelcount_); } + //@} + + /// + /// \name Converter methods + /// + //@{ + /// \brief Convert the Name to a string. + /// + /// This method returns a std::string object representing the + /// Name as a string. Unless omit_final_dot is + /// true, the returned string ends with a dot '.'; the default + /// is false. The default value of this parameter is + /// true; converted names will have a trailing dot by default. + /// + /// This function assumes the name is in proper uncompressed wire format. + /// If it finds an unexpected label character including compression pointer, + /// an exception of class \c BadLabelType will be thrown. + /// In addition, if resource allocation for the result string fails, a + /// corresponding standard exception will be thrown. + // + /// \param omit_final_dot whether to omit the trailing dot in the output. + /// \return a string representation of the Name. + std::string toText(bool omit_final_dot = false) const; + + /// \brief Render the Name in the wire format with compression. + /// + /// This method dumps the Name in wire format with help of \c renderer, + /// which encapsulates output buffer and name compression algorithm to + /// render the name. + /// + /// If resource allocation in rendering process fails, a corresponding + /// standard exception will be thrown. + /// + /// \param renderer DNS message rendering context that encapsulates the + /// output buffer and name compression information. + void toWire(MessageRenderer& renderer) const; + + /// \brief Render the Name in the wire format without + /// compression. + /// + /// If resource allocation in rendering process fails, a corresponding + /// standard exception will be thrown. This can be avoided by preallocating + /// a sufficient size of \c buffer. Specifically, if + /// buffer.getCapacity() - buffer.getLength() >= Name::MAX_WIRE + /// then this method should not throw an exception. + /// + void toWire(OutputBuffer& buffer) const; + //@} + + /// + /// \name Comparison methods + /// + //@{ + /// \brief Compare two Names. + /// + /// This method compares the Name and other and + /// returns the result in the form of a NameComparisonResult + /// object. + /// + /// Note that this is case-insensitive comparison. + /// + /// This method never throws an exception. + /// + /// \param other the right-hand operand to compare against. + /// \return a NameComparisonResult object representing the + /// comparison result. NameComparisonResult compare(const Name& other) const; + + /// \brief Return true iff two names are equal. + /// + /// Semantically this could be implemented based on the result of the + /// \c compare() method, but the actual implementation uses different code + /// that simply performs character-by-character comparison (case + /// insensitive for the name label parts) on the two names. This is because + /// it would be much faster and the simple equality check would be pretty + /// common. + /// + /// This method never throws an exception. + /// + /// \param other the Name object to compare against. + /// \return true if the two names are equal; otherwise false. + bool equals(const Name& other) const; + + /// Same as equals() + bool operator==(const Name& other) const { return (this->equals(other)); } + + /// \brief Return true iff two names are not equal. + /// + /// This method simply negates the result of \c equal() method, and in that + /// sense it's redundant. The separate method is provided just for + /// convenience. + bool nequals(const Name& other) const { return !(this->equals(other)); } + + /// Same as nequals() + bool operator!=(const Name& other) const { return (this->nequals(other)); } + + /// \brief Less-than or equal comparison for Name against other + /// + /// The comparison is based on the result of the \c compare() method. + /// + /// This method never throws an exception. + /// + /// \param other the Name object to compare against. + /// \return true if compare(other).getOrder() <= 0; + /// otherwise false. + bool leq(const Name& other) const; + + /// Same as leq() + bool operator<=(const Name& other) const { return (leq(other)); } + + /// \brief Greater-than or equal comparison for Name against + /// other + /// + /// The comparison is based on the result of the \c compare() method. + /// + /// This method never throws an exception. + /// + /// \param other the Name object to compare against. + /// \return true if compare(other).getOrder() >= 0; + /// otherwise false. + bool geq(const Name& other) const; + + /// Same as geq() + bool operator>=(const Name& other) const { return (geq(other)); } + + /// \brief Less-than comparison for Name against other + /// + /// The comparison is based on the result of the \c compare() method. + /// + /// This method never throws an exception. + /// + /// \param other the Name object to compare against. + /// \return true if compare(other).getOrder() < 0; + /// otherwise false. + bool lthan(const Name& other) const; + + /// Same as lthan() + bool operator<(const Name& other) const { return (lthan(other)); } + + /// \brief Greater-than comparison for Name against other + /// + /// The comparison is based on the result of the \c compare() method. + //// + /// This method never throws an exception. + /// + /// \param other the Name object to compare against. + /// \return true if compare(other).getOrder() > 0; + /// otherwise false. + bool gthan(const Name& other) const; + + /// Same as gthan() + bool operator>(const Name& other) const { return (gthan(other)); } + //@} + + /// + /// \name Transformer methods + /// + //@{ + /// \brief Extract a specified subpart of Name. + /// + /// name.split(first, n) constructs a new name starting from + /// the first-th label of the \c name, and subsequent \c n + /// labels including the \c first one. Since names in this current + /// implementation are always "absolute", if the specified range doesn't + /// contain the trailing dot of the original \c name, then a dot will be + /// appended to the resulting name. As a result, the number of labels + /// will be n + 1, rather than \c n. For example, + /// when \c n is Name("www.example.com"), + /// both n.split(1, 2) and n.split(1, 3) + /// will produce a name corresponding to "example.com.", which has 3 labels. + /// Note also that labels are counted from 0, and so first = 1 + /// in this example specified the label "example", not "www". + /// + /// Parameter \c n must be larger than 0, and the range specified by + /// \c first and \c n must not exceed the valid range of the original name; + /// otherwise, an exception of class \c OutOfRange will be thrown. + /// + /// Note to developers: we may want to have different versions (signatures) + /// of this method. For example, we want to split the Name based on a given + /// suffix name. + /// + /// \param first The start position (in labels) of the extracted name + /// \param n Number of labels of the extracted name + /// \return A new Name object based on the Name containing n + /// labels including and following the first label. Name split(unsigned int first, unsigned int n) const; + + /// \brief Concatenate two names. + /// + /// This method appends \c suffix to \c this Name. The trailing dot of + /// \c this Name will be removed. For example, if \c this is "www." + /// and \c suffix is "example.com.", a successful return of this method + /// will be a name of "www.example.com." + /// + ///The resulting length of the concatenated name must not exceed + /// \c Name::MAX_WIRE; otherwise an exception of class + /// \c TooLongName will be thrown. + /// + /// \param suffix a Name object to be appended to the Name. + /// \return a new Name object concatenating \c suffix to \c this Name. Name concatenate(const Name& suffix) const; - bool is_wildcard() const; - bool operator==(const Name& other) const; - bool equals(const Name& other) const; // alias of == - bool operator!=(const Name& other) const { return (!(*this == other)); } - bool nequals(const Name& other) const; // alias of != - bool operator<=(const Name& other) const; - bool leq(const Name& other) const; // alias of <= - bool operator>=(const Name& other) const; - bool geq(const Name& other) const; // alias of >= - bool operator<(const Name& other) const; - bool lthan(const Name& other) const; // alias of < - bool operator>(const Name& other) const; - bool gthan(const Name& other) const; // alias of > + + /// \brief Downcase all upper case alphabet characters in the name. + /// + /// This method modifies the calling object so that it can perform the + /// conversion as fast as possible and can be exception free. + /// + /// The return value of this version of \c downcase() is a reference to + /// the calling object (i.e., \c *this) so that the caller can use the + /// result of downcasing in a single line. For example, if variable + /// \c n is a \c Name class object possibly containing upper case + /// characters, and \c b is an \c OutputBuffer class object, then the + /// following code will dump the name in wire format to \c b with + /// downcasing upper case characters: + /// + /// \code n.downcase().toWire(b); \endcode + /// + /// Since this method modifies the calling object, a \c const name object + /// cannot call it. If \c n is a \c const Name class object, it must first + /// be copied to a different object and the latter must be used for the + /// downcase modification. + /// + /// \return A reference to the calling object with being downcased. + Name& downcase(); + //@} + + /// + /// \name Testing methods + /// + //@{ + /// \brief Test if this is a wildcard name. + /// + /// \return \c true if the least significant label of this Name is + /// '*'; otherwise \c false. + bool isWildcard() const; + //@} + + /// + /// \name Protocol constants + /// + //@{ + /// \brief Max allowable length of domain names. + static const size_t MAX_WIRE = 255; + + /// \brief Max allowable labels of domain names. + /// + /// This is ceil(MAX_WIRE / 2), and is equal to the number of + /// labels of name "a.a.a.a....a." (127 "a"'s and trailing dot). + static const size_t MAX_LABELS = 128; + + /// \brief Max allowable length of labels of a domain name. + static const size_t MAX_LABELLEN = 63; + + /// \brief Max possible pointer value for name compression. + /// + /// This is the highest number of 14-bit unsigned integer. Name compression + /// pointers are identified as a 2-byte value starting with the upper two + /// bit being 11. + static const uint16_t MAX_COMPRESS_POINTER = 0x3fff; + /// \brief A 8-bit masked value indicating a start of compression pointer. + static const uint16_t COMPRESS_POINTER_MARK8 = 0xc0; + /// \brief A 16-bit masked value indicating a start of compression pointer. + static const uint16_t COMPRESS_POINTER_MARK16 = 0xc000; + //@} private: - static const unsigned int MAXWIRE = 255; - std::string ndata_; - std::vector offsets_; + std::vector offsets_; unsigned int length_; - unsigned int labels_; - - void from_string(const std::string& namestr); + unsigned int labelcount_; }; -std::ostream& operator<<(std::ostream& os, const Name& name); +/// +/// \brief Insert the name as a string into stream. +/// +/// This method convert the \c name into a string and inserts it into the +/// output stream \c os. +/// +/// This function overloads the global operator<< to behave as described in +/// ostream::operator<< but applied to \c Name objects. +/// +/// \param os A \c std::ostream object on which the insertion operation is +/// performed. +/// \param name The \c Name object output by the operation. +/// \return A reference to the same \c std::ostream object referenced by +/// parameter \c os after the insertion operation. +std::ostream& +operator<<(std::ostream& os, const Name& name); } } #endif // __NAME_H diff --git a/src/lib/dns/cpp/name_unittest.cc b/src/lib/dns/cpp/name_unittest.cc new file mode 100644 index 0000000000..8c1eddc921 --- /dev/null +++ b/src/lib/dns/cpp/name_unittest.cc @@ -0,0 +1,537 @@ +// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// $Id$ + +#include +#include +#include +#include +#include + +#include "buffer.h" +#include "name.h" +#include "messagerenderer.h" + +#include "unittest_util.h" + +#include + +using isc::UnitTestUtil; +using isc::dns::InputBuffer; +using isc::dns::OutputBuffer; +using isc::dns::Name; +using isc::dns::MessageRenderer; +using isc::dns::NameComparisonResult; + +// +// XXX: these are defined as class static constants, but some compilers +// seemingly cannot find the symbols when used in the EXPECT_xxx macros. +// +const size_t isc::dns::Name::MAX_WIRE; +const size_t isc::dns::Name::MAX_LABELS; + +namespace { +class NameTest : public ::testing::Test { +protected: + NameTest() : example_name("www.example.com"), + example_name_upper("WWW.EXAMPLE.COM"), + small_name("aaa.example.com"), + large_name("zzz.example.com"), + buffer_actual(0), buffer_expected(0) + {} + + const Name example_name; + Name example_name_upper; // this will be modified and cannot be const + const Name small_name; + const Name large_name; + OutputBuffer buffer_actual, buffer_expected; + + // + // helper methods + // + static Name nameFactoryFromWire(const char* datafile, size_t position, + bool downcase = false); + // construct a name including all non-upper-case-alphabet characters. + static Name nameFactoryLowerCase(); + void compareInWireFormat(const Name& name_actual, + const Name& name_expected); +}; + +Name +NameTest::nameFactoryFromWire(const char* datafile, size_t position, + bool downcase) +{ + std::vector data; + UnitTestUtil::readWireData(datafile, data); + + InputBuffer buffer(&data[0], data.size()); + buffer.setPosition(position); + + return (Name(buffer, downcase)); +} + +Name +NameTest::nameFactoryLowerCase() +{ + std::string lowercase_namestr; + lowercase_namestr.reserve(Name::MAX_WIRE); + + unsigned int ch = 0; + unsigned int labelcount = 0; + do { + if (ch < 'A' || ch > 'Z') { + std::ostringstream ss; + ss.setf(std::ios_base::right, std::ios_base::adjustfield); + ss.width(3); + ss << std::setfill('0') << ch; + lowercase_namestr += '\\' + ss.str(); + + if (++labelcount == Name::MAX_LABELLEN) { + lowercase_namestr.push_back('.'); + labelcount = 0; + } + } + } while (++ch <= Name::MAX_WIRE); + + return (Name(lowercase_namestr)); +} + +void +NameTest::compareInWireFormat(const Name& name_actual, + const Name& name_expected) +{ + buffer_actual.clear(); + buffer_expected.clear(); + + name_actual.toWire(buffer_actual); + name_expected.toWire(buffer_expected); + + EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, + buffer_actual.getData(), buffer_actual.getLength(), + buffer_expected.getData(), buffer_expected.getLength()); +} + +TEST_F(NameTest, fromText) +{ + std::vector strnames; + strnames.push_back("www.example.com"); + strnames.push_back("www.example.com."); // with a trailing dot + strnames.push_back("wWw.exAmpLe.com"); // mixed cases + strnames.push_back("\\wWw.exAmpLe.com"); // escape with a backslash + // decimal representation for "WWW" + strnames.push_back("\\087\\087\\087.example.com"); + + std::vector::const_iterator it; + for (it = strnames.begin(); it != strnames.end(); ++it) { + EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name, Name(*it)); + } + + // root names + EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, Name("@"), Name(".")); + + // downcase + EXPECT_EQ(Name("Www.eXample.coM", true).toText(), example_name.toText()); + + // + // Tests for bogus names. These should trigger an exception. + // + // empty label cannot be followed by another label + EXPECT_THROW(Name(".a"), isc::dns::EmptyLabel); + // duplicate period + EXPECT_THROW(Name("a.."), isc::dns::EmptyLabel); + // label length must be < 64 + EXPECT_THROW(Name("012345678901234567890123456789" + "012345678901234567890123456789" + "0123"), isc::dns::TooLongLabel); + // now-unsupported bitstring labels + EXPECT_THROW(Name("\\[b11010000011101]"), isc::dns::BadLabelType); + // label length must be < 64 + EXPECT_THROW(Name("012345678901234567890123456789" + "012345678901234567890123456789" + "012\\x"), isc::dns::TooLongLabel); + // but okay as long as resulting len < 64 even if the original string is + // "too long" + EXPECT_NO_THROW(Name("012345678901234567890123456789" + "012345678901234567890123456789" + "01\\x")); + // incomplete \DDD pattern (exactly 3 D's must appear) + EXPECT_THROW(Name("\\12abc"), isc::dns::BadEscape); + // \DDD must not exceed 255 + EXPECT_THROW(Name("\\256"), isc::dns::BadEscape); + // Same tests for \111 as for \\x above + EXPECT_THROW(Name("012345678901234567890123456789" + "012345678901234567890123456789" + "012\\111"), isc::dns::TooLongLabel); + EXPECT_NO_THROW(Name("012345678901234567890123456789" + "012345678901234567890123456789" + "01\\111")); + // A domain name must be 255 octets or less + EXPECT_THROW(Name("123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "1234"), isc::dns::TooLongName); + // This is a possible longest name and should be accepted + EXPECT_NO_THROW(Name("123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "123")); + // \DDD must consist of 3 digits. + EXPECT_THROW(Name("\\12"), isc::dns::IncompleteName); + + // a name with the max number of labels. should be constructed without + // an error, and its length should be the max value. + Name maxlabels = Name("0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 40 + "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 80 + "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 120 + "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 160 + "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 200 + "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." // 240 + "0.1.2.3.4.5.6."); + EXPECT_EQ(Name::MAX_LABELS, maxlabels.getLabelCount()); +} + +TEST_F(NameTest, fromWire) +{ + // + // test cases derived from BIND9 tests. + // + // normal case with a compression pointer + EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, + nameFactoryFromWire("testdata/name_fromWire1", 25), + Name("vix.com")); + // bogus label character (looks like a local compression pointer) + EXPECT_THROW(nameFactoryFromWire("testdata/name_fromWire2", 25), + isc::dns::BadLabelType); + // a bad compression pointer (too big) + EXPECT_THROW(nameFactoryFromWire("testdata/name_fromWire3_1", 25), + isc::dns::BadPointer); + // forward reference + EXPECT_THROW(nameFactoryFromWire("testdata/name_fromWire3_2", 25), + isc::dns::BadPointer); + // invalid name length + EXPECT_THROW(nameFactoryFromWire("testdata/name_fromWire4", 550), + isc::dns::TooLongName); + + // skip test for from Wire5. It's for disabling decompression, but our + // implementation always allows it. + + // bad pointer (too big) + EXPECT_THROW(nameFactoryFromWire("testdata/name_fromWire6", 25), + isc::dns::BadPointer); + // input ends unexpectedly + EXPECT_THROW(nameFactoryFromWire("testdata/name_fromWire7", 25), + isc::dns::IncompleteName); + // many hops of compression but valid. should succeed. + EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, + nameFactoryFromWire("testdata/name_fromWire8", 383), + Name("vix.com")); + + // + // Additional test cases + // + + // large names, a long but valid one, and invalid (too long) one. + EXPECT_EQ(Name::MAX_WIRE, + nameFactoryFromWire("testdata/name_fromWire9", 0).getLength()); + EXPECT_THROW(nameFactoryFromWire("testdata/name_fromWire10", 0).getLength(), + isc::dns::TooLongName); + + // A name with possible maximum number of labels; awkward but valid + EXPECT_EQ(nameFactoryFromWire("testdata/name_fromWire11", + 0).getLabelCount(), + Name::MAX_LABELS); + + // Wire format including an invalid label length + EXPECT_THROW(nameFactoryFromWire("testdata/name_fromWire12", 0), + isc::dns::BadLabelType); + + // converting upper-case letters to down-case + EXPECT_EQ("vix.com.", nameFactoryFromWire("testdata/name_fromWire1", + 25, true).toText()); + EXPECT_EQ(3, + nameFactoryFromWire("testdata/name_fromWire1", + 25).getLabelCount()); +} + +TEST_F(NameTest, toText) +{ + // tests derived from BIND9 + EXPECT_EQ("a.b.c.d", Name("a.b.c.d").toText(true)); + EXPECT_EQ("a.\\\\[[.c.d", Name("a.\\\\[\\[.c.d").toText(true)); + EXPECT_EQ("a.b.C.d.", Name("a.b.C.d").toText(false)); + EXPECT_EQ("a.b.", Name("a.b.").toText(false)); + + // test omit_final_dot. It's false by default. + EXPECT_EQ("a.b.c.d", Name("a.b.c.d.").toText(true)); + EXPECT_EQ(Name("a.b.").toText(false), Name("a.b.").toText()); + + // the root name is a special case: omit_final_dot will be ignored. + EXPECT_EQ(".", Name(".").toText(true)); + + // test all printable characters to see whether special characters are + // escaped while the others are intact. note that the conversion is + // implementation specific; for example, it's not invalid to escape a + // "normal" character such as 'a' with regard to the standard. + std::string all_printable("!\\\"#\\$%&'\\(\\)*+,-\\./0123456789:\\;<=>?\\@" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "[\\\\]^_.`abcdefghijklmnopqrstuvwxyz{|}~."); + EXPECT_EQ(all_printable, + nameFactoryFromWire("testdata/name_fromWire13", 0).toText()); + + std::string all_nonprintable( + "\\000\\001\\002\\003\\004\\005\\006\\007\\008\\009" + "\\010\\011\\012\\013\\014\\015\\016\\017\\018\\019" + "\\020\\021\\022\\023\\024\\025\\026\\027\\028\\029" + "\\030\\031\\032\\127\\128\\129" + "\\130\\131\\132\\133\\134\\135\\136\\137\\138\\139" + "\\140\\141\\142\\143\\144\\145\\146\\147\\148\\149" + "\\150\\151\\152\\153\\154\\155\\156." + "\\157\\158\\159" + "\\160\\161\\162\\163\\164\\165\\166\\167\\168\\169" + "\\170\\171\\172\\173\\174\\175\\176\\177\\178\\179" + "\\180\\181\\182\\183\\184\\185\\186\\187\\188\\189" + "\\190\\191\\192\\193\\194\\195\\196\\197\\198\\199" + "\\200\\201\\202\\203\\204\\205\\206\\207\\208\\209" + "\\210\\211\\212\\213\\214\\215\\216\\217\\218\\219." + "\\220\\221\\222\\223\\224\\225\\226\\227\\228\\229" + "\\230\\231\\232\\233\\234\\235\\236\\237\\238\\239" + "\\240\\241\\242\\243\\244\\245\\246\\247\\248\\249" + "\\250\\251\\252\\253\\254\\255."); + EXPECT_EQ(all_nonprintable, + nameFactoryFromWire("testdata/name_fromWire14", 0).toText()); +} + +TEST_F(NameTest, toWireBuffer) +{ + std::vector data; + OutputBuffer buffer(0); + + UnitTestUtil::readWireData(std::string("01610376697803636f6d00"), data); + Name("a.vix.com.").toWire(buffer); + EXPECT_EQ(true, buffer.getLength() == data.size() && + memcmp(buffer.getData(), &data[0], data.size()) == 0); +} + +// +// We test various corner cases in Renderer tests, but add this test case +// to fill the code coverage gap. +// +TEST_F(NameTest, toWireRenderer) +{ + std::vector data; + OutputBuffer buffer(0); + MessageRenderer renderer(buffer); + + UnitTestUtil::readWireData(std::string("01610376697803636f6d00"), data); + Name("a.vix.com.").toWire(renderer); + EXPECT_EQ(true, buffer.getLength() == data.size() && + memcmp(buffer.getData(), &data[0], data.size()) == 0); +} + +// +// Helper class to hold comparison test parameters. +// +struct CompareParameters { + CompareParameters(const Name& n1, const Name& n2, + NameComparisonResult::NameRelation r, int o, + unsigned int l) : + name1(n1), name2(n2), reln(r), order(o), labels(l) {} + static int normalizeOrder(int o) + { + if (o > 0) { + return (1); + } else if (o < 0) { + return (-1); + } + return (0); + } + Name name1; + Name name2; + NameComparisonResult::NameRelation reln; + int order; + unsigned int labels; +}; + +TEST_F(NameTest, compare) +{ + std::vector params; + params.push_back(CompareParameters(Name("c.d"), Name("a.b.c.d"), + NameComparisonResult::SUPERDOMAIN, + -1, 3)); + params.push_back(CompareParameters(Name("a.b.c.d"), Name("c.d"), + NameComparisonResult::SUBDOMAIN, 1, 3)); + params.push_back(CompareParameters(Name("a.b.c.d"), Name("c.d.e.f"), + NameComparisonResult::COMMONANCESTOR, + -1, 1)); + params.push_back(CompareParameters(Name("a.b.c.d"), Name("f.g.c.d"), + NameComparisonResult::COMMONANCESTOR, + -1, 3)); + params.push_back(CompareParameters(Name("a.b.c.d"), Name("A.b.C.d."), + NameComparisonResult::EQUAL, + 0, 5)); + + std::vector::const_iterator it; + for (it = params.begin(); it != params.end(); ++it) { + NameComparisonResult result = (*it).name1.compare((*it).name2); + EXPECT_EQ((*it).reln, result.getRelation()); + EXPECT_EQ((*it).order, + CompareParameters::normalizeOrder(result.getOrder())); + EXPECT_EQ((*it).labels, result.getCommonLabels()); + } +} + +TEST_F(NameTest, equal) +{ + EXPECT_TRUE(example_name == Name("WWW.EXAMPLE.COM.")); + EXPECT_TRUE(example_name.equals(Name("WWW.EXAMPLE.COM."))); + EXPECT_TRUE(example_name != Name("www.example.org.")); + EXPECT_TRUE(example_name.nequals(Name("www.example.org."))); + // lengths don't match + EXPECT_TRUE(example_name != Name("www2.example.com.")); + EXPECT_TRUE(example_name.nequals(Name("www2.example.com."))); + // lengths are equal, but # of labels don't match (first test checks the + // prerequisite). + EXPECT_EQ(example_name.getLength(), Name("www\\.example.com.").getLength()); + EXPECT_TRUE(example_name != Name("www\\.example.com.")); + EXPECT_TRUE(example_name.nequals(Name("www\\.example.com."))); +} + +TEST_F(NameTest, isWildcard) +{ + EXPECT_EQ(false, example_name.isWildcard()); + EXPECT_EQ(true, Name("*.a.example.com").isWildcard()); + EXPECT_EQ(false, Name("a.*.example.com").isWildcard()); +} + +TEST_F(NameTest, concatenate) +{ + NameComparisonResult result = + Name("aaa.www.example.com.").compare(Name("aaa").concatenate(example_name)); + EXPECT_EQ(NameComparisonResult::EQUAL, result.getRelation()); + + result = example_name.compare(Name(".").concatenate(example_name)); + EXPECT_EQ(NameComparisonResult::EQUAL, result.getRelation()); + + result = example_name.compare(example_name.concatenate(Name("."))); + EXPECT_EQ(NameComparisonResult::EQUAL, result.getRelation()); + + // concatenating two valid names would result in too long a name. + Name n1("123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789."); + Name n2("123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "1234."); + EXPECT_THROW(n1.concatenate(n2), isc::dns::TooLongName); +} + +TEST_F(NameTest, split) +{ + // normal cases with or without explicitly specifying the trailing dot. + EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(1, 2), + Name("example.com.")); + EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(1, 3), + Name("example.com.")); + // edge cases: only the first or last label. + EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(0, 1), + Name("www.")); + EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(3, 1), + Name(".")); + // invalid range: an exception should be thrown. + EXPECT_THROW(example_name.split(1, 0), isc::dns::OutOfRange); + EXPECT_THROW(example_name.split(2, 3), isc::dns::OutOfRange); +} + +TEST_F(NameTest, downcase) +{ + // usual case: all-upper case name to all-lower case + compareInWireFormat(example_name_upper.downcase(), example_name); + // confirm that non upper-case characters are intact + compareInWireFormat(nameFactoryLowerCase().downcase(), + nameFactoryLowerCase()); + // confirm the calling object is actually modified + example_name_upper.downcase(); + compareInWireFormat(example_name_upper, example_name); + +} + +// +// The following set of tests confirm the result of <=, <, >=, > +// The test logic is simple, and all tests are just straightforward variations +// of the first one. +// +TEST_F(NameTest, leq) +{ + // small <= large is true + EXPECT_TRUE(small_name.leq(large_name)); + EXPECT_TRUE(small_name <= large_name); + + // small <= small is true + EXPECT_TRUE(small_name.leq(small_name)); + EXPECT_TRUE(small_name <= small_name); + + // large <= small is false + EXPECT_FALSE(large_name.leq(small_name)); + EXPECT_FALSE(large_name <= small_name); +} + +TEST_F(NameTest, geq) +{ + EXPECT_TRUE(large_name.geq(small_name)); + EXPECT_TRUE(large_name >= small_name); + + EXPECT_TRUE(large_name.geq(large_name)); + EXPECT_TRUE(large_name >= large_name); + + EXPECT_FALSE(small_name.geq(large_name)); + EXPECT_FALSE(small_name >= large_name); +} + +TEST_F(NameTest, lthan) +{ + EXPECT_TRUE(small_name.lthan(large_name)); + EXPECT_TRUE(small_name < large_name); + + EXPECT_FALSE(small_name.lthan(small_name)); + EXPECT_FALSE(small_name < small_name); + + EXPECT_FALSE(large_name.lthan(small_name)); + EXPECT_FALSE(large_name < small_name); +} + +TEST_F(NameTest, gthan) +{ + EXPECT_TRUE(large_name.gthan(small_name)); + EXPECT_TRUE(large_name > small_name); + + EXPECT_FALSE(large_name.gthan(large_name)); + EXPECT_FALSE(large_name > large_name); + + EXPECT_FALSE(small_name.gthan(large_name)); + EXPECT_FALSE(small_name > large_name); +} + +// test operator<<. We simply confirm it appends the result of toText(). +TEST_F(NameTest, LeftShiftOperator) +{ + std::ostringstream oss; + oss << example_name; + EXPECT_EQ(example_name.toText(), oss.str()); +} +} diff --git a/src/lib/dns/cpp/testdata/name_fromWire1 b/src/lib/dns/cpp/testdata/name_fromWire1 new file mode 100644 index 0000000000..42fc61d831 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire1 @@ -0,0 +1,14 @@ +# +# a global14 compression pointer +# +000a85800001000300000003 +# V i x c o m +0356697803636f6d0000020001c00c00 +02000100000e10000b05697372763102 +7061c00cc00c0002000100000e100009 +066e732d657874c00cc00c0002000100 +000e10000e036e733104676e61630363 +6f6d00c0250001000100000e100004cc +98b886c03c0001000100000e100004cc +98b840c051000100010002a14a0004c6 +97f8f6 diff --git a/src/lib/dns/cpp/testdata/name_fromWire10 b/src/lib/dns/cpp/testdata/name_fromWire10 new file mode 100644 index 0000000000..65be775e2f --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire10 @@ -0,0 +1,12 @@ +# +# Too large name; should trigger an exception. +# +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 040102030400 diff --git a/src/lib/dns/cpp/testdata/name_fromWire11 b/src/lib/dns/cpp/testdata/name_fromWire11 new file mode 100644 index 0000000000..32184f6758 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire11 @@ -0,0 +1,12 @@ +# +# A name with possible maximum number of labels; should be accepted safely. +# +01000100010001000100 01000100010001000100 01000100010001000100 +01000100010001000100 01000100010001000100 01000100010001000100 +01000100010001000100 01000100010001000100 01000100010001000100 +01000100010001000100 01000100010001000100 01000100010001000100 +01000100010001000100 01000100010001000100 01000100010001000100 +01000100010001000100 01000100010001000100 01000100010001000100 +01000100010001000100 01000100010001000100 01000100010001000100 +01000100010001000100 01000100010001000100 01000100010001000100 +01000100010001000100 0100010000 diff --git a/src/lib/dns/cpp/testdata/name_fromWire12 b/src/lib/dns/cpp/testdata/name_fromWire12 new file mode 100644 index 0000000000..073adda486 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire12 @@ -0,0 +1,13 @@ +# +# Wire format including an invalid label length +# +#(1) a (7) e x a m p l e + 01 61 07 65 78 61 6d 70 6c 65 +# invalid label length: 64 +40 +# a "label" of 64 characters: shouldn't be parsed +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f +10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f +20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f +30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f +00 diff --git a/src/lib/dns/cpp/testdata/name_fromWire13 b/src/lib/dns/cpp/testdata/name_fromWire13 new file mode 100644 index 0000000000..447f54bca2 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire13 @@ -0,0 +1,5 @@ +# +# A name including all "printable" characters +# + +3f2122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f1f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e00 diff --git a/src/lib/dns/cpp/testdata/name_fromWire14 b/src/lib/dns/cpp/testdata/name_fromWire14 new file mode 100644 index 0000000000..3123aec373 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire14 @@ -0,0 +1,7 @@ +# +# A name including all "non-printable" characters +# + +3f000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f207f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c +3f9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadb +24dcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00 diff --git a/src/lib/dns/cpp/testdata/name_fromWire2 b/src/lib/dns/cpp/testdata/name_fromWire2 new file mode 100644 index 0000000000..0758a68709 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire2 @@ -0,0 +1,15 @@ +# +# bogus label character (looks like a local compression pointer) +# +000a85800001000300000003 +#this is the bogus label character: +83 +76697803636f6d0000020001c00c00 +02000100000e10000b05697372763102 +7061c00cc00c0002000100000e100009 +066e732d657874c00cc00c0002000100 +000e10000e036e733104676e61630363 +6f6d00c0250001000100000e100004cc +98b886c03c0001000100000e100004cc +98b840c051000100010002a14a0004c6 +97f8f6 diff --git a/src/lib/dns/cpp/testdata/name_fromWire3_1 b/src/lib/dns/cpp/testdata/name_fromWire3_1 new file mode 100644 index 0000000000..e38efcccf5 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire3_1 @@ -0,0 +1,11 @@ +# +# a bad compression pointer starting with the bits 1111 (too big pointer) +# +000a85800001000300000003 +03766978 03636f6d 00 0002 0001 +f00c 0002 0001 0000 0e10 000b 056973727631 027061 c00c +c00c 0002 0001 0000 0e10 0009 066e732d657874 c00c +c00c 0002 0001 0000 0e10 000e 036e7331 04676e6163 03636f6d 00 +c025 0001 0001 0000 0e10 0004 cc98b886 +c03c 0001 0001 0000 0e10 0004 cc98b840 +c051 0001 0001 0002 a14a 0004 c697f8f6 diff --git a/src/lib/dns/cpp/testdata/name_fromWire3_2 b/src/lib/dns/cpp/testdata/name_fromWire3_2 new file mode 100644 index 0000000000..c377bb19c1 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire3_2 @@ -0,0 +1,13 @@ +# +# a bad compression pointer due to forward reference of 0x30 to +# another compression pointer with a valid backreference +# +000a85800001000300000003 +03766978 03636f6d 00 0002 0001 +#'30' is the forward reference, 'c00c' at the end is the valid pointer: +c030 0002 0001 0000 0e10 000b 056973727631 027061 c00c +c00c 0002 0001 0000 0e10 0009 066e732d657874 c00c +c00c 0002 0001 0000 0e10 000e 036e7331 04676e6163 03636f6d 00 +c025 0001 0001 0000 0e10 0004 cc98b886 +c03c 0001 0001 0000 0e10 0004 cc98b840 +c051 0001 0001 0002 a14a 0004 c697f8f6 diff --git a/src/lib/dns/cpp/testdata/name_fromWire4 b/src/lib/dns/cpp/testdata/name_fromWire4 new file mode 100644 index 0000000000..dba6035ab5 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire4 @@ -0,0 +1,45 @@ +# +# invalid name length, pointer at offset 0x0226 points to +# long name at offset 0x25 +# +000a 8580 0001 0003 0000 0001 +03 766978 03 636f6d 00 0002 0001 +c00c 0002 0001 00000e10 +0101 +# long name starts here +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a +03616263 0358595a 03616263 0358595a +03414243 0378797a 03414243 0378797a 00 +# compression pointer start here and refers back to long name +c023 0002 0001 00000e10 0009 066e732d657874 c00c +c00c 0002 0001 00000e10 000e 036e733104676e616303636f6d00 +c025 0001 0001 00000e10 0004 cc98b886 diff --git a/src/lib/dns/cpp/testdata/name_fromWire6 b/src/lib/dns/cpp/testdata/name_fromWire6 new file mode 100644 index 0000000000..fa1abe6a3b --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire6 @@ -0,0 +1,14 @@ +# +# a bad pointer +# +000a85800001000300000003 +# the bad pointer is f00c (offset = 300c) which is too large +0376697803636f6d0000020001 f00c 00 +02000100000e10000b05697372763102 +7061c00cc00c0002000100000e100009 +066e732d657874c00cc00c0002000100 +000e10000e036e733104676e61630363 +6f6d00c0250001000100000e100004cc +98b886c03c0001000100000e100004cc +98b840c051000100010002a14a0004c6 +97f8f6 diff --git a/src/lib/dns/cpp/testdata/name_fromWire7 b/src/lib/dns/cpp/testdata/name_fromWire7 new file mode 100644 index 0000000000..2dedd4adac --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire7 @@ -0,0 +1,6 @@ +# +# input ends unexpectedly +# +000a85800001000300000003 +# parser will start at the ending 'c0', which is an incomplete sequence. +0376697803636f6d0000020001 c0 diff --git a/src/lib/dns/cpp/testdata/name_fromWire8 b/src/lib/dns/cpp/testdata/name_fromWire8 new file mode 100644 index 0000000000..575563d4a7 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire8 @@ -0,0 +1,27 @@ +# +# many hops of compression. absolutely many, but should be decompressed. +# +000a85800001000300000013 +03 766978 03 636f6d 00 0002 0001 +c00c 0002 0001 00000e10 000b 056973727631027061 c00c +c019 0002 0001 00000e10 0009 066e732d657874 c00c +c030 0002 0001 00000e10 000e 036e7331 04676e6163 03636f6d 00 +c045 0001 0001 00000e10 0004 cc98b886 +c05f 0001 0001 00000e10 0004 cc98b840 +c06f 0001 0001 0002a14a 0004 c697f8f6 +c07f 0001 0001 0002a14a 0004 c697f8f6 +c08f 0001 0001 0002a14a 0004 c697f8f6 +c09f 0001 0001 0002a14a 0004 c697f8f6 +c0af 0001 0001 0002a14a 0004 c697f8f6 +c0bf 0001 0001 0002a14a 0004 c697f8f6 +c0cf 0001 0001 0002a14a 0004 c697f8f6 +c0df 0001 0001 0002a14a 0004 c697f8f6 +c0ef 0001 0001 0002a14a 0004 c697f8f6 +c0ff 0001 0001 0002a14a 0004 c697f8f6 +c10f 0001 0001 0002a14a 0004 c697f8f6 +c11f 0001 0001 0002a14a 0004 c697f8f6 +c12f 0001 0001 0002a14a 0004 c697f8f6 +c13f 0001 0001 0002a14a 0004 c697f8f6 +c14f 0001 0001 0002a14a 0004 c697f8f6 +c15f 0001 0001 0002a14a 0004 c697f8f6 +c16f 0001 0001 0002a14a 0004 c697f8f6 diff --git a/src/lib/dns/cpp/testdata/name_fromWire9 b/src/lib/dns/cpp/testdata/name_fromWire9 new file mode 100644 index 0000000000..79b2978e8c --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_fromWire9 @@ -0,0 +1,12 @@ +# +# A possible longest name; should be accepted safely. +# +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 09010203040506070809 09010203040506070809 +09010203040506070809 0301020300 diff --git a/src/lib/dns/cpp/testdata/name_toWire1 b/src/lib/dns/cpp/testdata/name_toWire1 new file mode 100644 index 0000000000..c06ec4baeb --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_toWire1 @@ -0,0 +1,12 @@ +# +# Rendering 3 names with compression. [x] means a compression pointer pointing +# to offset 'x'. +# +#bytes: +# 0 1 2 3 4 5 6 7 8 9 a b c d e +#(1)a(7)e x a m p l e(3)c o m . + 0161076578616d706c6503636f6d00 +#(1)b [2] + 0162c002 +# a . e x a m p l e . o r g . + 0161076578616d706c65036f726700 diff --git a/src/lib/dns/cpp/testdata/name_toWire2 b/src/lib/dns/cpp/testdata/name_toWire2 new file mode 100644 index 0000000000..2377121a0c --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_toWire2 @@ -0,0 +1,14 @@ +# +# Rendering names in a large buffer. [x] means a compression pointer pointing +# to offset 'x'. +# +#bytes: +#3f 40 +#ff 00 +#(1) a (7) e x a m p l e (3) c o m . + 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 +#[3fff] = a.example.com: can be compressed + ffff +#(1) b(7) e x a m p l e (3) c o m .; cannot compress as the pointer +# (0x4001) would exceed 0x4000 + 01 62 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 diff --git a/src/lib/dns/cpp/testdata/name_toWire3 b/src/lib/dns/cpp/testdata/name_toWire3 new file mode 100644 index 0000000000..643768e4b7 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_toWire3 @@ -0,0 +1,14 @@ +# +# Rendering names including one explicitly uncompressed. +# [x] means a compression pointer pointing to offset 'x'. +# +# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 (bytes) +#(1) a (7) e x a m p l e (3) c o m . + 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 + +#15 29 (bytes) +#(1) b(7) e x a m p l e (3) c o m .; specified to be not compressed, +# but can be pointed to from others + 01 62 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 +#[0f] referring to the second (uncompressed name) + c0 0f diff --git a/src/lib/dns/cpp/testdata/name_toWire4 b/src/lib/dns/cpp/testdata/name_toWire4 new file mode 100644 index 0000000000..740d718365 --- /dev/null +++ b/src/lib/dns/cpp/testdata/name_toWire4 @@ -0,0 +1,16 @@ +# +# Rendering 3 names with compression, including one resulting in a chain of +# pointers (the last one). +# legend: [x] means a compression pointer pointing to offset 'x'. +#bytes: +#00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e +#(1) a (7) e x a m p l e (3) c o m . + 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 + +#0f 10 11 12 +#(1) b [2] (b.example.com.) + 01 62 c0 02 + +#13 14 +# [0f]: (b.example.com.) + c0 0f diff --git a/src/lib/dns/cpp/unittest_util.cc b/src/lib/dns/cpp/unittest_util.cc new file mode 100644 index 0000000000..3cbe8c2795 --- /dev/null +++ b/src/lib/dns/cpp/unittest_util.cc @@ -0,0 +1,124 @@ +// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// $Id$ + +#include +#include +#include +#include +#include +#include + +#include + +#include "name.h" +#include "unittest_util.h" + +using isc::UnitTestUtil; +using isc::dns::NameComparisonResult; + +void +UnitTestUtil::readWireData(const char* datafile, + std::vector& data) +{ + std::ifstream ifs; + + ifs.open(datafile, std::ios_base::in); + if ((ifs.rdstate() & std::istream::failbit) != 0) { + throw std::runtime_error("failed to open data file: " + + std::string(datafile)); + } + + data.clear(); + + std::string s; + while (getline(ifs, s), !ifs.eof()) { + if (ifs.bad() || ifs.fail()) { + throw std::runtime_error("unexpected data line"); + } + if (s.empty() || s[0] == '#') { + continue; + } + + readWireData(s, data); + } +} + +void +UnitTestUtil::readWireData(const std::string& datastr, + std::vector& data) +{ + std::istringstream iss(datastr); + + do { + std::string bytes; + iss >> bytes; + if (iss.bad() || iss.fail() || (bytes.size() % 2) != 0) { + throw std::runtime_error("unexpected input or I/O error"); + } + + for (int pos = 0; pos < bytes.size(); pos += 2) { + unsigned int ch; + std::istringstream(bytes.substr(pos, 2)) >> std::hex >> ch; + data.push_back(static_cast(ch)); + } + } while (!iss.eof()); +} + +::testing::AssertionResult +UnitTestUtil::matchWireData(const char* dataexp1, const char* lenexp1, + const char* dataexp2, const char* lenexp2, + const void* data1, size_t len1, + const void* data2, size_t len2) +{ + ::testing::Message msg; + size_t cmplen = std::min(len1, len2); + + for (int i = 0; i < cmplen; i++) { + int ch1 = static_cast(data1)[i]; + int ch2 = static_cast(data2)[i]; + if (ch1 != ch2) { + msg << "Wire data mismatch at " << i << "th byte\n" + << " Actual: " << ch1 << "\n" + << "Expected: " << ch2 << "\n"; + return (::testing::AssertionFailure(msg)); + } + } + if (len1 != len2) { + msg << "Wire data mismatch in length:\n" + << " Actual: " << len1 << "\n" + << "Expected: " << len2 << "\n"; + return (::testing::AssertionFailure(msg)); + } + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult +UnitTestUtil::matchName(const char* nameexp1, const char* nameexp2, + const isc::dns::Name& name1, + const isc::dns::Name& name2) +{ + ::testing::Message msg; + + NameComparisonResult cmpresult = name1.compare(name2); + if (cmpresult.getOrder() != 0 || + cmpresult.getRelation() != NameComparisonResult::EQUAL) { + msg << "Two names are expected to be equal but not:\n" + << " One: " << name1 << "\n" + << "Other: " << name2 << "\n"; + return (::testing::AssertionFailure(msg)); + } + return ::testing::AssertionSuccess(); +} diff --git a/src/lib/dns/cpp/unittest_util.h b/src/lib/dns/cpp/unittest_util.h new file mode 100644 index 0000000000..4d5ced39d8 --- /dev/null +++ b/src/lib/dns/cpp/unittest_util.h @@ -0,0 +1,85 @@ +// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// $Id$ + +#ifndef __UNITTEST_UTIL_H +#define __UNITTEST_UTIL_H 1 + +#include +#include + +#include "name.h" + +#include + +namespace isc { + +class UnitTestUtil { +public: + /// + /// read text format wire data from a file and put it to the given vector. + /// + static void readWireData(const char*datafile, + std::vector& data); + + /// + /// convert a sequence of hex strings into the corresponding list of + /// 8-bit integers, and append them to the vector. + /// + static void readWireData(const std::string& datastr, + std::vector& data); + + /// + /// Compare len1 bytes of data1 with len2 bytes of data2 as binary data. + /// + /// If they don't match report the point of mismatch in the google test + /// format. This method is expected to be used from the EXPECT_PRED_FORMAT4 + /// macro of google test as follows: + /// \code EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, + /// actual_data, actual_data_len, + /// expected_data, expected_data_len); \endcode + /// Parameters from dataexp1 to lenexp2 are passed via the macro but will + /// be ignored by this method. + /// Note: newer versions of google test supports the direct use of + /// AssertionResult with the EXPECT_TRUE macro, which would be more + /// intuitive, but to be as compatible as possible we use the more primitive + /// macro, i.e., EXPECT_PRED_FORMAT4. + /// + static ::testing::AssertionResult + matchWireData(const char* dataexp1, const char* lenexp1, + const char* dataexp2, const char* lenexp2, + const void* data1, size_t len1, + const void* data2, size_t len2); + + /// + /// Compare two names. + /// + /// This check method uses \c Name::compare() for comparison, which performs + /// deeper checks including the equality of offsets, and should be better + /// than EXPECT_EQ, which uses operater==. Like the \c matchWireData() + /// method, the usage is a bit awkward; the caller should use + /// \c EXPECT_PRED_FORMAT2. + /// + static ::testing::AssertionResult + matchName(const char* nameexp1, const char* nameexp2, + const isc::dns::Name& name1, const isc::dns::Name& name2); +}; + +} +#endif // __UNITTEST_UTIL_H + +// Local Variables: +// mode: c++ +// End: