summaryrefslogtreecommitdiff
path: root/omapip
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2015-03-02 19:04:49 +0000
committer <>2015-05-08 15:30:59 +0000
commitf800382616186a5d30e28d8b2c51e97a9a8360f2 (patch)
tree0d5270190548a37223d14b54383ce8a3d3af5302 /omapip
downloadisc-dhcp-tarball-master.tar.gz
Imported from /home/lorry/working-area/delta_isc-dhcp-tarball/dhcp-4.2.8.tar.gz.HEADdhcp-4.2.8master
Diffstat (limited to 'omapip')
-rw-r--r--omapip/Makefile.am14
-rw-r--r--omapip/Makefile.in691
-rw-r--r--omapip/alloc.c1165
-rw-r--r--omapip/array.c156
-rw-r--r--omapip/auth.c278
-rw-r--r--omapip/buffer.c716
-rw-r--r--omapip/connection.c1104
-rw-r--r--omapip/convert.c179
-rw-r--r--omapip/dispatch.c959
-rw-r--r--omapip/errwarn.c363
-rw-r--r--omapip/generic.c299
-rw-r--r--omapip/handle.c302
-rw-r--r--omapip/hash.c560
-rw-r--r--omapip/inet_addr.c135
-rw-r--r--omapip/isclib.c276
-rw-r--r--omapip/iscprint.c539
-rw-r--r--omapip/listener.c484
-rw-r--r--omapip/message.c762
-rw-r--r--omapip/omapi.3249
-rw-r--r--omapip/protocol.c1314
-rw-r--r--omapip/result.c86
-rw-r--r--omapip/support.c853
-rw-r--r--omapip/test.c110
-rw-r--r--omapip/toisc.c211
-rw-r--r--omapip/trace.c719
25 files changed, 12524 insertions, 0 deletions
diff --git a/omapip/Makefile.am b/omapip/Makefile.am
new file mode 100644
index 0000000..595950a
--- /dev/null
+++ b/omapip/Makefile.am
@@ -0,0 +1,14 @@
+lib_LIBRARIES = libomapi.a
+noinst_PROGRAMS = svtest
+
+libomapi_a_SOURCES = protocol.c buffer.c alloc.c result.c connection.c \
+ errwarn.c listener.c dispatch.c generic.c support.c \
+ handle.c message.c convert.c hash.c auth.c inet_addr.c \
+ array.c trace.c toisc.c iscprint.c isclib.c
+
+man_MANS = omapi.3
+EXTRA_DIST = $(man_MANS)
+
+svtest_SOURCES = test.c
+svtest_LDADD = libomapi.a ../bind/lib/libdns.a ../bind/lib/libisc.a
+
diff --git a/omapip/Makefile.in b/omapip/Makefile.in
new file mode 100644
index 0000000..663dd49
--- /dev/null
+++ b/omapip/Makefile.in
@@ -0,0 +1,691 @@
+# Makefile.in generated by automake 1.14 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = svtest$(EXEEXT)
+subdir = omapip
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp
+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)/includes/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)"
+LIBRARIES = $(lib_LIBRARIES)
+AR = ar
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libomapi_a_AR = $(AR) $(ARFLAGS)
+libomapi_a_LIBADD =
+am_libomapi_a_OBJECTS = protocol.$(OBJEXT) buffer.$(OBJEXT) \
+ alloc.$(OBJEXT) result.$(OBJEXT) connection.$(OBJEXT) \
+ errwarn.$(OBJEXT) listener.$(OBJEXT) dispatch.$(OBJEXT) \
+ generic.$(OBJEXT) support.$(OBJEXT) handle.$(OBJEXT) \
+ message.$(OBJEXT) convert.$(OBJEXT) hash.$(OBJEXT) \
+ auth.$(OBJEXT) inet_addr.$(OBJEXT) array.$(OBJEXT) \
+ trace.$(OBJEXT) toisc.$(OBJEXT) iscprint.$(OBJEXT) \
+ isclib.$(OBJEXT)
+libomapi_a_OBJECTS = $(am_libomapi_a_OBJECTS)
+PROGRAMS = $(noinst_PROGRAMS)
+am_svtest_OBJECTS = test.$(OBJEXT)
+svtest_OBJECTS = $(am_svtest_OBJECTS)
+svtest_DEPENDENCIES = libomapi.a ../bind/lib/libdns.a \
+ ../bind/lib/libisc.a
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/includes
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libomapi_a_SOURCES) $(svtest_SOURCES)
+DIST_SOURCES = $(libomapi_a_SOURCES) $(svtest_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+man3dir = $(mandir)/man3
+NROFF = nroff
+MANS = $(man_MANS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ATF_BIN = @ATF_BIN@
+ATF_CFLAGS = @ATF_CFLAGS@
+ATF_LDFLAGS = @ATF_LDFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDAP_CFLAGS = @LDAP_CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+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_prefix_program = @ac_prefix_program@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+byte_order = @byte_order@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+lib_LIBRARIES = libomapi.a
+libomapi_a_SOURCES = protocol.c buffer.c alloc.c result.c connection.c \
+ errwarn.c listener.c dispatch.c generic.c support.c \
+ handle.c message.c convert.c hash.c auth.c inet_addr.c \
+ array.c trace.c toisc.c iscprint.c isclib.c
+
+man_MANS = omapi.3
+EXTRA_DIST = $(man_MANS)
+svtest_SOURCES = test.c
+svtest_LDADD = libomapi.a ../bind/lib/libdns.a ../bind/lib/libisc.a
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign omapip/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign omapip/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: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-libLIBRARIES: $(lib_LIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(INSTALL_DATA) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(INSTALL_DATA) $$list2 "$(DESTDIR)$(libdir)" || exit $$?; }
+ @$(POST_INSTALL)
+ @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ if test -f $$p; then \
+ $(am__strip_dir) \
+ echo " ( cd '$(DESTDIR)$(libdir)' && $(RANLIB) $$f )"; \
+ ( cd "$(DESTDIR)$(libdir)" && $(RANLIB) $$f ) || exit $$?; \
+ else :; fi; \
+ done
+
+uninstall-libLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(libdir)'; $(am__uninstall_files_from_dir)
+
+clean-libLIBRARIES:
+ -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES)
+
+libomapi.a: $(libomapi_a_OBJECTS) $(libomapi_a_DEPENDENCIES) $(EXTRA_libomapi_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libomapi.a
+ $(AM_V_AR)$(libomapi_a_AR) libomapi.a $(libomapi_a_OBJECTS) $(libomapi_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libomapi.a
+
+clean-noinstPROGRAMS:
+ -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+
+svtest$(EXEEXT): $(svtest_OBJECTS) $(svtest_DEPENDENCIES) $(EXTRA_svtest_DEPENDENCIES)
+ @rm -f svtest$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(svtest_OBJECTS) $(svtest_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/array.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/convert.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispatch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errwarn.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/handle.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inet_addr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isclib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iscprint.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listener.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/result.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/support.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/toisc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+install-man3: $(man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1=''; \
+ list2='$(man_MANS)'; \
+ test -n "$(man3dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.3[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man3:
+ @$(NORMAL_UNINSTALL)
+ @list=''; test -n "$(man3dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.3[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLIBRARIES clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man3
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLIBRARIES uninstall-man
+
+uninstall-man: uninstall-man3
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libLIBRARIES clean-noinstPROGRAMS cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am \
+ install-libLIBRARIES install-man install-man3 install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-libLIBRARIES uninstall-man \
+ uninstall-man3
+
+
+# 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/omapip/alloc.c b/omapip/alloc.c
new file mode 100644
index 0000000..a70fe21
--- /dev/null
+++ b/omapip/alloc.c
@@ -0,0 +1,1165 @@
+/* alloc.c
+
+ Functions supporting memory allocation for the object management
+ protocol... */
+
+/*
+ * Copyright (c) 2012,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+struct dmalloc_preamble *dmalloc_list;
+unsigned long dmalloc_outstanding;
+unsigned long dmalloc_longterm;
+unsigned long dmalloc_generation;
+unsigned long dmalloc_cutoff_generation;
+#endif
+
+#if defined (DEBUG_RC_HISTORY)
+struct rc_history_entry rc_history [RC_HISTORY_MAX];
+int rc_history_index;
+int rc_history_count;
+#endif
+
+#if defined (DEBUG_RC_HISTORY)
+static void print_rc_hist_entry (int);
+#endif
+
+void *
+dmalloc(unsigned size, const char *file, int line) {
+ unsigned char *foo;
+ unsigned len;
+ void **bar;
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ int i;
+ struct dmalloc_preamble *dp;
+#endif
+
+ len = size + DMDSIZE;
+ if (len < size)
+ return NULL;
+
+ foo = malloc(len);
+
+ if (!foo)
+ return NULL;
+ bar = (void *)(foo + DMDOFFSET);
+ memset (bar, 0, size);
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ dp = (struct dmalloc_preamble *)foo;
+ dp -> prev = dmalloc_list;
+ if (dmalloc_list)
+ dmalloc_list -> next = dp;
+ dmalloc_list = dp;
+ dp -> next = (struct dmalloc_preamble *)0;
+ dp -> size = size;
+ dp -> file = file;
+ dp -> line = line;
+ dp -> generation = dmalloc_generation++;
+ dmalloc_outstanding += size;
+ for (i = 0; i < DMLFSIZE; i++)
+ dp -> low_fence [i] =
+ (((unsigned long)
+ (&dp -> low_fence [i])) % 143) + 113;
+ for (i = DMDOFFSET; i < DMDSIZE; i++)
+ foo [i + size] =
+ (((unsigned long)
+ (&foo [i + size])) % 143) + 113;
+#if defined (DEBUG_MALLOC_POOL_EXHAUSTIVELY)
+ /* Check _every_ entry in the pool! Very expensive. */
+ for (dp = dmalloc_list; dp; dp = dp -> prev) {
+ for (i = 0; i < DMLFSIZE; i++) {
+ if (dp -> low_fence [i] !=
+ (((unsigned long)
+ (&dp -> low_fence [i])) % 143) + 113)
+ {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+ foo = (unsigned char *)dp;
+ for (i = DMDOFFSET; i < DMDSIZE; i++) {
+ if (foo [i + dp -> size] !=
+ (((unsigned long)
+ (&foo [i + dp -> size])) % 143) + 113) {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+ }
+#endif
+#endif
+#ifdef DEBUG_REFCNT_DMALLOC_FREE
+ rc_register (file, line, 0, foo + DMDOFFSET, 1, 0, RC_MALLOC);
+#endif
+ return bar;
+}
+
+void
+dfree(void *ptr, const char *file, int line) {
+ if (!ptr) {
+ log_error ("dfree %s(%d): free on null pointer.", file, line);
+ return;
+ }
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ {
+ unsigned char *bar = ptr;
+ struct dmalloc_preamble *dp, *cur;
+ int i;
+ bar -= DMDOFFSET;
+ cur = (struct dmalloc_preamble *)bar;
+ for (dp = dmalloc_list; dp; dp = dp -> prev)
+ if (dp == cur)
+ break;
+ if (!dp) {
+ log_error ("%s(%d): freeing unknown memory: %lx",
+ file, line, (unsigned long)cur);
+ abort ();
+ }
+ if (dp -> prev)
+ dp -> prev -> next = dp -> next;
+ if (dp -> next)
+ dp -> next -> prev = dp -> prev;
+ if (dp == dmalloc_list)
+ dmalloc_list = dp -> prev;
+ if (dp -> generation >= dmalloc_cutoff_generation)
+ dmalloc_outstanding -= dp -> size;
+ else
+ dmalloc_longterm -= dp -> size;
+
+ for (i = 0; i < DMLFSIZE; i++) {
+ if (dp -> low_fence [i] !=
+ (((unsigned long)
+ (&dp -> low_fence [i])) % 143) + 113)
+ {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+ for (i = DMDOFFSET; i < DMDSIZE; i++) {
+ if (bar [i + dp -> size] !=
+ (((unsigned long)
+ (&bar [i + dp -> size])) % 143) + 113) {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+ ptr = bar;
+ }
+#endif
+#ifdef DEBUG_REFCNT_DMALLOC_FREE
+ rc_register (file, line,
+ 0, (unsigned char *)ptr + DMDOFFSET, 0, 1, RC_MALLOC);
+#endif
+ free (ptr);
+}
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+/* For allocation functions that keep their own free lists, we want to
+ account for the reuse of the memory. */
+
+void
+dmalloc_reuse(void *foo, const char *file, int line, int justref) {
+ struct dmalloc_preamble *dp;
+
+ /* Get the pointer to the dmalloc header. */
+ dp = foo;
+ dp--;
+
+ /* If we just allocated this and are now referencing it, this
+ function would almost be a no-op, except that it would
+ increment the generation count needlessly. So just return
+ in this case. */
+ if (dp -> generation == dmalloc_generation)
+ return;
+
+ /* If this is longterm data, and we just made reference to it,
+ don't put it on the short-term list or change its name -
+ we don't need to know about this. */
+ if (dp -> generation < dmalloc_cutoff_generation && justref)
+ return;
+
+ /* Take it out of the place in the allocated list where it was. */
+ if (dp -> prev)
+ dp -> prev -> next = dp -> next;
+ if (dp -> next)
+ dp -> next -> prev = dp -> prev;
+ if (dp == dmalloc_list)
+ dmalloc_list = dp -> prev;
+
+ /* Account for its removal. */
+ if (dp -> generation >= dmalloc_cutoff_generation)
+ dmalloc_outstanding -= dp -> size;
+ else
+ dmalloc_longterm -= dp -> size;
+
+ /* Now put it at the head of the list. */
+ dp -> prev = dmalloc_list;
+ if (dmalloc_list)
+ dmalloc_list -> next = dp;
+ dmalloc_list = dp;
+ dp -> next = (struct dmalloc_preamble *)0;
+
+ /* Change the reference location information. */
+ dp -> file = file;
+ dp -> line = line;
+
+ /* Increment the generation. */
+ dp -> generation = dmalloc_generation++;
+
+ /* Account for it. */
+ dmalloc_outstanding += dp -> size;
+}
+
+void dmalloc_dump_outstanding ()
+{
+ static unsigned long dmalloc_cutoff_point;
+ struct dmalloc_preamble *dp;
+#if defined(DEBUG_MALLOC_POOL)
+ unsigned char *foo;
+ int i;
+#endif
+
+ if (!dmalloc_cutoff_point)
+ dmalloc_cutoff_point = dmalloc_cutoff_generation;
+ for (dp = dmalloc_list; dp; dp = dp -> prev) {
+ if (dp -> generation <= dmalloc_cutoff_point)
+ break;
+#if defined (DEBUG_MALLOC_POOL)
+ for (i = 0; i < DMLFSIZE; i++) {
+ if (dp -> low_fence [i] !=
+ (((unsigned long)
+ (&dp -> low_fence [i])) % 143) + 113)
+ {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+ foo = (unsigned char *)dp;
+ for (i = DMDOFFSET; i < DMDSIZE; i++) {
+ if (foo [i + dp -> size] !=
+ (((unsigned long)
+ (&foo [i + dp -> size])) % 143) + 113) {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ /* Don't count data that's actually on a free list
+ somewhere. */
+ if (dp -> file) {
+#if defined (DEBUG_RC_HISTORY)
+ int i, count, inhistory = 0, noted = 0;
+
+ /* If we have the info, see if this is actually
+ new garbage. */
+ if (rc_history_count < RC_HISTORY_MAX) {
+ count = rc_history_count;
+ } else
+ count = RC_HISTORY_MAX;
+ i = rc_history_index - 1;
+ if (i < 0)
+ i += RC_HISTORY_MAX;
+
+ do {
+ if (rc_history [i].addr == dp + 1) {
+ inhistory = 1;
+ if (!noted) {
+ log_info (" %s(%d): %ld", dp -> file,
+ dp -> line, (long) dp -> size);
+ noted = 1;
+ }
+ print_rc_hist_entry (i);
+ if (!rc_history [i].refcnt)
+ break;
+ }
+ if (--i < 0)
+ i = RC_HISTORY_MAX - 1;
+ } while (count--);
+ if (!inhistory)
+#endif
+ log_info (" %s(%d): %ld",
+ dp -> file, dp -> line,
+ (long) dp -> size);
+ }
+#endif
+ }
+ if (dmalloc_list)
+ dmalloc_cutoff_point = dmalloc_list -> generation;
+}
+#endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */
+
+#if defined (DEBUG_RC_HISTORY)
+static void print_rc_hist_entry (int i)
+{
+ log_info (" referenced by %s(%d)[%lx]: addr = %lx refcnt = %x",
+ rc_history [i].file, rc_history [i].line,
+ (unsigned long)rc_history [i].reference,
+ (unsigned long)rc_history [i].addr,
+ rc_history [i].refcnt);
+}
+
+void dump_rc_history (void *addr)
+{
+ int i;
+
+ i = rc_history_index;
+ if (!rc_history [i].file)
+ i = 0;
+ else if (rc_history_count < RC_HISTORY_MAX) {
+ i -= rc_history_count;
+ if (i < 0)
+ i += RC_HISTORY_MAX;
+ }
+ rc_history_count = 0;
+
+ while (rc_history [i].file) {
+ if (!addr || addr == rc_history [i].addr)
+ print_rc_hist_entry (i);
+ ++i;
+ if (i == RC_HISTORY_MAX)
+ i = 0;
+ if (i == rc_history_index)
+ break;
+ }
+}
+void rc_history_next (int d)
+{
+#if defined (RC_HISTORY_COMPRESSION)
+ int i, j = 0, m, n = 0;
+ void *ap, *rp;
+
+ /* If we are decreasing the reference count, try to find the
+ entry where the reference was made and eliminate it; then
+ we can also eliminate this reference. */
+ if (d) {
+ m = rc_history_index - 1000;
+ if (m < -1)
+ m = -1;
+ ap = rc_history [rc_history_index].addr;
+ rp = rc_history [rc_history_index].reference;
+ for (i = rc_history_index - 1; i > m; i--) {
+ if (rc_history [i].addr == ap) {
+ if (rc_history [i].reference == rp) {
+ if (n > 10) {
+ for (n = i; n <= rc_history_index; n++)
+ print_rc_hist_entry (n);
+ n = 11;
+ }
+ memmove (&rc_history [i],
+ &rc_history [i + 1],
+ (unsigned)((rc_history_index - i) *
+ sizeof (struct rc_history_entry)));
+ --rc_history_count;
+ --rc_history_index;
+ for (j = i; j < rc_history_count; j++) {
+ if (rc_history [j].addr == ap)
+ --rc_history [j].refcnt;
+ }
+ if (n > 10) {
+ for (n = i; n <= rc_history_index; n++)
+ print_rc_hist_entry (n);
+ n = 11;
+ exit (0);
+ }
+ return;
+ }
+ }
+ }
+ }
+#endif
+ if (++rc_history_index == RC_HISTORY_MAX)
+ rc_history_index = 0;
+ ++rc_history_count;
+}
+#endif /* DEBUG_RC_HISTORY */
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+struct caller {
+ struct dmalloc_preamble *dp;
+ int count;
+};
+
+static int dmalloc_find_entry (struct dmalloc_preamble *dp,
+ struct caller *array,
+ int min, int max)
+{
+ int middle;
+
+ middle = (min + max) / 2;
+ if (middle == min)
+ return middle;
+ if (array [middle].dp -> file == dp -> file) {
+ if (array [middle].dp -> line == dp -> line)
+ return middle;
+ else if (array [middle].dp -> line < dp -> line)
+ return dmalloc_find_entry (dp, array, middle, max);
+ else
+ return dmalloc_find_entry (dp, array, 0, middle);
+ } else if (array [middle].dp -> file < dp -> file)
+ return dmalloc_find_entry (dp, array, middle, max);
+ else
+ return dmalloc_find_entry (dp, array, 0, middle);
+}
+
+void omapi_print_dmalloc_usage_by_caller ()
+{
+ struct dmalloc_preamble *dp;
+ int ccur, cmax, i;
+ struct caller cp [1024];
+
+ cmax = 1024;
+ ccur = 0;
+
+ memset (cp, 0, sizeof cp);
+ for (dp = dmalloc_list; dp; dp = dp -> prev) {
+ i = dmalloc_find_entry (dp, cp, 0, ccur);
+ if ((i == ccur ||
+ cp [i].dp -> file != dp -> file ||
+ cp [i].dp -> line != dp -> line) &&
+ ccur == cmax) {
+ log_error ("no space for memory usage summary.");
+ return;
+ }
+ if (i == ccur) {
+ cp [ccur++].dp = dp;
+ cp [i].count = 1;
+ } else if (cp [i].dp -> file < dp -> file ||
+ (cp [i].dp -> file == dp -> file &&
+ cp [i].dp -> line < dp -> line)) {
+ if (i + 1 != ccur)
+ memmove (cp + i + 2, cp + i + 1,
+ (ccur - i) * sizeof *cp);
+ cp [i + 1].dp = dp;
+ cp [i + 1].count = 1;
+ ccur++;
+ } else if (cp [i].dp -> file != dp -> file ||
+ cp [i].dp -> line != dp -> line) {
+ memmove (cp + i + 1,
+ cp + i, (ccur - i) * sizeof *cp);
+ cp [i].dp = dp;
+ cp [i].count = 1;
+ ccur++;
+ } else
+ cp [i].count++;
+#if 0
+ printf ("%d\t%s:%d\n", i, dp -> file, dp -> line);
+ dump_rc_history (dp + 1);
+#endif
+ }
+ for (i = 0; i < ccur; i++) {
+ printf ("%d\t%s:%d\t%d\n", i,
+ cp [i].dp -> file, cp [i].dp -> line, cp [i].count);
+#if defined(DUMP_RC_HISTORY)
+ dump_rc_history (cp [i].dp + 1);
+#endif
+ }
+}
+#endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */
+
+isc_result_t omapi_object_allocate (omapi_object_t **o,
+ omapi_object_type_t *type,
+ size_t size,
+ const char *file, int line)
+{
+ size_t tsize;
+ omapi_object_t *foo;
+ isc_result_t status;
+
+ if (type -> allocator) {
+ foo = (omapi_object_t *)0;
+ status = (*type -> allocator) (&foo, file, line);
+ tsize = type -> size;
+ } else {
+ status = ISC_R_NOMEMORY;
+ tsize = 0;
+ }
+
+ if (status == ISC_R_NOMEMORY) {
+ if (type -> sizer)
+ tsize = (*type -> sizer) (size);
+ else
+ tsize = type -> size;
+
+ /* Sanity check. */
+ if (tsize < sizeof (omapi_object_t))
+ return DHCP_R_INVALIDARG;
+
+ foo = dmalloc (tsize, file, line);
+ if (!foo)
+ return ISC_R_NOMEMORY;
+ }
+
+ status = omapi_object_initialize (foo, type, size, tsize, file, line);
+ if (status != ISC_R_SUCCESS) {
+ if (type -> freer)
+ (*type -> freer) (foo, file, line);
+ else
+ dfree (foo, file, line);
+ return status;
+ }
+ return omapi_object_reference (o, foo, file, line);
+}
+
+isc_result_t omapi_object_initialize (omapi_object_t *o,
+ omapi_object_type_t *type,
+ size_t usize, size_t psize,
+ const char *file, int line)
+{
+ memset (o, 0, psize);
+ o -> type = type;
+ if (type -> initialize)
+ (*type -> initialize) (o, file, line);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_object_reference (omapi_object_t **r,
+ omapi_object_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return DHCP_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!",
+ file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, h -> type -> rc_flag);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_object_dereference (omapi_object_t **h,
+ const char *file, int line)
+{
+ int outer_reference = 0;
+ int inner_reference = 0;
+ int handle_reference = 0;
+ int extra_references;
+ omapi_object_t *p, *hp;
+
+ if (!h)
+ return DHCP_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with refcnt of zero!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ /* See if this object's inner object refers to it, but don't
+ count this as a reference if we're being asked to free the
+ reference from the inner object. */
+ if ((*h) -> inner && (*h) -> inner -> outer &&
+ h != &((*h) -> inner -> outer))
+ inner_reference = 1;
+
+ /* Ditto for the outer object. */
+ if ((*h) -> outer && (*h) -> outer -> inner &&
+ h != &((*h) -> outer -> inner))
+ outer_reference = 1;
+
+ /* Ditto for the outer object. The code below assumes that
+ the only reason we'd get a dereference from the handle
+ table is if this function does it - otherwise we'd have to
+ traverse the handle table to find the address where the
+ reference is stored and compare against that, and we don't
+ want to do that if we can avoid it. */
+ if ((*h) -> handle)
+ handle_reference = 1;
+
+ /* If we are getting rid of the last reference other than
+ references to inner and outer objects, or from the handle
+ table, then we must examine all the objects in either
+ direction to see if they hold any non-inner, non-outer,
+ non-handle-table references. If not, we need to free the
+ entire chain of objects. */
+ if ((*h) -> refcnt ==
+ inner_reference + outer_reference + handle_reference + 1) {
+ if (inner_reference || outer_reference || handle_reference) {
+ /* XXX we could check for a reference from the
+ handle table here. */
+ extra_references = 0;
+ for (p = (*h) -> inner;
+ p && !extra_references; p = p -> inner) {
+ extra_references += p -> refcnt;
+ if (p -> inner && p -> inner -> outer == p)
+ --extra_references;
+ if (p -> outer)
+ --extra_references;
+ if (p -> handle)
+ --extra_references;
+ }
+ for (p = (*h) -> outer;
+ p && !extra_references; p = p -> outer) {
+ extra_references += p -> refcnt;
+ if (p -> outer && p -> outer -> inner == p)
+ --extra_references;
+ if (p -> inner)
+ --extra_references;
+ if (p -> handle)
+ --extra_references;
+ }
+ } else
+ extra_references = 0;
+
+ if (!extra_references) {
+ hp = *h;
+ *h = 0;
+ hp -> refcnt--;
+ if (inner_reference)
+ omapi_object_dereference
+ (&hp -> inner, file, line);
+ if (outer_reference)
+ omapi_object_dereference
+ (&hp -> outer, file, line);
+/* if (!hp -> type -> freer) */
+ rc_register (file, line, h, hp,
+ 0, 1, hp -> type -> rc_flag);
+ if (handle_reference) {
+ if (omapi_handle_clear(hp->handle) !=
+ ISC_R_SUCCESS) {
+ log_debug("Attempt to clear null "
+ "handle pointer");
+ }
+ }
+ if (hp -> type -> destroy)
+ (*(hp -> type -> destroy)) (hp, file, line);
+ if (hp -> type -> freer)
+ (hp -> type -> freer (hp, file, line));
+ else
+ dfree (hp, file, line);
+ } else {
+ (*h) -> refcnt--;
+/* if (!(*h) -> type -> freer) */
+ rc_register (file, line,
+ h, *h, (*h) -> refcnt, 1,
+ (*h) -> type -> rc_flag);
+ }
+ } else {
+ (*h) -> refcnt--;
+/* if (!(*h) -> type -> freer) */
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1,
+ (*h) -> type -> rc_flag);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_buffer_new (omapi_buffer_t **h,
+ const char *file, int line)
+{
+ omapi_buffer_t *t;
+ isc_result_t status;
+
+ t = (omapi_buffer_t *)dmalloc (sizeof *t, file, line);
+ if (!t)
+ return ISC_R_NOMEMORY;
+ memset (t, 0, sizeof *t);
+ status = omapi_buffer_reference (h, t, file, line);
+ if (status != ISC_R_SUCCESS)
+ dfree (t, file, line);
+ (*h) -> head = sizeof ((*h) -> buf) - 1;
+ return status;
+}
+
+isc_result_t omapi_buffer_reference (omapi_buffer_t **r,
+ omapi_buffer_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return DHCP_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!",
+ file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_buffer_dereference (omapi_buffer_t **h,
+ const char *file, int line)
+{
+ if (!h)
+ return DHCP_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with refcnt of zero!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ --(*h) -> refcnt;
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC);
+ if ((*h) -> refcnt == 0)
+ dfree (*h, file, line);
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_typed_data_new (const char *file, int line,
+ omapi_typed_data_t **t,
+ omapi_datatype_t type, ...)
+{
+ va_list l;
+ omapi_typed_data_t *new;
+ unsigned len;
+ unsigned val = 0;
+ int intval = 0;
+ char *s = NULL;
+ isc_result_t status;
+ omapi_object_t *obj = NULL;
+
+ va_start (l, type);
+
+ switch (type) {
+ case omapi_datatype_int:
+ len = OMAPI_TYPED_DATA_INT_LEN;
+ intval = va_arg (l, int);
+ break;
+ case omapi_datatype_string:
+ s = va_arg (l, char *);
+ val = strlen (s);
+ len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val;
+ if (len < val) {
+ va_end(l);
+ return DHCP_R_INVALIDARG;
+ }
+ break;
+ case omapi_datatype_data:
+ val = va_arg (l, unsigned);
+ len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val;
+ if (len < val) {
+ va_end(l);
+ return DHCP_R_INVALIDARG;
+ }
+ break;
+ case omapi_datatype_object:
+ len = OMAPI_TYPED_DATA_OBJECT_LEN;
+ obj = va_arg (l, omapi_object_t *);
+ break;
+ default:
+ va_end (l);
+ return DHCP_R_INVALIDARG;
+ }
+ va_end (l);
+
+ new = dmalloc (len, file, line);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, len);
+
+ switch (type) {
+ case omapi_datatype_int:
+ new -> u.integer = intval;
+ break;
+ case omapi_datatype_string:
+ memcpy (new -> u.buffer.value, s, val);
+ new -> u.buffer.len = val;
+ break;
+ case omapi_datatype_data:
+ new -> u.buffer.len = val;
+ break;
+ case omapi_datatype_object:
+ status = omapi_object_reference (&new -> u.object, obj,
+ file, line);
+ if (status != ISC_R_SUCCESS) {
+ dfree (new, file, line);
+ return status;
+ }
+ break;
+ }
+ new -> type = type;
+
+ return omapi_typed_data_reference (t, new, file, line);
+}
+
+isc_result_t omapi_typed_data_reference (omapi_typed_data_t **r,
+ omapi_typed_data_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return DHCP_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!", file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_typed_data_dereference (omapi_typed_data_t **h,
+ const char *file, int line)
+{
+ if (!h)
+ return DHCP_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with refcnt of zero!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ --((*h) -> refcnt);
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC);
+ if ((*h) -> refcnt <= 0 ) {
+ switch ((*h) -> type) {
+ case omapi_datatype_int:
+ case omapi_datatype_string:
+ case omapi_datatype_data:
+ default:
+ break;
+ case omapi_datatype_object:
+ omapi_object_dereference (&(*h) -> u.object,
+ file, line);
+ break;
+ }
+ dfree (*h, file, line);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_data_string_new (omapi_data_string_t **d, unsigned len,
+ const char *file, int line)
+{
+ omapi_data_string_t *new;
+ unsigned nlen;
+
+ nlen = OMAPI_DATA_STRING_EMPTY_SIZE + len;
+ if (nlen < len)
+ return DHCP_R_INVALIDARG;
+ new = dmalloc (nlen, file, line);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, OMAPI_DATA_STRING_EMPTY_SIZE);
+ new -> len = len;
+ return omapi_data_string_reference (d, new, file, line);
+}
+
+isc_result_t omapi_data_string_reference (omapi_data_string_t **r,
+ omapi_data_string_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return DHCP_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!", file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_data_string_dereference (omapi_data_string_t **h,
+ const char *file, int line)
+{
+ if (!h)
+ return DHCP_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with refcnt of zero!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ --((*h) -> refcnt);
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC);
+ if ((*h) -> refcnt <= 0 ) {
+ dfree (*h, file, line);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_value_new (omapi_value_t **d,
+ const char *file, int line)
+{
+ omapi_value_t *new;
+
+ new = dmalloc (sizeof *new, file, line);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, sizeof *new);
+ return omapi_value_reference (d, new, file, line);
+}
+
+isc_result_t omapi_value_reference (omapi_value_t **r,
+ omapi_value_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return DHCP_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!",
+ file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_value_dereference (omapi_value_t **h,
+ const char *file, int line)
+{
+ if (!h)
+ return DHCP_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with refcnt of zero!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ --((*h) -> refcnt);
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC);
+ if ((*h) -> refcnt == 0) {
+ if ((*h) -> name)
+ omapi_data_string_dereference (&(*h) -> name,
+ file, line);
+ if ((*h) -> value)
+ omapi_typed_data_dereference (&(*h) -> value,
+ file, line);
+ dfree (*h, file, line);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_addr_list_new (omapi_addr_list_t **d, unsigned count,
+ const char *file, int line)
+{
+ omapi_addr_list_t *new;
+
+ new = dmalloc ((count * sizeof (omapi_addr_t)) +
+ sizeof (omapi_addr_list_t), file, line);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, ((count * sizeof (omapi_addr_t)) +
+ sizeof (omapi_addr_list_t)));
+ new -> count = count;
+ new -> addresses = (omapi_addr_t *)(new + 1);
+ return omapi_addr_list_reference (d, new, file, line);
+}
+
+isc_result_t omapi_addr_list_reference (omapi_addr_list_t **r,
+ omapi_addr_list_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return DHCP_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!",
+ file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_addr_list_dereference (omapi_addr_list_t **h,
+ const char *file, int line)
+{
+ if (!h)
+ return DHCP_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with zero refcnt!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return DHCP_R_INVALIDARG;
+#endif
+ }
+
+ --((*h) -> refcnt);
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC);
+ if ((*h) -> refcnt <= 0 ) {
+ dfree (*h, file, line);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
diff --git a/omapip/array.c b/omapip/array.c
new file mode 100644
index 0000000..5e67d27
--- /dev/null
+++ b/omapip/array.c
@@ -0,0 +1,156 @@
+/* listener.c
+
+ Subroutines that support the omapi extensible array type. */
+
+/*
+ * Copyright (c) 2004-2007,2009,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2001-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+
+/* Allocate a new extensible array. */
+
+isc_result_t omapi_array_allocate (omapi_array_t **array,
+ omapi_array_ref_t ref,
+ omapi_array_deref_t deref,
+ const char *file, int line)
+{
+ omapi_array_t *aptr;
+
+ if (!array || *array)
+ return DHCP_R_INVALIDARG;
+ aptr = dmalloc (sizeof (omapi_array_t),file, line);
+ if (!aptr)
+ return ISC_R_NOMEMORY;
+ *array = aptr;
+ aptr -> ref = ref;
+ aptr -> deref = deref;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_array_free (omapi_array_t **array,
+ const char *file, int line)
+{
+ omapi_array_t *aptr;
+ int i;
+
+ if (!array || !*array)
+ return DHCP_R_INVALIDARG;
+ aptr = *array;
+ for (i = 0; i < aptr -> count; i++)
+ if (aptr -> data [i] && aptr -> deref)
+ (*aptr -> deref) (&aptr -> data [i], file, line);
+ dfree (aptr -> data, MDL);
+ dfree (aptr, MDL);
+ *array = (omapi_array_t *)0;
+ return ISC_R_SUCCESS;
+}
+
+/* Extend the size of the array by one entry (we may allocate more than that)
+ and store the specified value in the new array element. */
+
+isc_result_t omapi_array_extend (omapi_array_t *array, char *ptr,
+ int *index, const char *file, int line)
+{
+ isc_result_t status;
+ int new = array -> count;
+ status = omapi_array_set (array, ptr, new, file, line);
+ if (index && status == ISC_R_SUCCESS)
+ *index = new;
+ return status;
+}
+
+/* Set a value in the specified array, extending it if necessary. */
+
+isc_result_t omapi_array_set (omapi_array_t *array, void *ptr, int index,
+ const char *file, int line)
+{
+ char **newbuf;
+ int delta;
+ isc_result_t status;
+
+ if (!array)
+ return DHCP_R_INVALIDARG;
+ if (!ptr)
+ return DHCP_R_INVALIDARG;
+ if (index < 0)
+ return DHCP_R_INVALIDARG;
+
+ /* If the proposed index is larger than the current available
+ space in the array, make more space in the array. */
+ if (array -> max <= index) {
+ delta = index - array -> max + 10;
+ newbuf = dmalloc ((array -> max + delta) * sizeof (char *),
+ file, line);
+ if (!newbuf)
+ return ISC_R_NOMEMORY;
+ /* Zero the new elements. */
+ memset (&newbuf [array -> max], 0, (sizeof (char *)) * delta);
+ array -> max += delta;
+ /* Copy the old array data into the new buffer. */
+ if (array -> data) {
+ memcpy (newbuf,
+ array -> data, array -> count * sizeof (char *));
+ dfree (array -> data, file, line);
+ }
+ array -> data = newbuf;
+ } else {
+ /* If there's already data there, and this is an array
+ of references, dereference what's there. */
+ if (array -> data [index]) {
+ status = ((*array -> deref) (&array -> data [index],
+ file, line));
+
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+ }
+
+ /* Store the pointer using the referencer function. We have
+ either just memset this to zero or dereferenced what was
+ there previously, so there is no need to do anything if the
+ pointer we have been asked to store is null. */
+ if (ptr) {
+ status = (*array -> ref) (&array -> data [index], ptr,
+ file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+ if (index >= array -> count)
+ array -> count = index + 1;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_array_lookup (char **ptr, omapi_array_t *array, int index,
+ const char *file, int line)
+{
+ if (!array || !ptr || *ptr || index < 0 || index >= array -> count)
+ return DHCP_R_INVALIDARG;
+ if (array -> data [index])
+ return (*array -> ref) (ptr,
+ array -> data [index], file, line);
+ return ISC_R_NOTFOUND;
+}
+
diff --git a/omapip/auth.c b/omapip/auth.c
new file mode 100644
index 0000000..1f400d0
--- /dev/null
+++ b/omapip/auth.c
@@ -0,0 +1,278 @@
+/* auth.c
+
+ Subroutines having to do with authentication. */
+
+/*
+ * Copyright (c) 2009-2010,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+
+OMAPI_OBJECT_ALLOC (omapi_auth_key, omapi_auth_key_t, omapi_type_auth_key)
+typedef struct hash omapi_auth_hash_t;
+HASH_FUNCTIONS_DECL (omapi_auth_key, const char *,
+ omapi_auth_key_t, omapi_auth_hash_t)
+omapi_auth_hash_t *auth_key_hash;
+HASH_FUNCTIONS (omapi_auth_key, const char *, omapi_auth_key_t,
+ omapi_auth_hash_t,
+ omapi_auth_key_reference, omapi_auth_key_dereference,
+ do_case_hash)
+
+isc_result_t omapi_auth_key_new (omapi_auth_key_t **o, const char *file,
+ int line)
+{
+ return omapi_auth_key_allocate (o, file, line);
+}
+
+isc_result_t omapi_auth_key_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_auth_key_t *a;
+
+ if (h->type != omapi_type_auth_key)
+ return DHCP_R_INVALIDARG;
+ a = (omapi_auth_key_t *)h;
+
+ if (auth_key_hash != NULL)
+ omapi_auth_key_hash_delete(auth_key_hash, a->name, 0, MDL);
+
+ if (a->name != NULL)
+ dfree(a->name, MDL);
+ if (a->algorithm != NULL)
+ dfree(a->algorithm, MDL);
+ if (a->key != NULL)
+ omapi_data_string_dereference(&a->key, MDL);
+ if (a->tsec_key != NULL)
+ dns_tsec_destroy(&a->tsec_key);
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_auth_key_enter (omapi_auth_key_t *a)
+{
+ omapi_auth_key_t *tk;
+ isc_result_t status;
+ dst_key_t *dstkey;
+
+ if (a -> type != omapi_type_auth_key)
+ return DHCP_R_INVALIDARG;
+
+ tk = (omapi_auth_key_t *)0;
+ if (auth_key_hash) {
+ omapi_auth_key_hash_lookup (&tk, auth_key_hash,
+ a -> name, 0, MDL);
+ if (tk == a) {
+ omapi_auth_key_dereference (&tk, MDL);
+ return ISC_R_SUCCESS;
+ }
+ if (tk) {
+ omapi_auth_key_hash_delete (auth_key_hash,
+ tk -> name, 0, MDL);
+ omapi_auth_key_dereference (&tk, MDL);
+ }
+ } else {
+ if (!omapi_auth_key_new_hash(&auth_key_hash,
+ KEY_HASH_SIZE, MDL))
+ return ISC_R_NOMEMORY;
+ }
+
+ /*
+ * If possible create a tsec structure for this key,
+ * if we can't create the structure we put out a warning
+ * and continue.
+ */
+ status = isclib_make_dst_key(a->name, a->algorithm,
+ a->key->value, a->key->len,
+ &dstkey);
+ if (status == ISC_R_SUCCESS) {
+ status = dns_tsec_create(dhcp_gbl_ctx.mctx, dns_tsectype_tsig,
+ dstkey, &a->tsec_key);
+ dst_key_free(&dstkey);
+ }
+ if (status != ISC_R_SUCCESS)
+ log_error("Unable to create tsec structure for %s", a->name);
+
+ omapi_auth_key_hash_add (auth_key_hash, a -> name, 0, a, MDL);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_auth_key_lookup_name (omapi_auth_key_t **a,
+ const char *name)
+{
+ if (!auth_key_hash)
+ return ISC_R_NOTFOUND;
+ if (!omapi_auth_key_hash_lookup (a, auth_key_hash, name, 0, MDL))
+ return ISC_R_NOTFOUND;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_auth_key_lookup (omapi_object_t **h,
+ omapi_object_t *id,
+ omapi_object_t *ref)
+{
+ isc_result_t status;
+ omapi_value_t *name = (omapi_value_t *)0;
+ omapi_value_t *algorithm = (omapi_value_t *)0;
+
+ if (!auth_key_hash)
+ return ISC_R_NOTFOUND;
+
+ if (!ref)
+ return DHCP_R_NOKEYS;
+
+ status = omapi_get_value_str (ref, id, "name", &name);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ if ((name -> value -> type != omapi_datatype_string) &&
+ (name -> value -> type != omapi_datatype_data)) {
+ omapi_value_dereference (&name, MDL);
+ return ISC_R_NOTFOUND;
+ }
+
+ status = omapi_get_value_str (ref, id, "algorithm", &algorithm);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (&name, MDL);
+ return status;
+ }
+
+ if ((algorithm -> value -> type != omapi_datatype_string) &&
+ (algorithm -> value -> type != omapi_datatype_data)) {
+ omapi_value_dereference (&name, MDL);
+ omapi_value_dereference (&algorithm, MDL);
+ return ISC_R_NOTFOUND;
+ }
+
+
+ if (!omapi_auth_key_hash_lookup ((omapi_auth_key_t **)h, auth_key_hash,
+ (const char *)
+ name -> value -> u.buffer.value,
+ name -> value -> u.buffer.len, MDL)) {
+ omapi_value_dereference (&name, MDL);
+ omapi_value_dereference (&algorithm, MDL);
+ return ISC_R_NOTFOUND;
+ }
+
+ if (omapi_td_strcasecmp (algorithm -> value,
+ ((omapi_auth_key_t *)*h) -> algorithm) != 0) {
+ omapi_value_dereference (&name, MDL);
+ omapi_value_dereference (&algorithm, MDL);
+ omapi_object_dereference (h, MDL);
+ return ISC_R_NOTFOUND;
+ }
+
+ omapi_value_dereference (&name, MDL);
+ omapi_value_dereference (&algorithm, MDL);
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_auth_key_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *h)
+{
+ omapi_auth_key_t *a;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_auth_key)
+ return DHCP_R_INVALIDARG;
+ a = (omapi_auth_key_t *)h;
+
+ /* Write only the name and algorithm -- not the secret! */
+ if (a -> name) {
+ status = omapi_connection_put_name (c, "name");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_string (c, a -> name);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+ if (a -> algorithm) {
+ status = omapi_connection_put_name (c, "algorithm");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_string (c, a -> algorithm);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_auth_key_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ omapi_auth_key_t *a;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_auth_key)
+ return ISC_R_UNEXPECTED;
+ a = (omapi_auth_key_t *)h;
+
+ if (omapi_ds_strcmp (name, "name") == 0) {
+ if (a -> name)
+ return omapi_make_string_value
+ (value, name, a -> name, MDL);
+ else
+ return ISC_R_NOTFOUND;
+ } else if (omapi_ds_strcmp (name, "key") == 0) {
+ if (a -> key) {
+ status = omapi_value_new (value, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference
+ (&(*value) -> name, name, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (value, MDL);
+ return status;
+ }
+
+ status = omapi_typed_data_new (MDL, &(*value) -> value,
+ omapi_datatype_data,
+ a -> key -> len);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (value, MDL);
+ return status;
+ }
+
+ memcpy ((*value) -> value -> u.buffer.value,
+ a -> key -> value, a -> key -> len);
+ return ISC_R_SUCCESS;
+ } else
+ return ISC_R_NOTFOUND;
+ } else if (omapi_ds_strcmp (name, "algorithm") == 0) {
+ if (a -> algorithm)
+ return omapi_make_string_value
+ (value, name, a -> algorithm, MDL);
+ else
+ return ISC_R_NOTFOUND;
+ }
+
+ return ISC_R_SUCCESS;
+}
diff --git a/omapip/buffer.c b/omapip/buffer.c
new file mode 100644
index 0000000..36bc8b9
--- /dev/null
+++ b/omapip/buffer.c
@@ -0,0 +1,716 @@
+/* buffer.c
+
+ Buffer access functions for the object management protocol... */
+
+/*
+ * Copyright (c) 2009,2012-2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+#include <errno.h>
+
+#if defined (TRACING)
+static void trace_connection_input_input (trace_type_t *, unsigned, char *);
+static void trace_connection_input_stop (trace_type_t *);
+static void trace_connection_output_input (trace_type_t *, unsigned, char *);
+static void trace_connection_output_stop (trace_type_t *);
+static trace_type_t *trace_connection_input;
+static trace_type_t *trace_connection_output;
+static isc_result_t omapi_connection_reader_trace (omapi_object_t *,
+ unsigned, char *,
+ unsigned *);
+extern omapi_array_t *omapi_connections;
+
+void omapi_buffer_trace_setup ()
+{
+ trace_connection_input =
+ trace_type_register ("connection-input",
+ (void *)0,
+ trace_connection_input_input,
+ trace_connection_input_stop, MDL);
+ trace_connection_output =
+ trace_type_register ("connection-output",
+ (void *)0,
+ trace_connection_output_input,
+ trace_connection_output_stop, MDL);
+}
+
+static void trace_connection_input_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ unsigned left, taken, cc = 0;
+ char *s;
+ int32_t connect_index;
+ isc_result_t status;
+ omapi_connection_object_t *c = (omapi_connection_object_t *)0;
+
+ memcpy (&connect_index, buf, sizeof connect_index);
+ connect_index = ntohl (connect_index);
+
+ omapi_array_foreach_begin (omapi_connections,
+ omapi_connection_object_t, lp) {
+ if (lp -> index == ntohl (connect_index)) {
+ omapi_connection_reference (&c, lp, MDL);
+ omapi_connection_dereference (&lp, MDL);
+ break;
+ }
+ } omapi_array_foreach_end (omapi_connections,
+ omapi_connection_object_t, lp);
+
+ if (!c) {
+ log_error ("trace connection input: no connection index %ld",
+ (long int)connect_index);
+ return;
+ }
+
+ s = buf + sizeof connect_index;
+ left = length - sizeof connect_index;
+
+ while (left) {
+ taken = 0;
+ status = omapi_connection_reader_trace ((omapi_object_t *)c,
+ left, s, &taken);
+ if (status != ISC_R_SUCCESS) {
+ log_error ("trace connection input: %s",
+ isc_result_totext (status));
+ break;
+ }
+ if (!taken) {
+ if (cc > 0) {
+ log_error ("trace connection_input: %s",
+ "input is not being consumed.");
+ break;
+ }
+ cc++;
+ } else {
+ cc = 0;
+ left -= taken;
+ }
+ }
+ omapi_connection_dereference (&c, MDL);
+}
+
+static void trace_connection_input_stop (trace_type_t *ttype) { }
+
+static void trace_connection_output_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ /* We *could* check to see if the output is correct, but for now
+ we aren't going to do that. */
+}
+
+static void trace_connection_output_stop (trace_type_t *ttype) { }
+
+#endif
+
+/* Make sure that at least len bytes are in the input buffer, and if not,
+ read enough bytes to make up the difference. */
+
+isc_result_t omapi_connection_reader (omapi_object_t *h)
+{
+#if defined (TRACING)
+ return omapi_connection_reader_trace (h, 0, (char *)0, (unsigned *)0);
+}
+
+static isc_result_t omapi_connection_reader_trace (omapi_object_t *h,
+ unsigned stuff_len,
+ char *stuff_buf,
+ unsigned *stuff_taken)
+{
+#endif
+ omapi_buffer_t *buffer;
+ isc_result_t status;
+ unsigned read_len;
+ int read_status;
+ omapi_connection_object_t *c;
+ unsigned bytes_to_read;
+
+ if (!h || h -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ /* See if there are enough bytes. */
+ if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
+ c -> in_bytes > c -> bytes_needed)
+ return ISC_R_SUCCESS;
+
+
+ if (c -> inbufs) {
+ for (buffer = c -> inbufs; buffer -> next;
+ buffer = buffer -> next)
+ ;
+ if (!BUFFER_BYTES_FREE (buffer)) {
+ status = omapi_buffer_new (&buffer -> next, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ buffer = buffer -> next;
+ }
+ } else {
+ status = omapi_buffer_new (&c -> inbufs, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ buffer = c -> inbufs;
+ }
+
+ bytes_to_read = BUFFER_BYTES_FREE (buffer);
+
+ while (bytes_to_read) {
+ if (buffer -> tail > buffer -> head)
+ read_len = sizeof (buffer -> buf) - buffer -> tail;
+ else
+ read_len = buffer -> head - buffer -> tail;
+
+#if defined (TRACING)
+ if (trace_playback()) {
+ if (stuff_len) {
+ if (read_len > stuff_len)
+ read_len = stuff_len;
+ if (stuff_taken)
+ *stuff_taken += read_len;
+ memcpy (&buffer -> buf [buffer -> tail],
+ stuff_buf, read_len);
+ stuff_len -= read_len;
+ stuff_buf += read_len;
+ read_status = read_len;
+ } else {
+ break;
+ }
+ } else
+#endif
+ {
+ read_status = read (c -> socket,
+ &buffer -> buf [buffer -> tail],
+ read_len);
+ }
+ if (read_status < 0) {
+ if (errno == EWOULDBLOCK)
+ break;
+ else if (errno == EIO)
+ return ISC_R_IOERROR;
+ else if (errno == EINVAL)
+ return DHCP_R_INVALIDARG;
+ else if (errno == ECONNRESET) {
+ omapi_disconnect (h, 1);
+ return ISC_R_SHUTTINGDOWN;
+ } else
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* If we got a zero-length read, as opposed to EWOULDBLOCK,
+ the remote end closed the connection. */
+ if (read_status == 0) {
+ omapi_disconnect (h, 0);
+ return ISC_R_SHUTTINGDOWN;
+ }
+#if defined (TRACING)
+ if (trace_record ()) {
+ trace_iov_t iov [2];
+ int32_t connect_index;
+
+ connect_index = htonl (c -> index);
+
+ iov [0].buf = (char *)&connect_index;
+ iov [0].len = sizeof connect_index;
+ iov [1].buf = &buffer -> buf [buffer -> tail];
+ iov [1].len = read_status;
+
+ status = (trace_write_packet_iov
+ (trace_connection_input, 2, iov, MDL));
+ if (status != ISC_R_SUCCESS) {
+ trace_stop ();
+ log_error ("trace connection input: %s",
+ isc_result_totext (status));
+ }
+ }
+#endif
+ buffer -> tail += read_status;
+ c -> in_bytes += read_status;
+ if (buffer -> tail == sizeof buffer -> buf)
+ buffer -> tail = 0;
+ if (read_status < read_len)
+ break;
+ bytes_to_read -= read_status;
+ }
+
+ if (c -> bytes_needed <= c -> in_bytes) {
+ omapi_signal (h, "ready", c);
+ }
+ return ISC_R_SUCCESS;
+}
+
+/* Put some bytes into the output buffer for a connection. */
+
+isc_result_t omapi_connection_copyin (omapi_object_t *h,
+ const unsigned char *bufp,
+ unsigned len)
+{
+ omapi_buffer_t *buffer;
+ isc_result_t status;
+ int bytes_copied = 0;
+ unsigned copy_len;
+ int sig_flags = SIG_MODE_UPDATE;
+ omapi_connection_object_t *c;
+
+ /* no need to verify len as it's unsigned */
+ if (!h || h -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ /* If the connection is closed, return an error if the caller
+ tries to copy in. */
+ if (c -> state == omapi_connection_disconnecting ||
+ c -> state == omapi_connection_closed)
+ return ISC_R_NOTCONNECTED;
+
+ if (c -> outbufs) {
+ for (buffer = c -> outbufs;
+ buffer -> next; buffer = buffer -> next)
+ ;
+ } else {
+ status = omapi_buffer_new (&c -> outbufs, MDL);
+ if (status != ISC_R_SUCCESS)
+ goto leave;
+ buffer = c -> outbufs;
+ }
+
+ while (bytes_copied < len) {
+ /* If there is no space available in this buffer,
+ allocate a new one. */
+ if (!BUFFER_BYTES_FREE (buffer)) {
+ status = (omapi_buffer_new (&buffer -> next, MDL));
+ if (status != ISC_R_SUCCESS)
+ goto leave;
+ buffer = buffer -> next;
+ }
+
+ if (buffer -> tail > buffer -> head)
+ copy_len = sizeof (buffer -> buf) - buffer -> tail;
+ else
+ copy_len = buffer -> head - buffer -> tail;
+
+ if (copy_len > (len - bytes_copied))
+ copy_len = len - bytes_copied;
+
+ if (c -> out_key) {
+ if (!c -> out_context)
+ sig_flags |= SIG_MODE_INIT;
+ status = omapi_connection_sign_data
+ (sig_flags, c -> out_key, &c -> out_context,
+ &bufp [bytes_copied], copy_len,
+ (omapi_typed_data_t **)0);
+ if (status != ISC_R_SUCCESS)
+ goto leave;
+ }
+
+ memcpy (&buffer -> buf [buffer -> tail],
+ &bufp [bytes_copied], copy_len);
+ buffer -> tail += copy_len;
+ c -> out_bytes += copy_len;
+ bytes_copied += copy_len;
+ if (buffer -> tail == sizeof buffer -> buf)
+ buffer -> tail = 0;
+ }
+
+ status = ISC_R_SUCCESS;
+
+ leave:
+ /*
+ * If we have any bytes to send and we have a proper io object
+ * inform the socket code that we would like to know when we
+ * can send more bytes.
+ */
+ if (c->out_bytes != 0) {
+ if ((c->outer != NULL) &&
+ (c->outer->type == omapi_type_io_object)) {
+ omapi_io_object_t *io = (omapi_io_object_t *)c->outer;
+ isc_socket_fdwatchpoke(io->fd,
+ ISC_SOCKFDWATCH_WRITE);
+ }
+ }
+
+ return (status);
+}
+
+/* Copy some bytes from the input buffer, and advance the input buffer
+ pointer beyond the bytes copied out. */
+
+isc_result_t omapi_connection_copyout (unsigned char *buf,
+ omapi_object_t *h,
+ unsigned size)
+{
+ unsigned bytes_remaining;
+ unsigned bytes_this_copy;
+ unsigned first_byte;
+ omapi_buffer_t *buffer;
+ unsigned char *bufp;
+ int sig_flags = SIG_MODE_UPDATE;
+ omapi_connection_object_t *c;
+ isc_result_t status;
+
+ if (!h || h -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ if (size > c -> in_bytes)
+ return ISC_R_NOMORE;
+ bufp = buf;
+ bytes_remaining = size;
+ buffer = c -> inbufs;
+
+ while (bytes_remaining) {
+ if (!buffer)
+ return ISC_R_UNEXPECTED;
+ if (BYTES_IN_BUFFER (buffer)) {
+ if (buffer -> head == (sizeof buffer -> buf) - 1)
+ first_byte = 0;
+ else
+ first_byte = buffer -> head + 1;
+
+ if (first_byte > buffer -> tail) {
+ bytes_this_copy = (sizeof buffer -> buf -
+ first_byte);
+ } else {
+ bytes_this_copy =
+ buffer -> tail - first_byte;
+ }
+ if (bytes_this_copy > bytes_remaining)
+ bytes_this_copy = bytes_remaining;
+ if (bufp) {
+ if (c -> in_key) {
+ if (!c -> in_context)
+ sig_flags |= SIG_MODE_INIT;
+ status = omapi_connection_sign_data
+ (sig_flags,
+ c -> in_key,
+ &c -> in_context,
+ (unsigned char *)
+ &buffer -> buf [first_byte],
+ bytes_this_copy,
+ (omapi_typed_data_t **)0);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ memcpy (bufp, &buffer -> buf [first_byte],
+ bytes_this_copy);
+ bufp += bytes_this_copy;
+ }
+ bytes_remaining -= bytes_this_copy;
+ buffer -> head = first_byte + bytes_this_copy - 1;
+ c -> in_bytes -= bytes_this_copy;
+ }
+
+ if (!BYTES_IN_BUFFER (buffer))
+ buffer = buffer -> next;
+ }
+
+ /* Get rid of any input buffers that we emptied. */
+ buffer = (omapi_buffer_t *)0;
+ while (c -> inbufs &&
+ !BYTES_IN_BUFFER (c -> inbufs)) {
+ if (c -> inbufs -> next) {
+ omapi_buffer_reference (&buffer,
+ c -> inbufs -> next, MDL);
+ omapi_buffer_dereference (&c -> inbufs -> next, MDL);
+ }
+ omapi_buffer_dereference (&c -> inbufs, MDL);
+ if (buffer) {
+ omapi_buffer_reference
+ (&c -> inbufs, buffer, MDL);
+ omapi_buffer_dereference (&buffer, MDL);
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_writer (omapi_object_t *h)
+{
+ unsigned bytes_this_write;
+ int bytes_written;
+ unsigned first_byte;
+ omapi_buffer_t *buffer;
+ omapi_connection_object_t *c;
+
+ if (!h || h -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ /* Already flushed... */
+ if (!c -> out_bytes)
+ return ISC_R_SUCCESS;
+
+ buffer = c -> outbufs;
+
+ while (c -> out_bytes) {
+ if (!buffer)
+ return ISC_R_UNEXPECTED;
+ if (BYTES_IN_BUFFER (buffer)) {
+ if (buffer -> head == (sizeof buffer -> buf) - 1)
+ first_byte = 0;
+ else
+ first_byte = buffer -> head + 1;
+
+ if (first_byte > buffer -> tail) {
+ bytes_this_write = (sizeof buffer -> buf -
+ first_byte);
+ } else {
+ bytes_this_write =
+ buffer -> tail - first_byte;
+ }
+ bytes_written = write (c -> socket,
+ &buffer -> buf [first_byte],
+ bytes_this_write);
+ /* If the write failed with EWOULDBLOCK or we wrote
+ zero bytes, a further write would block, so we have
+ flushed as much as we can for now. Other errors
+ are really errors. */
+ if (bytes_written < 0) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ return ISC_R_INPROGRESS;
+ else if (errno == EPIPE)
+ return ISC_R_NOCONN;
+#ifdef EDQUOT
+ else if (errno == EFBIG || errno == EDQUOT)
+#else
+ else if (errno == EFBIG)
+#endif
+ return ISC_R_NORESOURCES;
+ else if (errno == ENOSPC)
+ return ISC_R_NOSPACE;
+ else if (errno == EIO)
+ return ISC_R_IOERROR;
+ else if (errno == EINVAL)
+ return DHCP_R_INVALIDARG;
+ else if (errno == ECONNRESET)
+ return ISC_R_SHUTTINGDOWN;
+ else
+ return ISC_R_UNEXPECTED;
+ }
+ if (bytes_written == 0)
+ return ISC_R_INPROGRESS;
+
+#if defined (TRACING)
+ if (trace_record ()) {
+ isc_result_t status;
+ trace_iov_t iov [2];
+ int32_t connect_index;
+
+ connect_index = htonl (c -> index);
+
+ iov [0].buf = (char *)&connect_index;
+ iov [0].len = sizeof connect_index;
+ iov [1].buf = &buffer -> buf [buffer -> tail];
+ iov [1].len = bytes_written;
+
+ status = (trace_write_packet_iov
+ (trace_connection_input, 2, iov,
+ MDL));
+ if (status != ISC_R_SUCCESS) {
+ trace_stop ();
+ log_error ("trace %s output: %s",
+ "connection",
+ isc_result_totext (status));
+ }
+ }
+#endif
+
+ buffer -> head = first_byte + bytes_written - 1;
+ c -> out_bytes -= bytes_written;
+
+ /* If we didn't finish out the write, we filled the
+ O.S. output buffer and a further write would block,
+ so stop trying to flush now. */
+ if (bytes_written != bytes_this_write)
+ return ISC_R_INPROGRESS;
+ }
+
+ if (!BYTES_IN_BUFFER (buffer))
+ buffer = buffer -> next;
+ }
+
+ /* Get rid of any output buffers we emptied. */
+ buffer = (omapi_buffer_t *)0;
+ while (c -> outbufs &&
+ !BYTES_IN_BUFFER (c -> outbufs)) {
+ if (c -> outbufs -> next) {
+ omapi_buffer_reference (&buffer,
+ c -> outbufs -> next, MDL);
+ omapi_buffer_dereference (&c -> outbufs -> next, MDL);
+ }
+ omapi_buffer_dereference (&c -> outbufs, MDL);
+ if (buffer) {
+ omapi_buffer_reference (&c -> outbufs, buffer, MDL);
+ omapi_buffer_dereference (&buffer, MDL);
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_get_uint32 (omapi_object_t *c,
+ u_int32_t *result)
+{
+ u_int32_t inbuf;
+ isc_result_t status;
+
+ status = omapi_connection_copyout ((unsigned char *)&inbuf,
+ c, sizeof inbuf);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ *result = ntohl (inbuf);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_put_uint32 (omapi_object_t *c,
+ u_int32_t value)
+{
+ u_int32_t inbuf;
+
+ inbuf = htonl (value);
+
+ return omapi_connection_copyin (c, (unsigned char *)&inbuf,
+ sizeof inbuf);
+}
+
+isc_result_t omapi_connection_get_uint16 (omapi_object_t *c,
+ u_int16_t *result)
+{
+ u_int16_t inbuf;
+ isc_result_t status;
+
+ status = omapi_connection_copyout ((unsigned char *)&inbuf,
+ c, sizeof inbuf);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ *result = ntohs (inbuf);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_put_uint16 (omapi_object_t *c,
+ u_int32_t value)
+{
+ u_int16_t inbuf;
+
+ inbuf = htons (value);
+
+ return omapi_connection_copyin (c, (unsigned char *)&inbuf,
+ sizeof inbuf);
+}
+
+isc_result_t omapi_connection_write_typed_data (omapi_object_t *c,
+ omapi_typed_data_t *data)
+{
+ isc_result_t status;
+ omapi_handle_t handle;
+
+ /* Null data is valid. */
+ if (!data)
+ return omapi_connection_put_uint32 (c, 0);
+
+ switch (data -> type) {
+ case omapi_datatype_int:
+ status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ return omapi_connection_put_uint32 (c, ((u_int32_t)
+ (data -> u.integer)));
+
+ case omapi_datatype_string:
+ case omapi_datatype_data:
+ status = omapi_connection_put_uint32 (c, data -> u.buffer.len);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ if (data -> u.buffer.len)
+ return omapi_connection_copyin
+ (c, data -> u.buffer.value,
+ data -> u.buffer.len);
+ return ISC_R_SUCCESS;
+
+ case omapi_datatype_object:
+ if (data -> u.object) {
+ status = omapi_object_handle (&handle,
+ data -> u.object);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ } else
+ handle = 0;
+ status = omapi_connection_put_uint32 (c, sizeof handle);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ return omapi_connection_put_uint32 (c, handle);
+
+ }
+ return DHCP_R_INVALIDARG;
+}
+
+isc_result_t omapi_connection_put_name (omapi_object_t *c, const char *name)
+{
+ isc_result_t status;
+ unsigned len = strlen (name);
+
+ status = omapi_connection_put_uint16 (c, len);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ return omapi_connection_copyin (c, (const unsigned char *)name, len);
+}
+
+isc_result_t omapi_connection_put_string (omapi_object_t *c,
+ const char *string)
+{
+ isc_result_t status;
+ unsigned len;
+
+ if (string)
+ len = strlen (string);
+ else
+ len = 0;
+
+ status = omapi_connection_put_uint32 (c, len);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ if (len)
+ return omapi_connection_copyin
+ (c, (const unsigned char *)string, len);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h)
+{
+ isc_result_t status;
+ omapi_handle_t handle;
+
+ if (h) {
+ status = omapi_object_handle (&handle, h);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ } else
+ handle = 0; /* The null handle. */
+ status = omapi_connection_put_uint32 (c, sizeof handle);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ return omapi_connection_put_uint32 (c, handle);
+}
diff --git a/omapip/connection.c b/omapip/connection.c
new file mode 100644
index 0000000..58b08c6
--- /dev/null
+++ b/omapip/connection.c
@@ -0,0 +1,1104 @@
+/* connection.c
+
+ Subroutines for dealing with connections. */
+
+/*
+ * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <errno.h>
+
+#if defined (TRACING)
+static void trace_connect_input (trace_type_t *, unsigned, char *);
+static void trace_connect_stop (trace_type_t *);
+static void trace_disconnect_input (trace_type_t *, unsigned, char *);
+static void trace_disconnect_stop (trace_type_t *);
+trace_type_t *trace_connect;
+trace_type_t *trace_disconnect;
+extern omapi_array_t *trace_listeners;
+#endif
+static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
+
+OMAPI_OBJECT_ALLOC (omapi_connection,
+ omapi_connection_object_t, omapi_type_connection)
+
+isc_result_t omapi_connect (omapi_object_t *c,
+ const char *server_name,
+ unsigned port)
+{
+ struct hostent *he;
+ unsigned i, hix;
+ omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;
+ struct in_addr foo;
+ isc_result_t status;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_connect(%s, port=%d)", server_name, port);
+#endif
+
+ if (!inet_aton (server_name, &foo)) {
+ /* If we didn't get a numeric address, try for a domain
+ name. It's okay for this call to block. */
+ he = gethostbyname (server_name);
+ if (!he)
+ return DHCP_R_HOSTUNKNOWN;
+ for (i = 0; he -> h_addr_list [i]; i++)
+ ;
+ if (i == 0)
+ return DHCP_R_HOSTUNKNOWN;
+ hix = i;
+
+ status = omapi_addr_list_new (&addrs, hix, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ for (i = 0; i < hix; i++) {
+ addrs -> addresses [i].addrtype = he -> h_addrtype;
+ addrs -> addresses [i].addrlen = he -> h_length;
+ memcpy (addrs -> addresses [i].address,
+ he -> h_addr_list [i],
+ (unsigned)he -> h_length);
+ addrs -> addresses [i].port = port;
+ }
+ } else {
+ status = omapi_addr_list_new (&addrs, 1, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ addrs -> addresses [0].addrtype = AF_INET;
+ addrs -> addresses [0].addrlen = sizeof foo;
+ memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
+ addrs -> addresses [0].port = port;
+ }
+ status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
+ omapi_addr_list_dereference (&addrs, MDL);
+ return status;
+}
+
+isc_result_t omapi_connect_list (omapi_object_t *c,
+ omapi_addr_list_t *remote_addrs,
+ omapi_addr_t *local_addr)
+{
+ isc_result_t status;
+ omapi_connection_object_t *obj;
+ int flag;
+ struct sockaddr_in local_sin;
+
+ obj = (omapi_connection_object_t *)0;
+ status = omapi_connection_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
+ MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_connection_dereference (&obj, MDL);
+ return status;
+ }
+ status = omapi_object_reference (&obj -> inner, c, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_connection_dereference (&obj, MDL);
+ return status;
+ }
+
+ /* Store the address list on the object. */
+ omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
+ obj -> cptr = 0;
+ obj -> state = omapi_connection_unconnected;
+
+#if defined (TRACING)
+ /* If we're playing back, don't actually try to connect - just leave
+ the object available for a subsequent connect or disconnect. */
+ if (!trace_playback ()) {
+#endif
+ /* Create a socket on which to communicate. */
+ obj -> socket =
+ socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (obj -> socket < 0) {
+ omapi_connection_dereference (&obj, MDL);
+ if (errno == EMFILE || errno == ENFILE
+ || errno == ENOBUFS)
+ return ISC_R_NORESOURCES;
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* Set up the local address, if any. */
+ if (local_addr) {
+ /* Only do TCPv4 so far. */
+ if (local_addr -> addrtype != AF_INET) {
+ omapi_connection_dereference (&obj, MDL);
+ return DHCP_R_INVALIDARG;
+ }
+ local_sin.sin_port = htons (local_addr -> port);
+ memcpy (&local_sin.sin_addr,
+ local_addr -> address,
+ local_addr -> addrlen);
+#if defined (HAVE_SA_LEN)
+ local_sin.sin_len = sizeof local_addr;
+#endif
+ local_sin.sin_family = AF_INET;
+ memset (&local_sin.sin_zero, 0,
+ sizeof local_sin.sin_zero);
+
+ if (bind (obj -> socket, (struct sockaddr *)&local_sin,
+ sizeof local_sin) < 0) {
+ omapi_connection_object_t **objp = &obj;
+ omapi_object_t **o = (omapi_object_t **)objp;
+ omapi_object_dereference(o, MDL);
+ if (errno == EADDRINUSE)
+ return ISC_R_ADDRINUSE;
+ if (errno == EADDRNOTAVAIL)
+ return ISC_R_ADDRNOTAVAIL;
+ if (errno == EACCES)
+ return ISC_R_NOPERM;
+ return ISC_R_UNEXPECTED;
+ }
+ obj -> local_addr = local_sin;
+ }
+
+#if defined(F_SETFD)
+ if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
+ close (obj -> socket);
+ omapi_connection_dereference (&obj, MDL);
+ return ISC_R_UNEXPECTED;
+ }
+#endif
+
+ /* Set the SO_REUSEADDR flag (this should not fail). */
+ flag = 1;
+ if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&flag, sizeof flag) < 0) {
+ omapi_connection_dereference (&obj, MDL);
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* Set the file to nonblocking mode. */
+ if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
+ omapi_connection_dereference (&obj, MDL);
+ return ISC_R_UNEXPECTED;
+ }
+
+#ifdef SO_NOSIGPIPE
+ /*
+ * If available stop the OS from killing our
+ * program on a SIGPIPE failure
+ */
+ flag = 1;
+ if (setsockopt(obj->socket, SOL_SOCKET, SO_NOSIGPIPE,
+ (char *)&flag, sizeof(flag)) < 0) {
+ omapi_connection_dereference (&obj, MDL);
+ return ISC_R_UNEXPECTED;
+ }
+#endif
+
+ status = (omapi_register_io_object
+ ((omapi_object_t *)obj,
+ 0, omapi_connection_writefd,
+ 0, omapi_connection_connect,
+ omapi_connection_reaper));
+ if (status != ISC_R_SUCCESS)
+ goto out;
+ status = omapi_connection_connect_internal ((omapi_object_t *)
+ obj);
+ /*
+ * inprogress is the same as success but used
+ * to indicate to the dispatch code that we should
+ * mark the socket as requiring more attention.
+ * Routines calling this function should handle
+ * success properly.
+ */
+ if (status == ISC_R_INPROGRESS) {
+ status = ISC_R_SUCCESS;
+ }
+#if defined (TRACING)
+ }
+ omapi_connection_register (obj, MDL);
+#endif
+
+ out:
+ omapi_connection_dereference (&obj, MDL);
+ return status;
+}
+
+#if defined (TRACING)
+omapi_array_t *omapi_connections;
+
+OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t)
+
+void omapi_connection_trace_setup (void) {
+ trace_connect = trace_type_register ("connect", (void *)0,
+ trace_connect_input,
+ trace_connect_stop, MDL);
+ trace_disconnect = trace_type_register ("disconnect", (void *)0,
+ trace_disconnect_input,
+ trace_disconnect_stop, MDL);
+}
+
+void omapi_connection_register (omapi_connection_object_t *obj,
+ const char *file, int line)
+{
+ isc_result_t status;
+ trace_iov_t iov [6];
+ int iov_count = 0;
+ int32_t connect_index, listener_index;
+ static int32_t index;
+
+ if (!omapi_connections) {
+ status = omapi_connection_array_allocate (&omapi_connections,
+ file, line);
+ if (status != ISC_R_SUCCESS)
+ return;
+ }
+
+ status = omapi_connection_array_extend (omapi_connections, obj,
+ (int *)0, file, line);
+ if (status != ISC_R_SUCCESS) {
+ obj -> index = -1;
+ return;
+ }
+
+#if defined (TRACING)
+ if (trace_record ()) {
+ /* Connection registration packet:
+
+ int32_t index
+ int32_t listener_index [-1 means no listener]
+ u_int16_t remote_port
+ u_int16_t local_port
+ u_int32_t remote_addr
+ u_int32_t local_addr */
+
+ connect_index = htonl (index);
+ index++;
+ if (obj -> listener)
+ listener_index = htonl (obj -> listener -> index);
+ else
+ listener_index = htonl (-1);
+ iov [iov_count].buf = (char *)&connect_index;
+ iov [iov_count++].len = sizeof connect_index;
+ iov [iov_count].buf = (char *)&listener_index;
+ iov [iov_count++].len = sizeof listener_index;
+ iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port;
+ iov [iov_count++].len = sizeof obj -> remote_addr.sin_port;
+ iov [iov_count].buf = (char *)&obj -> local_addr.sin_port;
+ iov [iov_count++].len = sizeof obj -> local_addr.sin_port;
+ iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr;
+ iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr;
+ iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr;
+ iov [iov_count++].len = sizeof obj -> local_addr.sin_addr;
+
+ status = trace_write_packet_iov (trace_connect,
+ iov_count, iov, file, line);
+ }
+#endif
+}
+
+static void trace_connect_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ struct sockaddr_in remote, local;
+ int32_t connect_index, listener_index;
+ char *s = buf;
+ omapi_connection_object_t *obj;
+ isc_result_t status;
+ int i;
+
+ if (length != ((sizeof connect_index) +
+ (sizeof remote.sin_port) +
+ (sizeof remote.sin_addr)) * 2) {
+ log_error ("Trace connect: invalid length %d", length);
+ return;
+ }
+
+ memset (&remote, 0, sizeof remote);
+ memset (&local, 0, sizeof local);
+ memcpy (&connect_index, s, sizeof connect_index);
+ s += sizeof connect_index;
+ memcpy (&listener_index, s, sizeof listener_index);
+ s += sizeof listener_index;
+ memcpy (&remote.sin_port, s, sizeof remote.sin_port);
+ s += sizeof remote.sin_port;
+ memcpy (&local.sin_port, s, sizeof local.sin_port);
+ s += sizeof local.sin_port;
+ memcpy (&remote.sin_addr, s, sizeof remote.sin_addr);
+ s += sizeof remote.sin_addr;
+ memcpy (&local.sin_addr, s, sizeof local.sin_addr);
+ s += sizeof local.sin_addr;
+ POST(s);
+
+ connect_index = ntohl (connect_index);
+ listener_index = ntohl (listener_index);
+
+ /* If this was a connect to a listener, then we just slap together
+ a new connection. */
+ if (listener_index != -1) {
+ omapi_listener_object_t *listener;
+ listener = (omapi_listener_object_t *)0;
+ omapi_array_foreach_begin (trace_listeners,
+ omapi_listener_object_t, lp) {
+ if (lp -> address.sin_port == local.sin_port) {
+ omapi_listener_reference (&listener, lp, MDL);
+ omapi_listener_dereference (&lp, MDL);
+ break;
+ }
+ } omapi_array_foreach_end (trace_listeners,
+ omapi_listener_object_t, lp);
+ if (!listener) {
+ log_error ("%s%ld, addr %s, port %d",
+ "Spurious traced listener connect - index ",
+ (long int)listener_index,
+ inet_ntoa (local.sin_addr),
+ ntohs (local.sin_port));
+ return;
+ }
+ obj = (omapi_connection_object_t *)0;
+ status = omapi_listener_connect (&obj, listener, -1, &remote);
+ if (status != ISC_R_SUCCESS) {
+ log_error ("traced listener connect: %s",
+ isc_result_totext (status));
+ }
+ if (obj)
+ omapi_connection_dereference (&obj, MDL);
+ omapi_listener_dereference (&listener, MDL);
+ return;
+ }
+
+ /* Find the matching connect object, if there is one. */
+ omapi_array_foreach_begin (omapi_connections,
+ omapi_connection_object_t, lp) {
+ for (i = 0; (lp->connect_list &&
+ i < lp->connect_list->count); i++) {
+ if (!memcmp (&remote.sin_addr,
+ &lp->connect_list->addresses[i].address,
+ sizeof remote.sin_addr) &&
+ (ntohs (remote.sin_port) ==
+ lp->connect_list->addresses[i].port)) {
+ lp->state = omapi_connection_connected;
+ lp->remote_addr = remote;
+ lp->remote_addr.sin_family = AF_INET;
+ omapi_addr_list_dereference(&lp->connect_list, MDL);
+ lp->index = connect_index;
+ status = omapi_signal_in((omapi_object_t *)lp,
+ "connect");
+ omapi_connection_dereference (&lp, MDL);
+ return;
+ }
+ }
+ } omapi_array_foreach_end (omapi_connections,
+ omapi_connection_object_t, lp);
+
+ log_error ("Spurious traced connect - index %ld, addr %s, port %d",
+ (long int)connect_index, inet_ntoa (remote.sin_addr),
+ ntohs (remote.sin_port));
+ return;
+}
+
+static void trace_connect_stop (trace_type_t *ttype) { }
+
+static void trace_disconnect_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ int32_t *index;
+ if (length != sizeof *index) {
+ log_error ("trace disconnect: wrong length %d", length);
+ return;
+ }
+
+ index = (int32_t *)buf;
+
+ omapi_array_foreach_begin (omapi_connections,
+ omapi_connection_object_t, lp) {
+ if (lp -> index == ntohl (*index)) {
+ omapi_disconnect ((omapi_object_t *)lp, 1);
+ omapi_connection_dereference (&lp, MDL);
+ return;
+ }
+ } omapi_array_foreach_end (omapi_connections,
+ omapi_connection_object_t, lp);
+
+ log_error ("trace disconnect: no connection matching index %ld",
+ (long int)ntohl (*index));
+}
+
+static void trace_disconnect_stop (trace_type_t *ttype) { }
+#endif
+
+/* Disconnect a connection object from the remote end. If force is nonzero,
+ close the connection immediately. Otherwise, shut down the receiving end
+ but allow any unsent data to be sent before actually closing the socket. */
+
+isc_result_t omapi_disconnect (omapi_object_t *h,
+ int force)
+{
+ omapi_connection_object_t *c;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_disconnect(%s)", force ? "force" : "");
+#endif
+
+ c = (omapi_connection_object_t *)h;
+ if (c -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+
+#if defined (TRACING)
+ if (trace_record ()) {
+ isc_result_t status;
+ int32_t index;
+
+ index = htonl (c -> index);
+ status = trace_write_packet (trace_disconnect,
+ sizeof index, (char *)&index,
+ MDL);
+ if (status != ISC_R_SUCCESS) {
+ trace_stop ();
+ log_error ("trace_write_packet: %s",
+ isc_result_totext (status));
+ }
+ }
+ if (!trace_playback ()) {
+#endif
+ if (!force) {
+ /* If we're already disconnecting, we don't have to do
+ anything. */
+ if (c -> state == omapi_connection_disconnecting)
+ return ISC_R_SUCCESS;
+
+ /* Try to shut down the socket - this sends a FIN to
+ the remote end, so that it won't send us any more
+ data. If the shutdown succeeds, and we still
+ have bytes left to write, defer closing the socket
+ until that's done. */
+ if (!shutdown (c -> socket, SHUT_RD)) {
+ if (c -> out_bytes > 0) {
+ c -> state =
+ omapi_connection_disconnecting;
+ return ISC_R_SUCCESS;
+ }
+ }
+ }
+ close (c -> socket);
+#if defined (TRACING)
+ }
+#endif
+ c -> state = omapi_connection_closed;
+
+#if 0
+ /*
+ * Disconnecting from the I/O object seems incorrect as it doesn't
+ * cause the I/O object to be cleaned and released. Previous to
+ * using the isc socket library this wouldn't have caused a problem
+ * with the socket library we would have a reference to a closed
+ * socket. Instead we now do an unregister to properly free the
+ * I/O object.
+ */
+
+ /* Disconnect from I/O object, if any. */
+ if (h -> outer) {
+ if (h -> outer -> inner)
+ omapi_object_dereference (&h -> outer -> inner, MDL);
+ omapi_object_dereference (&h -> outer, MDL);
+ }
+#else
+ if (h->outer) {
+ omapi_unregister_io_object(h);
+ }
+#endif
+
+ /* If whatever created us registered a signal handler, send it
+ a disconnect signal. */
+ omapi_signal (h, "disconnect", h);
+
+ /* Disconnect from protocol object, if any. */
+ if (h->inner != NULL) {
+ if (h->inner->outer != NULL) {
+ omapi_object_dereference(&h->inner->outer, MDL);
+ }
+ omapi_object_dereference(&h->inner, MDL);
+ }
+
+ /* XXX: the code to free buffers should be in the dereference
+ function, but there is no special-purpose function to
+ dereference connections, so these just get leaked */
+ /* Free any buffers */
+ if (c->inbufs != NULL) {
+ omapi_buffer_dereference(&c->inbufs, MDL);
+ }
+ c->in_bytes = 0;
+ if (c->outbufs != NULL) {
+ omapi_buffer_dereference(&c->outbufs, MDL);
+ }
+ c->out_bytes = 0;
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes)
+{
+ omapi_connection_object_t *c;
+
+ if (h -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ c -> bytes_needed = bytes;
+ if (c -> bytes_needed <= c -> in_bytes) {
+ return ISC_R_SUCCESS;
+ }
+ return DHCP_R_NOTYET;
+}
+
+/* Return the socket on which the dispatcher should wait for readiness
+ to read, for a connection object. */
+int omapi_connection_readfd (omapi_object_t *h)
+{
+ omapi_connection_object_t *c;
+ if (h -> type != omapi_type_connection)
+ return -1;
+ c = (omapi_connection_object_t *)h;
+ if (c -> state != omapi_connection_connected)
+ return -1;
+ return c -> socket;
+}
+
+/*
+ * Return the socket on which the dispatcher should wait for readiness
+ * to write, for a connection object. When bytes are buffered we should
+ * also poke the dispatcher to tell it to start or re-start watching the
+ * socket.
+ */
+int omapi_connection_writefd (omapi_object_t *h)
+{
+ omapi_connection_object_t *c;
+ if (h -> type != omapi_type_connection)
+ return -1;
+ c = (omapi_connection_object_t *)h;
+ return c->socket;
+}
+
+isc_result_t omapi_connection_connect (omapi_object_t *h)
+{
+ isc_result_t status;
+
+ /*
+ * We use the INPROGRESS status to indicate that
+ * we want more from the socket. In this case we
+ * have now connected and are trying to write to
+ * the socket for the first time. For the signaling
+ * code this is the same as a SUCCESS so we don't
+ * pass it on as a signal.
+ */
+ status = omapi_connection_connect_internal (h);
+ if (status == ISC_R_INPROGRESS)
+ return ISC_R_INPROGRESS;
+
+ if (status != ISC_R_SUCCESS)
+ omapi_signal (h, "status", status);
+
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t omapi_connection_connect_internal (omapi_object_t *h)
+{
+ int error = 0;
+ omapi_connection_object_t *c;
+ socklen_t sl;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ if (c -> state == omapi_connection_connecting) {
+ sl = sizeof error;
+ if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
+ (char *)&error, &sl) < 0) {
+ omapi_disconnect (h, 1);
+ return ISC_R_SUCCESS;
+ }
+ if (!error)
+ c -> state = omapi_connection_connected;
+ }
+ if (c -> state == omapi_connection_connecting ||
+ c -> state == omapi_connection_unconnected) {
+ if (c -> cptr >= c -> connect_list -> count) {
+ switch (error) {
+ case ECONNREFUSED:
+ status = ISC_R_CONNREFUSED;
+ break;
+ case ENETUNREACH:
+ status = ISC_R_NETUNREACH;
+ break;
+ default:
+ status = uerr2isc (error);
+ break;
+ }
+ omapi_disconnect (h, 1);
+ return status;
+ }
+
+ if (c -> connect_list -> addresses [c -> cptr].addrtype !=
+ AF_INET) {
+ omapi_disconnect (h, 1);
+ return DHCP_R_INVALIDARG;
+ }
+
+ memcpy (&c -> remote_addr.sin_addr,
+ &c -> connect_list -> addresses [c -> cptr].address,
+ sizeof c -> remote_addr.sin_addr);
+ c -> remote_addr.sin_family = AF_INET;
+ c -> remote_addr.sin_port =
+ htons (c -> connect_list -> addresses [c -> cptr].port);
+#if defined (HAVE_SA_LEN)
+ c -> remote_addr.sin_len = sizeof c -> remote_addr;
+#endif
+ memset (&c -> remote_addr.sin_zero, 0,
+ sizeof c -> remote_addr.sin_zero);
+ ++c -> cptr;
+
+ error = connect (c -> socket,
+ (struct sockaddr *)&c -> remote_addr,
+ sizeof c -> remote_addr);
+ if (error < 0) {
+ error = errno;
+ if (error != EINPROGRESS) {
+ omapi_disconnect (h, 1);
+ switch (error) {
+ case ECONNREFUSED:
+ status = ISC_R_CONNREFUSED;
+ break;
+ case ENETUNREACH:
+ status = ISC_R_NETUNREACH;
+ break;
+ default:
+ status = uerr2isc (error);
+ break;
+ }
+ return status;
+ }
+ c -> state = omapi_connection_connecting;
+ return DHCP_R_INCOMPLETE;
+ }
+ c -> state = omapi_connection_connected;
+ }
+
+ /* I don't know why this would fail, so I'm tempted not to test
+ the return value. */
+ sl = sizeof (c -> local_addr);
+ if (getsockname (c -> socket,
+ (struct sockaddr *)&c -> local_addr, &sl) < 0) {
+ }
+
+ /* Reregister with the I/O object. If we don't already have an
+ I/O object this turns into a register call, otherwise we simply
+ modify the pointers in the I/O object. */
+
+ status = omapi_reregister_io_object (h,
+ omapi_connection_readfd,
+ omapi_connection_writefd,
+ omapi_connection_reader,
+ omapi_connection_writer,
+ omapi_connection_reaper);
+
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (h, 1);
+ return status;
+ }
+
+ omapi_signal_in (h, "connect");
+ omapi_addr_list_dereference (&c -> connect_list, MDL);
+ return ISC_R_INPROGRESS;
+}
+
+/* Reaper function for connection - if the connection is completely closed,
+ reap it. If it's in the disconnecting state, there were bytes left
+ to write when the user closed it, so if there are now no bytes left to
+ write, we can close it. */
+isc_result_t omapi_connection_reaper (omapi_object_t *h)
+{
+ omapi_connection_object_t *c;
+
+ if (h -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+
+ c = (omapi_connection_object_t *)h;
+ if (c -> state == omapi_connection_disconnecting &&
+ c -> out_bytes == 0) {
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_connection_reaper(): disconnect");
+#endif
+ omapi_disconnect (h, 1);
+ }
+ if (c -> state == omapi_connection_closed) {
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_connection_reaper(): closed");
+#endif
+ return ISC_R_NOTCONNECTED;
+ }
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t make_dst_key (dst_key_t **dst_key, omapi_object_t *a) {
+ omapi_value_t *name = (omapi_value_t *)0;
+ omapi_value_t *algorithm = (omapi_value_t *)0;
+ omapi_value_t *key = (omapi_value_t *)0;
+ char *name_str = NULL;
+ isc_result_t status = ISC_R_SUCCESS;
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_get_value_str
+ (a, (omapi_object_t *)0, "name", &name);
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_get_value_str
+ (a, (omapi_object_t *)0, "algorithm", &algorithm);
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_get_value_str
+ (a, (omapi_object_t *)0, "key", &key);
+
+ if (status == ISC_R_SUCCESS) {
+ if ((algorithm->value->type != omapi_datatype_data &&
+ algorithm->value->type != omapi_datatype_string) ||
+ strncasecmp((char *)algorithm->value->u.buffer.value,
+ NS_TSIG_ALG_HMAC_MD5 ".",
+ algorithm->value->u.buffer.len) != 0) {
+ status = DHCP_R_INVALIDARG;
+ }
+ }
+
+ if (status == ISC_R_SUCCESS) {
+ name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL);
+ if (!name_str)
+ status = ISC_R_NOMEMORY;
+ }
+
+ if (status == ISC_R_SUCCESS) {
+ memcpy (name_str,
+ name -> value -> u.buffer.value,
+ name -> value -> u.buffer.len);
+ name_str [name -> value -> u.buffer.len] = 0;
+
+ status = isclib_make_dst_key(name_str,
+ DHCP_HMAC_MD5_NAME,
+ key->value->u.buffer.value,
+ key->value->u.buffer.len,
+ dst_key);
+
+ if (*dst_key == NULL)
+ status = ISC_R_NOMEMORY;
+ }
+
+ if (name_str)
+ dfree (name_str, MDL);
+ if (key)
+ omapi_value_dereference (&key, MDL);
+ if (algorithm)
+ omapi_value_dereference (&algorithm, MDL);
+ if (name)
+ omapi_value_dereference (&name, MDL);
+
+ return status;
+}
+
+isc_result_t omapi_connection_sign_data (int mode,
+ dst_key_t *key,
+ void **context,
+ const unsigned char *data,
+ const unsigned len,
+ omapi_typed_data_t **result)
+{
+ omapi_typed_data_t *td = (omapi_typed_data_t *)0;
+ isc_result_t status;
+ dst_context_t **dctx = (dst_context_t **)context;
+
+ /* Create the context for the dst module */
+ if (mode & SIG_MODE_INIT) {
+ status = dst_context_create(key, dhcp_gbl_ctx.mctx, dctx);
+ if (status != ISC_R_SUCCESS) {
+ return status;
+ }
+ }
+
+ /* If we have any data add it to the context */
+ if (len != 0) {
+ isc_region_t region;
+ region.base = (unsigned char *)data;
+ region.length = len;
+ dst_context_adddata(*dctx, &region);
+ }
+
+ /* Finish the signature and clean up the context */
+ if (mode & SIG_MODE_FINAL) {
+ unsigned int sigsize;
+ isc_buffer_t sigbuf;
+
+ status = dst_key_sigsize(key, &sigsize);
+ if (status != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
+
+ status = omapi_typed_data_new (MDL, &td,
+ omapi_datatype_data,
+ sigsize);
+ if (status != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
+
+ isc_buffer_init(&sigbuf, td->u.buffer.value, td->u.buffer.len);
+ status = dst_context_sign(*dctx, &sigbuf);
+ if (status != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
+
+ if (result) {
+ omapi_typed_data_reference (result, td, MDL);
+ }
+
+ cleanup:
+ /* We are done with the context and the td. On success
+ * the td is now referenced from result, on failure we
+ * don't need it any more */
+ if (td) {
+ omapi_typed_data_dereference (&td, MDL);
+ }
+ dst_context_destroy(dctx);
+ return status;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_output_auth_length (omapi_object_t *h,
+ unsigned *l)
+{
+ omapi_connection_object_t *c;
+
+ if (h->type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ if (c->out_key == NULL)
+ return ISC_R_NOTFOUND;
+
+ return(dst_key_sigsize(c->out_key, l));
+}
+
+isc_result_t omapi_connection_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ omapi_connection_object_t *c;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ if (omapi_ds_strcmp (name, "input-authenticator") == 0) {
+ if (value && value -> type != omapi_datatype_object)
+ return DHCP_R_INVALIDARG;
+
+ if (c -> in_context) {
+ omapi_connection_sign_data (SIG_MODE_FINAL,
+ c -> in_key,
+ &c -> in_context,
+ 0, 0,
+ (omapi_typed_data_t **) 0);
+ }
+
+ if (c->in_key != NULL) {
+ dst_key_free(&c->in_key);
+ }
+
+ if (value) {
+ status = make_dst_key (&c -> in_key,
+ value -> u.object);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ return ISC_R_SUCCESS;
+ }
+ else if (omapi_ds_strcmp (name, "output-authenticator") == 0) {
+ if (value && value -> type != omapi_datatype_object)
+ return DHCP_R_INVALIDARG;
+
+ if (c -> out_context) {
+ omapi_connection_sign_data (SIG_MODE_FINAL,
+ c -> out_key,
+ &c -> out_context,
+ 0, 0,
+ (omapi_typed_data_t **) 0);
+ }
+
+ if (c->out_key != NULL) {
+ dst_key_free(&c->out_key);
+ }
+
+ if (value) {
+ status = make_dst_key (&c -> out_key,
+ value -> u.object);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ return ISC_R_SUCCESS;
+ }
+
+ if (h -> inner && h -> inner -> type -> set_value)
+ return (*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_connection_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ omapi_connection_object_t *c;
+ omapi_typed_data_t *td = (omapi_typed_data_t *)0;
+ isc_result_t status;
+ unsigned int sigsize;
+
+ if (h -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ if (omapi_ds_strcmp (name, "input-signature") == 0) {
+ if (!c -> in_key || !c -> in_context)
+ return ISC_R_NOTFOUND;
+
+ status = omapi_connection_sign_data (SIG_MODE_FINAL,
+ c -> in_key,
+ &c -> in_context,
+ 0, 0, &td);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_make_value (value, name, td, MDL);
+ omapi_typed_data_dereference (&td, MDL);
+ return status;
+
+ } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) {
+ if (c->in_key == NULL)
+ return ISC_R_NOTFOUND;
+
+ status = dst_key_sigsize(c->in_key, &sigsize);
+ if (status != ISC_R_SUCCESS) {
+ return(status);
+ }
+
+ return omapi_make_int_value(value, name, sigsize, MDL);
+
+ } else if (omapi_ds_strcmp (name, "output-signature") == 0) {
+ if (!c -> out_key || !c -> out_context)
+ return ISC_R_NOTFOUND;
+
+ status = omapi_connection_sign_data (SIG_MODE_FINAL,
+ c -> out_key,
+ &c -> out_context,
+ 0, 0, &td);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_make_value (value, name, td, MDL);
+ omapi_typed_data_dereference (&td, MDL);
+ return status;
+
+ } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) {
+ if (c->out_key == NULL)
+ return ISC_R_NOTFOUND;
+
+
+ status = dst_key_sigsize(c->out_key, &sigsize);
+ if (status != ISC_R_SUCCESS) {
+ return(status);
+ }
+
+ return omapi_make_int_value(value, name, sigsize, MDL);
+ }
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_connection_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_connection_object_t *c;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_connection_destroy()");
+#endif
+
+ if (h -> type != omapi_type_connection)
+ return ISC_R_UNEXPECTED;
+ c = (omapi_connection_object_t *)(h);
+ if (c -> state == omapi_connection_connected)
+ omapi_disconnect (h, 1);
+ if (c -> listener)
+ omapi_listener_dereference (&c -> listener, file, line);
+ if (c -> connect_list)
+ omapi_addr_list_dereference (&c -> connect_list, file, line);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ if (h -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_connection_signal_handler(%s)", name);
+#endif
+
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_connection_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *m)
+{
+ if (m -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+
+ if (m -> inner && m -> inner -> type -> stuff_values)
+ return (*(m -> inner -> type -> stuff_values)) (c, id,
+ m -> inner);
+ return ISC_R_SUCCESS;
+}
diff --git a/omapip/convert.c b/omapip/convert.c
new file mode 100644
index 0000000..3482a9a
--- /dev/null
+++ b/omapip/convert.c
@@ -0,0 +1,179 @@
+/* convert.c
+
+ Safe copying of option values into and out of the option buffer, which
+ can't be assumed to be aligned. */
+
+/*
+ * Copyright (c) 2004,2007,2009,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+
+u_int32_t getULong (buf)
+ const unsigned char *buf;
+{
+ u_int32_t ibuf;
+
+ memcpy (&ibuf, buf, sizeof (u_int32_t));
+ return ntohl (ibuf);
+}
+
+int32_t getLong (buf)
+ const unsigned char *buf;
+{
+ int32_t ibuf;
+
+ memcpy (&ibuf, buf, sizeof (int32_t));
+ return ntohl (ibuf);
+}
+
+u_int32_t getUShort (buf)
+ const unsigned char *buf;
+{
+ unsigned short ibuf;
+
+ memcpy (&ibuf, buf, sizeof (u_int16_t));
+ return ntohs (ibuf);
+}
+
+int32_t getShort (buf)
+ const unsigned char *buf;
+{
+ short ibuf;
+
+ memcpy (&ibuf, buf, sizeof (int16_t));
+ return ntohs (ibuf);
+}
+
+void putULong (obuf, val)
+ unsigned char *obuf;
+ u_int32_t val;
+{
+ u_int32_t tmp = htonl (val);
+ memcpy (obuf, &tmp, sizeof tmp);
+}
+
+void putLong (obuf, val)
+ unsigned char *obuf;
+ int32_t val;
+{
+ int32_t tmp = htonl (val);
+ memcpy (obuf, &tmp, sizeof tmp);
+}
+
+void putUShort (obuf, val)
+ unsigned char *obuf;
+ u_int32_t val;
+{
+ u_int16_t tmp = htons (val);
+ memcpy (obuf, &tmp, sizeof tmp);
+}
+
+void putShort (obuf, val)
+ unsigned char *obuf;
+ int32_t val;
+{
+ int16_t tmp = htons (val);
+ memcpy (obuf, &tmp, sizeof tmp);
+}
+
+void putUChar (obuf, val)
+ unsigned char *obuf;
+ u_int32_t val;
+{
+ *obuf = val;
+}
+
+u_int32_t getUChar (obuf)
+ const unsigned char *obuf;
+{
+ return obuf [0];
+}
+
+int converted_length (buf, base, width)
+ const unsigned char *buf;
+ unsigned int base;
+ unsigned int width;
+{
+ u_int32_t number;
+ u_int32_t column;
+ int power = 1;
+ u_int32_t newcolumn = base;
+
+ if (base > 16)
+ return 0;
+
+ if (width == 1)
+ number = getUChar (buf);
+ else if (width == 2)
+ number = getUShort (buf);
+ else if (width == 4)
+ number = getULong (buf);
+ else
+ return 0;
+
+ do {
+ column = newcolumn;
+
+ if (number < column)
+ return power;
+ power++;
+ newcolumn = column * base;
+ /* If we wrap around, it must be the next power of two up. */
+ } while (newcolumn > column);
+
+ return power;
+}
+
+int binary_to_ascii (outbuf, inbuf, base, width)
+ unsigned char *outbuf;
+ const unsigned char *inbuf;
+ unsigned int base;
+ unsigned int width;
+{
+ u_int32_t number;
+ static char h2a [] = "0123456789abcdef";
+ int power = converted_length (inbuf, base, width);
+ int i;
+
+ if (base > 16)
+ return 0;
+
+ if (width == 1)
+ number = getUChar (inbuf);
+ else if (width == 2)
+ number = getUShort (inbuf);
+ else if (width == 4)
+ number = getULong (inbuf);
+ else
+ return 0;
+
+ for (i = power - 1 ; i >= 0; i--) {
+ outbuf [i] = h2a [number % base];
+ number /= base;
+ }
+
+ return power;
+}
diff --git a/omapip/dispatch.c b/omapip/dispatch.c
new file mode 100644
index 0000000..be3918b
--- /dev/null
+++ b/omapip/dispatch.c
@@ -0,0 +1,959 @@
+/* dispatch.c
+
+ I/O dispatcher. */
+
+/*
+ * Copyright (c) 2004,2007-2009,2013-2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+#include <sys/time.h>
+
+static omapi_io_object_t omapi_io_states;
+struct timeval cur_tv;
+
+struct eventqueue *rw_queue_empty;
+
+OMAPI_OBJECT_ALLOC (omapi_io,
+ omapi_io_object_t, omapi_type_io_object)
+OMAPI_OBJECT_ALLOC (omapi_waiter,
+ omapi_waiter_object_t, omapi_type_waiter)
+
+void
+register_eventhandler(struct eventqueue **queue, void (*handler)(void *))
+{
+ struct eventqueue *t, *q;
+
+ /* traverse to end of list */
+ t = NULL;
+ for (q = *queue ; q ; q = q->next) {
+ if (q->handler == handler)
+ return; /* handler already registered */
+ t = q;
+ }
+
+ q = ((struct eventqueue *)dmalloc(sizeof(struct eventqueue), MDL));
+ if (!q)
+ log_fatal("register_eventhandler: no memory!");
+ memset(q, 0, sizeof *q);
+ if (t)
+ t->next = q;
+ else
+ *queue = q;
+ q->handler = handler;
+ return;
+}
+
+void
+unregister_eventhandler(struct eventqueue **queue, void (*handler)(void *))
+{
+ struct eventqueue *t, *q;
+
+ /* traverse to end of list */
+ t= NULL;
+ for (q = *queue ; q ; q = q->next) {
+ if (q->handler == handler) {
+ if (t)
+ t->next = q->next;
+ else
+ *queue = q->next;
+ dfree(q, MDL); /* Don't access q after this!*/
+ break;
+ }
+ t = q;
+ }
+ return;
+}
+
+void
+trigger_event(struct eventqueue **queue)
+{
+ struct eventqueue *q;
+
+ for (q=*queue ; q ; q=q->next) {
+ if (q->handler)
+ (*q->handler)(NULL);
+ }
+}
+
+/*
+ * Callback routine to connect the omapi I/O object and socket with
+ * the isc socket code. The isc socket code will call this routine
+ * which will then call the correct local routine to process the bytes.
+ *
+ * Currently we are always willing to read more data, this should be modified
+ * so that on connections we don't read more if we already have enough.
+ *
+ * If we have more bytes to write we ask the library to call us when
+ * we can write more. If we indicate we don't have more to write we need
+ * to poke the library via isc_socket_fdwatchpoke.
+ */
+
+/*
+ * sockdelete indicates if we are deleting the socket or leaving it in place
+ * 1 is delete, 0 is leave in place
+ */
+#define SOCKDELETE 1
+int
+omapi_iscsock_cb(isc_task_t *task,
+ isc_socket_t *socket,
+ void *cbarg,
+ int flags)
+{
+ omapi_io_object_t *obj;
+ isc_result_t status;
+
+ /* Get the current time... */
+ gettimeofday (&cur_tv, (struct timezone *)0);
+
+ /* isc socket stuff */
+#if SOCKDELETE
+ /*
+ * walk through the io states list, if our object is on there
+ * service it. if not ignore it.
+ */
+ for (obj = omapi_io_states.next;
+ (obj != NULL) && (obj->next != NULL);
+ obj = obj->next) {
+ if (obj == cbarg)
+ break;
+ }
+ if (obj == NULL) {
+ return(0);
+ }
+#else
+ /* Not much to be done if we have the wrong type of object. */
+ if (((omapi_object_t *)cbarg) -> type != omapi_type_io_object) {
+ log_fatal ("Incorrect object type, must be of type io_object");
+ }
+ obj = (omapi_io_object_t *)cbarg;
+
+ /*
+ * If the object is marked as closed don't try and process
+ * anything just indicate that we don't want any more.
+ *
+ * This should be a temporary fix until we arrange to properly
+ * close the socket.
+ */
+ if (obj->closed == ISC_TRUE) {
+ return(0);
+ }
+#endif
+
+ if ((flags == ISC_SOCKFDWATCH_READ) &&
+ (obj->reader != NULL) &&
+ (obj->inner != NULL)) {
+ status = obj->reader(obj->inner);
+ /*
+ * If we are shutting down (basically tried to
+ * read and got no bytes) we don't need to try
+ * again.
+ */
+ if (status == ISC_R_SHUTTINGDOWN)
+ return (0);
+ /* Otherwise We always ask for more when reading */
+ return (1);
+ } else if ((flags == ISC_SOCKFDWATCH_WRITE) &&
+ (obj->writer != NULL) &&
+ (obj->inner != NULL)) {
+ status = obj->writer(obj->inner);
+ /* If the writer has more to write they should return
+ * ISC_R_INPROGRESS */
+ if (status == ISC_R_INPROGRESS) {
+ return (1);
+ }
+ }
+
+ /*
+ * We get here if we either had an error (inconsistent
+ * structures etc) or no more to write, tell the socket
+ * lib we don't have more to do right now.
+ */
+ return (0);
+}
+
+/* Register an I/O handle so that we can do asynchronous I/O on it. */
+
+isc_result_t omapi_register_io_object (omapi_object_t *h,
+ int (*readfd) (omapi_object_t *),
+ int (*writefd) (omapi_object_t *),
+ isc_result_t (*reader)
+ (omapi_object_t *),
+ isc_result_t (*writer)
+ (omapi_object_t *),
+ isc_result_t (*reaper)
+ (omapi_object_t *))
+{
+ isc_result_t status;
+ omapi_io_object_t *obj, *p;
+ int fd_flags = 0, fd = 0;
+
+ /* omapi_io_states is a static object. If its reference count
+ is zero, this is the first I/O handle to be registered, so
+ we need to initialize it. Because there is no inner or outer
+ pointer on this object, and we're setting its refcnt to 1, it
+ will never be freed. */
+ if (!omapi_io_states.refcnt) {
+ omapi_io_states.refcnt = 1;
+ omapi_io_states.type = omapi_type_io_object;
+ }
+
+ obj = (omapi_io_object_t *)0;
+ status = omapi_io_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ obj->closed = ISC_FALSE; /* mark as open */
+
+ status = omapi_object_reference (&obj -> inner, h, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_io_dereference (&obj, MDL);
+ return status;
+ }
+
+ status = omapi_object_reference (&h -> outer,
+ (omapi_object_t *)obj, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_io_dereference (&obj, MDL);
+ return status;
+ }
+
+ /*
+ * Attach the I/O object to the isc socket library via the
+ * fdwatch function. This allows the socket library to watch
+ * over a socket that we built. If there are both a read and
+ * a write socket we asssume they are the same socket.
+ */
+
+ if (readfd) {
+ fd_flags |= ISC_SOCKFDWATCH_READ;
+ fd = readfd(h);
+ }
+
+ if (writefd) {
+ fd_flags |= ISC_SOCKFDWATCH_WRITE;
+ fd = writefd(h);
+ }
+
+ if (fd_flags != 0) {
+ status = isc_socket_fdwatchcreate(dhcp_gbl_ctx.socketmgr,
+ fd, fd_flags,
+ omapi_iscsock_cb,
+ obj,
+ dhcp_gbl_ctx.task,
+ &obj->fd);
+ if (status != ISC_R_SUCCESS) {
+ log_error("Unable to register fd with library %s",
+ isc_result_totext(status));
+
+ /*sar*/
+ /* is this the cleanup we need? */
+ omapi_object_dereference(&h->outer, MDL);
+ omapi_io_dereference (&obj, MDL);
+ return (status);
+ }
+ }
+
+
+ /* Find the last I/O state, if there are any. */
+ for (p = omapi_io_states.next;
+ p && p -> next; p = p -> next)
+ ;
+ if (p)
+ omapi_io_reference (&p -> next, obj, MDL);
+ else
+ omapi_io_reference (&omapi_io_states.next, obj, MDL);
+
+ obj -> readfd = readfd;
+ obj -> writefd = writefd;
+ obj -> reader = reader;
+ obj -> writer = writer;
+ obj -> reaper = reaper;
+
+ omapi_io_dereference(&obj, MDL);
+ return ISC_R_SUCCESS;
+}
+
+/*
+ * ReRegister an I/O handle so that we can do asynchronous I/O on it.
+ * If the handle doesn't exist we call the register routine to build it.
+ * If it does exist we change the functions associated with it, and
+ * repoke the fd code to make it happy. Neither the objects nor the
+ * fd are allowed to have changed.
+ */
+
+isc_result_t omapi_reregister_io_object (omapi_object_t *h,
+ int (*readfd) (omapi_object_t *),
+ int (*writefd) (omapi_object_t *),
+ isc_result_t (*reader)
+ (omapi_object_t *),
+ isc_result_t (*writer)
+ (omapi_object_t *),
+ isc_result_t (*reaper)
+ (omapi_object_t *))
+{
+ omapi_io_object_t *obj;
+ int fd_flags = 0;
+
+ if ((!h -> outer) || (h -> outer -> type != omapi_type_io_object)) {
+ /*
+ * If we don't have an object or if the type isn't what
+ * we expect do the normal registration (which will overwrite
+ * an incorrect type, that's what we did historically, may
+ * want to change that)
+ */
+ return (omapi_register_io_object (h, readfd, writefd,
+ reader, writer, reaper));
+ }
+
+ /* We have an io object of the correct type, try to update it */
+ /*sar*/
+ /* Should we validate that the fd matches the previous one?
+ * It's suppossed to, that's a requirement, don't bother yet */
+
+ obj = (omapi_io_object_t *)h->outer;
+
+ obj->readfd = readfd;
+ obj->writefd = writefd;
+ obj->reader = reader;
+ obj->writer = writer;
+ obj->reaper = reaper;
+
+ if (readfd) {
+ fd_flags |= ISC_SOCKFDWATCH_READ;
+ }
+
+ if (writefd) {
+ fd_flags |= ISC_SOCKFDWATCH_WRITE;
+ }
+
+ isc_socket_fdwatchpoke(obj->fd, fd_flags);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t omapi_unregister_io_object (omapi_object_t *h)
+{
+ omapi_io_object_t *obj, *ph;
+#if SOCKDELETE
+ omapi_io_object_t *p, *last;
+#endif
+
+ if (!h -> outer || h -> outer -> type != omapi_type_io_object)
+ return DHCP_R_INVALIDARG;
+ obj = (omapi_io_object_t *)h -> outer;
+ ph = (omapi_io_object_t *)0;
+ omapi_io_reference (&ph, obj, MDL);
+
+#if SOCKDELETE
+ /*
+ * For now we leave this out. We can't clean up the isc socket
+ * structure cleanly yet so we need to leave the io object in place.
+ * By leaving it on the io states list we avoid it being freed.
+ * We also mark it as closed to avoid using it.
+ */
+
+ /* remove from the list of I/O states */
+ last = &omapi_io_states;
+ for (p = omapi_io_states.next; p; p = p -> next) {
+ if (p == obj) {
+ omapi_io_dereference (&last -> next, MDL);
+ omapi_io_reference (&last -> next, p -> next, MDL);
+ break;
+ }
+ last = p;
+ }
+ if (obj -> next)
+ omapi_io_dereference (&obj -> next, MDL);
+#endif
+
+ if (obj -> outer) {
+ if (obj -> outer -> inner == (omapi_object_t *)obj)
+ omapi_object_dereference (&obj -> outer -> inner,
+ MDL);
+ omapi_object_dereference (&obj -> outer, MDL);
+ }
+ omapi_object_dereference (&obj -> inner, MDL);
+ omapi_object_dereference (&h -> outer, MDL);
+
+#if SOCKDELETE
+ /* remove isc socket associations */
+ if (obj->fd != NULL) {
+ isc_socket_cancel(obj->fd, dhcp_gbl_ctx.task,
+ ISC_SOCKCANCEL_ALL);
+ isc_socket_detach(&obj->fd);
+ }
+#else
+ obj->closed = ISC_TRUE;
+#endif
+
+ omapi_io_dereference (&ph, MDL);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_dispatch (struct timeval *t)
+{
+ return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
+ t);
+}
+
+isc_result_t omapi_wait_for_completion (omapi_object_t *object,
+ struct timeval *t)
+{
+ isc_result_t status;
+ omapi_waiter_object_t *waiter;
+ omapi_object_t *inner;
+
+ if (object) {
+ waiter = (omapi_waiter_object_t *)0;
+ status = omapi_waiter_allocate (&waiter, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ /* Paste the waiter object onto the inner object we're
+ waiting on. */
+ for (inner = object; inner -> inner; inner = inner -> inner)
+ ;
+
+ status = omapi_object_reference (&waiter -> outer, inner, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_waiter_dereference (&waiter, MDL);
+ return status;
+ }
+
+ status = omapi_object_reference (&inner -> inner,
+ (omapi_object_t *)waiter,
+ MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_waiter_dereference (&waiter, MDL);
+ return status;
+ }
+ } else
+ waiter = (omapi_waiter_object_t *)0;
+
+ do {
+ status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ } while (!waiter || !waiter -> ready);
+
+ if (waiter -> outer) {
+ if (waiter -> outer -> inner) {
+ omapi_object_dereference (&waiter -> outer -> inner,
+ MDL);
+ if (waiter -> inner)
+ omapi_object_reference
+ (&waiter -> outer -> inner,
+ waiter -> inner, MDL);
+ }
+ omapi_object_dereference (&waiter -> outer, MDL);
+ }
+ if (waiter -> inner)
+ omapi_object_dereference (&waiter -> inner, MDL);
+
+ status = waiter -> waitstatus;
+ omapi_waiter_dereference (&waiter, MDL);
+ return status;
+}
+
+isc_result_t omapi_one_dispatch (omapi_object_t *wo,
+ struct timeval *t)
+{
+ fd_set r, w, x, rr, ww, xx;
+ int max = 0;
+ int count;
+ int desc;
+ struct timeval now, to;
+ omapi_io_object_t *io, *prev, *next;
+ omapi_waiter_object_t *waiter;
+ omapi_object_t *tmp = (omapi_object_t *)0;
+
+ if (!wo || wo -> type != omapi_type_waiter)
+ waiter = (omapi_waiter_object_t *)0;
+ else
+ waiter = (omapi_waiter_object_t *)wo;
+
+ FD_ZERO (&x);
+
+ /* First, see if the timeout has expired, and if so return. */
+ if (t) {
+ gettimeofday (&now, (struct timezone *)0);
+ cur_tv.tv_sec = now.tv_sec;
+ cur_tv.tv_usec = now.tv_usec;
+ if (now.tv_sec > t -> tv_sec ||
+ (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
+ return ISC_R_TIMEDOUT;
+
+ /* We didn't time out, so figure out how long until
+ we do. */
+ to.tv_sec = t -> tv_sec - now.tv_sec;
+ to.tv_usec = t -> tv_usec - now.tv_usec;
+ if (to.tv_usec < 0) {
+ to.tv_usec += 1000000;
+ to.tv_sec--;
+ }
+
+ /* It is possible for the timeout to get set larger than
+ the largest time select() is willing to accept.
+ Restricting the timeout to a maximum of one day should
+ work around this. -DPN. (Ref: Bug #416) */
+ if (to.tv_sec > (60 * 60 * 24))
+ to.tv_sec = 60 * 60 * 24;
+ }
+
+ /* If the object we're waiting on has reached completion,
+ return now. */
+ if (waiter && waiter -> ready)
+ return ISC_R_SUCCESS;
+
+ again:
+ /* If we have no I/O state, we can't proceed. */
+ if (!(io = omapi_io_states.next))
+ return ISC_R_NOMORE;
+
+ /* Set up the read and write masks. */
+ FD_ZERO (&r);
+ FD_ZERO (&w);
+
+ for (; io; io = io -> next) {
+ /* Check for a read socket. If we shouldn't be
+ trying to read for this I/O object, either there
+ won't be a readfd function, or it'll return -1. */
+ if (io -> readfd && io -> inner &&
+ (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
+ FD_SET (desc, &r);
+ if (desc > max)
+ max = desc;
+ }
+
+ /* Same deal for write fdets. */
+ if (io -> writefd && io -> inner &&
+ (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
+ FD_SET (desc, &w);
+ if (desc > max)
+ max = desc;
+ }
+ }
+
+ /* poll if all reader are dry */
+ now.tv_sec = 0;
+ now.tv_usec = 0;
+ rr=r;
+ ww=w;
+ xx=x;
+
+ /* poll once */
+ count = select(max + 1, &r, &w, &x, &now);
+ if (!count) {
+ /* We are dry now */
+ trigger_event(&rw_queue_empty);
+ /* Wait for a packet or a timeout... XXX */
+ r = rr;
+ w = ww;
+ x = xx;
+ count = select(max + 1, &r, &w, &x, t ? &to : NULL);
+ }
+
+ /* Get the current time... */
+ gettimeofday (&cur_tv, (struct timezone *)0);
+
+ /* We probably have a bad file descriptor. Figure out which one.
+ When we find it, call the reaper function on it, which will
+ maybe make it go away, and then try again. */
+ if (count < 0) {
+ struct timeval t0;
+ omapi_io_object_t *prev = (omapi_io_object_t *)0;
+ io = (omapi_io_object_t *)0;
+ if (omapi_io_states.next)
+ omapi_io_reference (&io, omapi_io_states.next, MDL);
+
+ while (io) {
+ omapi_object_t *obj;
+ FD_ZERO (&r);
+ FD_ZERO (&w);
+ t0.tv_sec = t0.tv_usec = 0;
+
+ if (io -> readfd && io -> inner &&
+ (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
+ FD_SET (desc, &r);
+ count = select (desc + 1, &r, &w, &x, &t0);
+ bogon:
+ if (count < 0) {
+ log_error ("Bad descriptor %d.", desc);
+ for (obj = (omapi_object_t *)io;
+ obj -> outer;
+ obj = obj -> outer)
+ ;
+ for (; obj; obj = obj -> inner) {
+ omapi_value_t *ov;
+ int len;
+ const char *s;
+ ov = (omapi_value_t *)0;
+ omapi_get_value_str (obj,
+ (omapi_object_t *)0,
+ "name", &ov);
+ if (ov && ov -> value &&
+ (ov -> value -> type ==
+ omapi_datatype_string)) {
+ s = (char *)
+ ov -> value -> u.buffer.value;
+ len = ov -> value -> u.buffer.len;
+ } else {
+ s = "";
+ len = 0;
+ }
+ log_error ("Object %lx %s%s%.*s",
+ (unsigned long)obj,
+ obj -> type -> name,
+ len ? " " : "",
+ len, s);
+ if (len)
+ omapi_value_dereference (&ov, MDL);
+ }
+ (*(io -> reaper)) (io -> inner);
+ if (prev) {
+ omapi_io_dereference (&prev -> next, MDL);
+ if (io -> next)
+ omapi_io_reference (&prev -> next,
+ io -> next, MDL);
+ } else {
+ omapi_io_dereference
+ (&omapi_io_states.next, MDL);
+ if (io -> next)
+ omapi_io_reference
+ (&omapi_io_states.next,
+ io -> next, MDL);
+ }
+ omapi_io_dereference (&io, MDL);
+ goto again;
+ }
+ }
+
+ FD_ZERO (&r);
+ FD_ZERO (&w);
+ t0.tv_sec = t0.tv_usec = 0;
+
+ /* Same deal for write fdets. */
+ if (io -> writefd && io -> inner &&
+ (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
+ FD_SET (desc, &w);
+ count = select (desc + 1, &r, &w, &x, &t0);
+ if (count < 0)
+ goto bogon;
+ }
+ if (prev)
+ omapi_io_dereference (&prev, MDL);
+ omapi_io_reference (&prev, io, MDL);
+ omapi_io_dereference (&io, MDL);
+ if (prev -> next)
+ omapi_io_reference (&io, prev -> next, MDL);
+ }
+ if (prev)
+ omapi_io_dereference (&prev, MDL);
+
+ }
+
+ for (io = omapi_io_states.next; io; io = io -> next) {
+ if (!io -> inner)
+ continue;
+ omapi_object_reference (&tmp, io -> inner, MDL);
+ /* Check for a read descriptor, and if there is one,
+ see if we got input on that socket. */
+ if (io -> readfd &&
+ (desc = (*(io -> readfd)) (tmp)) >= 0) {
+ if (FD_ISSET (desc, &r))
+ ((*(io -> reader)) (tmp));
+ }
+
+ /* Same deal for write descriptors. */
+ if (io -> writefd &&
+ (desc = (*(io -> writefd)) (tmp)) >= 0)
+ {
+ if (FD_ISSET (desc, &w))
+ ((*(io -> writer)) (tmp));
+ }
+ omapi_object_dereference (&tmp, MDL);
+ }
+
+ /* Now check for I/O handles that are no longer valid,
+ and remove them from the list. */
+ prev = NULL;
+ io = NULL;
+ if (omapi_io_states.next != NULL) {
+ omapi_io_reference(&io, omapi_io_states.next, MDL);
+ }
+ while (io != NULL) {
+ if ((io->inner == NULL) ||
+ ((io->reaper != NULL) &&
+ ((io->reaper)(io->inner) != ISC_R_SUCCESS)))
+ {
+
+ omapi_io_object_t *tmp = NULL;
+ /* Save a reference to the next
+ pointer, if there is one. */
+ if (io->next != NULL) {
+ omapi_io_reference(&tmp, io->next, MDL);
+ omapi_io_dereference(&io->next, MDL);
+ }
+ if (prev != NULL) {
+ omapi_io_dereference(&prev->next, MDL);
+ if (tmp != NULL)
+ omapi_io_reference(&prev->next,
+ tmp, MDL);
+ } else {
+ omapi_io_dereference(&omapi_io_states.next,
+ MDL);
+ if (tmp != NULL)
+ omapi_io_reference
+ (&omapi_io_states.next,
+ tmp, MDL);
+ else
+ omapi_signal_in(
+ (omapi_object_t *)
+ &omapi_io_states,
+ "ready");
+ }
+ if (tmp != NULL)
+ omapi_io_dereference(&tmp, MDL);
+
+ } else {
+
+ if (prev != NULL) {
+ omapi_io_dereference(&prev, MDL);
+ }
+ omapi_io_reference(&prev, io, MDL);
+ }
+
+ /*
+ * Equivalent to:
+ * io = io->next
+ * But using our reference counting voodoo.
+ */
+ next = NULL;
+ if (io->next != NULL) {
+ omapi_io_reference(&next, io->next, MDL);
+ }
+ omapi_io_dereference(&io, MDL);
+ if (next != NULL) {
+ omapi_io_reference(&io, next, MDL);
+ omapi_io_dereference(&next, MDL);
+ }
+ }
+ if (prev != NULL) {
+ omapi_io_dereference(&prev, MDL);
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_io_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ if (h -> type != omapi_type_io_object)
+ return DHCP_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> set_value)
+ return (*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_io_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ if (h -> type != omapi_type_io_object)
+ return DHCP_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+/* omapi_io_destroy (object, MDL);
+ *
+ * Find the requested IO [object] and remove it from the list of io
+ * states, causing the cleanup functions to destroy it. Note that we must
+ * hold a reference on the object while moving its ->next reference and
+ * removing the reference in the chain to the target object...otherwise it
+ * may be cleaned up from under us.
+ */
+isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
+{
+ omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder;
+
+ if (h -> type != omapi_type_io_object)
+ return DHCP_R_INVALIDARG;
+
+ /* remove from the list of I/O states */
+ for (p = omapi_io_states.next; p; p = p -> next) {
+ if (p == (omapi_io_object_t *)h) {
+ omapi_io_reference (&obj, p, MDL);
+
+ if (last)
+ holder = &last -> next;
+ else
+ holder = &omapi_io_states.next;
+
+ omapi_io_dereference (holder, MDL);
+
+ if (obj -> next) {
+ omapi_io_reference (holder, obj -> next, MDL);
+ omapi_io_dereference (&obj -> next, MDL);
+ }
+
+ return omapi_io_dereference (&obj, MDL);
+ }
+ last = p;
+ }
+
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_io_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ if (h -> type != omapi_type_io_object)
+ return DHCP_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_io_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *i)
+{
+ if (i -> type != omapi_type_io_object)
+ return DHCP_R_INVALIDARG;
+
+ if (i -> inner && i -> inner -> type -> stuff_values)
+ return (*(i -> inner -> type -> stuff_values)) (c, id,
+ i -> inner);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ omapi_waiter_object_t *waiter;
+
+ if (h -> type != omapi_type_waiter)
+ return DHCP_R_INVALIDARG;
+
+ if (!strcmp (name, "ready")) {
+ waiter = (omapi_waiter_object_t *)h;
+ waiter -> ready = 1;
+ waiter -> waitstatus = ISC_R_SUCCESS;
+ return ISC_R_SUCCESS;
+ }
+
+ if (!strcmp(name, "status")) {
+ waiter = (omapi_waiter_object_t *)h;
+ waiter->ready = 1;
+ waiter->waitstatus = va_arg(ap, isc_result_t);
+ return ISC_R_SUCCESS;
+ }
+
+ if (!strcmp (name, "disconnect")) {
+ waiter = (omapi_waiter_object_t *)h;
+ waiter -> ready = 1;
+ waiter -> waitstatus = DHCP_R_CONNRESET;
+ return ISC_R_SUCCESS;
+ }
+
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+/** @brief calls a given function on every object
+ *
+ * @param func function to be called
+ * @param p parameter to be passed to each function instance
+ *
+ * @return result (ISC_R_SUCCESS if successful, error code otherwise)
+ */
+isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
+ void *),
+ void *p)
+{
+ omapi_io_object_t *io = NULL;
+ isc_result_t status;
+ omapi_io_object_t *next = NULL;
+
+ /*
+ * This just calls func on every inner object on the list. It would
+ * be much simpler in general case, but one of the operations could be
+ * release of the objects. Therefore we need to ref count the io and
+ * io->next pointers.
+ */
+
+ if (omapi_io_states.next) {
+ omapi_object_reference((omapi_object_t**)&io,
+ (omapi_object_t*)omapi_io_states.next,
+ MDL);
+ }
+
+ while(io) {
+ /* If there's a next object, save it */
+ if (io->next) {
+ omapi_object_reference((omapi_object_t**)&next,
+ (omapi_object_t*)io->next, MDL);
+ }
+ if (io->inner) {
+ status = (*func) (io->inner, p);
+ if (status != ISC_R_SUCCESS) {
+ /* Something went wrong. Let's stop using io & next pointer
+ * and bail out */
+ omapi_object_dereference((omapi_object_t**)&io, MDL);
+ if (next) {
+ omapi_object_dereference((omapi_object_t**)&next, MDL);
+ }
+ return status;
+ }
+ }
+ /* Update the io pointer and free the next pointer */
+ omapi_object_dereference((omapi_object_t**)&io, MDL);
+ if (next) {
+ omapi_object_reference((omapi_object_t**)&io,
+ (omapi_object_t*)next,
+ MDL);
+ omapi_object_dereference((omapi_object_t**)&next, MDL);
+ }
+ }
+
+ /*
+ * The only way to get here is when next is NULL. There's no need
+ * to dereference it.
+ */
+ return ISC_R_SUCCESS;
+}
diff --git a/omapip/errwarn.c b/omapip/errwarn.c
new file mode 100644
index 0000000..d68af04
--- /dev/null
+++ b/omapip/errwarn.c
@@ -0,0 +1,363 @@
+/* errwarn.c
+
+ Errors and warnings... */
+
+/*
+ * Copyright (c) 1995 RadioMail Corporation.
+ * Copyright (c) 2004,2007,2009,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ * This software was written for RadioMail Corporation by Ted Lemon
+ * under a contract with Vixie Enterprises. Further modifications have
+ * been made for Internet Systems Consortium under a contract
+ * with Vixie Laboratories.
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+#include <errno.h>
+#include <syslog.h>
+
+#ifdef DEBUG
+int log_perror = -1;
+#else
+int log_perror = 1;
+#endif
+void (*log_cleanup) (void);
+
+#define CVT_BUF_MAX 1023
+static char mbuf [CVT_BUF_MAX + 1];
+static char fbuf [CVT_BUF_MAX + 1];
+
+/* Log an error message, then exit... */
+
+void log_fatal (const char * fmt, ... )
+{
+ va_list list;
+
+ do_percentm (fbuf, fmt);
+
+ /* %Audit% This is log output. %2004.06.17,Safe%
+ * If we truncate we hope the user can get a hint from the log.
+ */
+ va_start (list, fmt);
+ vsnprintf (mbuf, sizeof mbuf, fbuf, list);
+ va_end (list);
+
+#ifndef DEBUG
+ syslog (LOG_ERR, "%s", mbuf);
+#endif
+
+ /* Also log it to stderr? */
+ if (log_perror) {
+ IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf)));
+ IGNORE_RET (write (STDERR_FILENO, "\n", 1));
+ }
+
+#if !defined (NOMINUM)
+ log_error ("%s", "");
+ log_error ("If you did not get this software from ftp.isc.org, please");
+ log_error ("get the latest from ftp.isc.org and install that before");
+ log_error ("requesting help.");
+ log_error ("%s", "");
+ log_error ("If you did get this software from ftp.isc.org and have not");
+ log_error ("yet read the README, please read it before requesting help.");
+ log_error ("If you intend to request help from the dhcp-bugs at isc.org");
+ log_error ("mailing list, please read the section on the README about");
+ log_error ("submitting bug reports and requests for help.");
+ log_error ("%s", "");
+ log_error ("Please do not under any circumstances send requests for");
+ log_error ("help directly to the authors of this software - please");
+ log_error ("send them to the appropriate mailing list as described in");
+ log_error ("the README file.");
+ log_error ("%s", "");
+ log_error ("exiting.");
+#endif
+ if (log_cleanup)
+ (*log_cleanup) ();
+ exit (1);
+}
+
+/* Log an error message... */
+
+int log_error (const char * fmt, ...)
+{
+ va_list list;
+
+ do_percentm (fbuf, fmt);
+
+ /* %Audit% This is log output. %2004.06.17,Safe%
+ * If we truncate we hope the user can get a hint from the log.
+ */
+ va_start (list, fmt);
+ vsnprintf (mbuf, sizeof mbuf, fbuf, list);
+ va_end (list);
+
+#ifndef DEBUG
+ syslog (LOG_ERR, "%s", mbuf);
+#endif
+
+ if (log_perror) {
+ IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf)));
+ IGNORE_RET (write (STDERR_FILENO, "\n", 1));
+ }
+
+ return 0;
+}
+
+/* Log a note... */
+
+int log_info (const char *fmt, ...)
+{
+ va_list list;
+
+ do_percentm (fbuf, fmt);
+
+ /* %Audit% This is log output. %2004.06.17,Safe%
+ * If we truncate we hope the user can get a hint from the log.
+ */
+ va_start (list, fmt);
+ vsnprintf (mbuf, sizeof mbuf, fbuf, list);
+ va_end (list);
+
+#ifndef DEBUG
+ syslog (LOG_INFO, "%s", mbuf);
+#endif
+
+ if (log_perror) {
+ IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf)));
+ IGNORE_RET (write (STDERR_FILENO, "\n", 1));
+ }
+
+ return 0;
+}
+
+/* Log a debug message... */
+
+int log_debug (const char *fmt, ...)
+{
+ va_list list;
+
+ do_percentm (fbuf, fmt);
+
+ /* %Audit% This is log output. %2004.06.17,Safe%
+ * If we truncate we hope the user can get a hint from the log.
+ */
+ va_start (list, fmt);
+ vsnprintf (mbuf, sizeof mbuf, fbuf, list);
+ va_end (list);
+
+#ifndef DEBUG
+ syslog (LOG_DEBUG, "%s", mbuf);
+#endif
+
+ if (log_perror) {
+ IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf)));
+ IGNORE_RET (write (STDERR_FILENO, "\n", 1));
+ }
+
+ return 0;
+}
+
+/* Find %m in the input string and substitute an error message string. */
+
+void do_percentm (obuf, ibuf)
+ char *obuf;
+ const char *ibuf;
+{
+ const char *s = ibuf;
+ char *p = obuf;
+ int infmt = 0;
+ const char *m;
+ int len = 0;
+
+ while (*s) {
+ if (infmt) {
+ if (*s == 'm') {
+#ifndef __CYGWIN32__
+ m = strerror (errno);
+#else
+ m = pWSAError ();
+#endif
+ if (!m)
+ m = "<unknown error>";
+ len += strlen (m);
+ if (len > CVT_BUF_MAX)
+ goto out;
+ strcpy (p - 1, m);
+ p += strlen (p);
+ ++s;
+ } else {
+ if (++len > CVT_BUF_MAX)
+ goto out;
+ *p++ = *s++;
+ }
+ infmt = 0;
+ } else {
+ if (*s == '%')
+ infmt = 1;
+ if (++len > CVT_BUF_MAX)
+ goto out;
+ *p++ = *s++;
+ }
+ }
+ out:
+ *p = 0;
+}
+
+#ifdef NO_STRERROR
+char *strerror (err)
+ int err;
+{
+ extern char *sys_errlist [];
+ extern int sys_nerr;
+ static char errbuf [128];
+
+ if (err < 0 || err >= sys_nerr) {
+ sprintf (errbuf, "Error %d", err);
+ return errbuf;
+ }
+ return sys_errlist [err];
+}
+#endif /* NO_STRERROR */
+
+#ifdef _WIN32
+char *pWSAError ()
+{
+ int err = WSAGetLastError ();
+
+ switch (err)
+ {
+ case WSAEACCES:
+ return "Permission denied";
+ case WSAEADDRINUSE:
+ return "Address already in use";
+ case WSAEADDRNOTAVAIL:
+ return "Cannot assign requested address";
+ case WSAEAFNOSUPPORT:
+ return "Address family not supported by protocol family";
+ case WSAEALREADY:
+ return "Operation already in progress";
+ case WSAECONNABORTED:
+ return "Software caused connection abort";
+ case WSAECONNREFUSED:
+ return "Connection refused";
+ case WSAECONNRESET:
+ return "Connection reset by peer";
+ case WSAEDESTADDRREQ:
+ return "Destination address required";
+ case WSAEFAULT:
+ return "Bad address";
+ case WSAEHOSTDOWN:
+ return "Host is down";
+ case WSAEHOSTUNREACH:
+ return "No route to host";
+ case WSAEINPROGRESS:
+ return "Operation now in progress";
+ case WSAEINTR:
+ return "Interrupted function call";
+ case WSAEINVAL:
+ return "Invalid argument";
+ case WSAEISCONN:
+ return "Socket is already connected";
+ case WSAEMFILE:
+ return "Too many open files";
+ case WSAEMSGSIZE:
+ return "Message too long";
+ case WSAENETDOWN:
+ return "Network is down";
+ case WSAENETRESET:
+ return "Network dropped connection on reset";
+ case WSAENETUNREACH:
+ return "Network is unreachable";
+ case WSAENOBUFS:
+ return "No buffer space available";
+ case WSAENOPROTOOPT:
+ return "Bad protocol option";
+ case WSAENOTCONN:
+ return "Socket is not connected";
+ case WSAENOTSOCK:
+ return "Socket operation on non-socket";
+ case WSAEOPNOTSUPP:
+ return "Operation not supported";
+ case WSAEPFNOSUPPORT:
+ return "Protocol family not supported";
+ case WSAEPROCLIM:
+ return "Too many processes";
+ case WSAEPROTONOSUPPORT:
+ return "Protocol not supported";
+ case WSAEPROTOTYPE:
+ return "Protocol wrong type for socket";
+ case WSAESHUTDOWN:
+ return "Cannot send after socket shutdown";
+ case WSAESOCKTNOSUPPORT:
+ return "Socket type not supported";
+ case WSAETIMEDOUT:
+ return "Connection timed out";
+ case WSAEWOULDBLOCK:
+ return "Resource temporarily unavailable";
+ case WSAHOST_NOT_FOUND:
+ return "Host not found";
+#if 0
+ case WSA_INVALID_HANDLE:
+ return "Specified event object handle is invalid";
+ case WSA_INVALID_PARAMETER:
+ return "One or more parameters are invalid";
+ case WSAINVALIDPROCTABLE:
+ return "Invalid procedure table from service provider";
+ case WSAINVALIDPROVIDER:
+ return "Invalid service provider version number";
+ case WSA_IO_PENDING:
+ return "Overlapped operations will complete later";
+ case WSA_IO_INCOMPLETE:
+ return "Overlapped I/O event object not in signaled state";
+ case WSA_NOT_ENOUGH_MEMORY:
+ return "Insufficient memory available";
+#endif
+ case WSANOTINITIALISED:
+ return "Successful WSAStartup not yet performer";
+ case WSANO_DATA:
+ return "Valid name, no data record of requested type";
+ case WSANO_RECOVERY:
+ return "This is a non-recoverable error";
+#if 0
+ case WSAPROVIDERFAILEDINIT:
+ return "Unable to initialize a service provider";
+ case WSASYSCALLFAILURE:
+ return "System call failure";
+#endif
+ case WSASYSNOTREADY:
+ return "Network subsystem is unavailable";
+ case WSATRY_AGAIN:
+ return "Non-authoritative host not found";
+ case WSAVERNOTSUPPORTED:
+ return "WINSOCK.DLL version out of range";
+ case WSAEDISCON:
+ return "Graceful shutdown in progress";
+#if 0
+ case WSA_OPERATION_ABORTED:
+ return "Overlapped operation aborted";
+#endif
+ }
+ return "Unknown WinSock error";
+}
+#endif /* _WIN32 */
diff --git a/omapip/generic.c b/omapip/generic.c
new file mode 100644
index 0000000..6dee801
--- /dev/null
+++ b/omapip/generic.c
@@ -0,0 +1,299 @@
+/* generic.c
+
+ Subroutines that support the generic object. */
+
+/*
+ * Copyright (c) 2004-2007,2009,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+
+OMAPI_OBJECT_ALLOC (omapi_generic,
+ omapi_generic_object_t, omapi_type_generic)
+
+isc_result_t omapi_generic_new (omapi_object_t **gen,
+ const char *file, int line)
+{
+ /* Backwards compatibility. */
+ return omapi_generic_allocate ((omapi_generic_object_t **)gen,
+ file, line);
+}
+
+isc_result_t omapi_generic_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ omapi_generic_object_t *g;
+ omapi_value_t *new;
+ omapi_value_t **va;
+ u_int8_t *ca;
+ int vm_new;
+ int i, vfree = -1;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_generic)
+ return DHCP_R_INVALIDARG;
+ g = (omapi_generic_object_t *)h;
+
+ /* See if there's already a value with this name attached to
+ the generic object, and if so, replace the current value
+ with the new one. */
+ for (i = 0; i < g -> nvalues; i++) {
+ if (!omapi_data_string_cmp (name, g -> values [i] -> name)) {
+ /* There's an inconsistency here: the standard
+ behaviour of a set_values method when
+ passed a matching name and a null value is
+ to delete the value associated with that
+ name (where possible). In the generic
+ object, we remember the name/null pair,
+ because generic objects are generally used
+ to pass messages around, and this is the
+ way that remote entities delete values from
+ local objects. If the get_value method of
+ a generic object is called for a name that
+ maps to a name/null pair, ISC_R_NOTFOUND is
+ returned. */
+ new = (omapi_value_t *)0;
+ status = (omapi_value_new (&new, MDL));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ omapi_data_string_reference (&new -> name, name, MDL);
+ if (value)
+ omapi_typed_data_reference (&new -> value,
+ value, MDL);
+
+ omapi_value_dereference (&(g -> values [i]), MDL);
+ status = (omapi_value_reference
+ (&(g -> values [i]), new, MDL));
+ omapi_value_dereference (&new, MDL);
+ g -> changed [i] = 1;
+ return status;
+ }
+ /* Notice a free slot if we pass one. */
+ else if (vfree == -1 && !g -> values [i])
+ vfree = i;
+ }
+
+ /* If the name isn't already attached to this object, see if an
+ inner object has it. */
+ if (h -> inner && h -> inner -> type -> set_value) {
+ status = ((*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value));
+ if (status != ISC_R_NOTFOUND)
+ return status;
+ }
+
+ /* Okay, so it's a value that no inner object knows about, and
+ (implicitly, since the outer object set_value method would
+ have called this object's set_value method) it's an object that
+ no outer object knows about, it's this object's responsibility
+ to remember it - that's what generic objects do. */
+
+ /* Arrange for there to be space for the pointer to the new
+ name/value pair if necessary: */
+ if (vfree == -1) {
+ vfree = g -> nvalues;
+ if (vfree == g -> va_max) {
+ if (g -> va_max)
+ vm_new = 2 * g -> va_max;
+ else
+ vm_new = 10;
+ va = dmalloc (vm_new * sizeof *va, MDL);
+ if (!va)
+ return ISC_R_NOMEMORY;
+ ca = dmalloc (vm_new * sizeof *ca, MDL);
+ if (!ca) {
+ dfree (va, MDL);
+ return ISC_R_NOMEMORY;
+ }
+ if (g -> va_max) {
+ memcpy (va, g -> values,
+ g -> va_max * sizeof *va);
+ memcpy (ca, g -> changed,
+ g -> va_max * sizeof *ca);
+ }
+ memset (va + g -> va_max, 0,
+ (vm_new - g -> va_max) * sizeof *va);
+ memset (ca + g -> va_max, 0,
+ (vm_new - g -> va_max) * sizeof *ca);
+ if (g -> values)
+ dfree (g -> values, MDL);
+ if (g -> changed)
+ dfree (g -> changed, MDL);
+ g -> values = va;
+ g -> changed = ca;
+ g -> va_max = vm_new;
+ }
+ }
+ status = omapi_value_new (&g -> values [vfree], MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ omapi_data_string_reference (&g -> values [vfree] -> name,
+ name, MDL);
+ if (value)
+ omapi_typed_data_reference
+ (&g -> values [vfree] -> value, value, MDL);
+ g -> changed [vfree] = 1;
+ if (vfree == g -> nvalues)
+ g -> nvalues++;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_generic_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ int i;
+ omapi_generic_object_t *g;
+
+ if (h -> type != omapi_type_generic)
+ return DHCP_R_INVALIDARG;
+ g = (omapi_generic_object_t *)h;
+
+ /* Look up the specified name in our list of objects. */
+ for (i = 0; i < g -> nvalues; i++) {
+ if (!g -> values[i])
+ continue;
+ if (!omapi_data_string_cmp (name, g -> values [i] -> name)) {
+ /* If this is a name/null value pair, this is the
+ same as if there were no value that matched
+ the specified name, so return ISC_R_NOTFOUND. */
+ if (!g -> values [i] -> value)
+ return ISC_R_NOTFOUND;
+ /* Otherwise, return the name/value pair. */
+ return omapi_value_reference (value,
+ g -> values [i], MDL);
+ }
+ }
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_generic_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_generic_object_t *g;
+ int i;
+
+ if (h -> type != omapi_type_generic)
+ return ISC_R_UNEXPECTED;
+ g = (omapi_generic_object_t *)h;
+
+ if (g -> values) {
+ for (i = 0; i < g -> nvalues; i++) {
+ if (g -> values [i])
+ omapi_value_dereference (&g -> values [i],
+ file, line);
+ }
+ dfree (g -> values, file, line);
+ dfree (g -> changed, file, line);
+ g -> values = (omapi_value_t **)0;
+ g -> changed = (u_int8_t *)0;
+ g -> va_max = 0;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_generic_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ if (h -> type != omapi_type_generic)
+ return DHCP_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_generic_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *g)
+{
+ omapi_generic_object_t *src;
+ int i;
+ isc_result_t status;
+
+ if (g -> type != omapi_type_generic)
+ return DHCP_R_INVALIDARG;
+ src = (omapi_generic_object_t *)g;
+
+ for (i = 0; i < src -> nvalues; i++) {
+ if (src -> values [i] && src -> values [i] -> name -> len &&
+ src -> changed [i]) {
+ status = (omapi_connection_put_uint16
+ (c, src -> values [i] -> name -> len));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = (omapi_connection_copyin
+ (c, src -> values [i] -> name -> value,
+ src -> values [i] -> name -> len));
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = (omapi_connection_write_typed_data
+ (c, src -> values [i] -> value));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+ }
+
+ if (g -> inner && g -> inner -> type -> stuff_values)
+ return (*(g -> inner -> type -> stuff_values)) (c, id,
+ g -> inner);
+ return ISC_R_SUCCESS;
+}
+
+/* Clear the changed flags on the object. This has the effect that if
+ generic_stuff is called, any attributes that still have a cleared changed
+ flag aren't sent to the peer. This also deletes any values that are
+ null, presuming that these have now been properly handled. */
+
+isc_result_t omapi_generic_clear_flags (omapi_object_t *o)
+{
+ int i;
+ omapi_generic_object_t *g;
+
+ if (o -> type != omapi_type_generic)
+ return DHCP_R_INVALIDARG;
+ g = (omapi_generic_object_t *)o;
+
+ for (i = 0; i < g -> nvalues; i++) {
+ g -> changed [i] = 0;
+ if (g -> values [i] &&
+ !g -> values [i] -> value)
+ omapi_value_dereference (&g -> values [i], MDL);
+ }
+ return ISC_R_SUCCESS;
+}
diff --git a/omapip/handle.c b/omapip/handle.c
new file mode 100644
index 0000000..cae5ec2
--- /dev/null
+++ b/omapip/handle.c
@@ -0,0 +1,302 @@
+/* handle.c
+
+ Functions for maintaining handles on objects. */
+
+/*
+ * Copyright (c) 2009-2010,2012,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+
+/* The handle table is a hierarchical tree designed for quick mapping
+ of handle identifiers to objects. Objects contain their own handle
+ identifiers if they have them, so the reverse mapping is also
+ quick. The hierarchy is made up of table objects, each of which
+ has 120 entries, a flag indicating whether the table is a leaf
+ table or an indirect table, the handle of the first object covered
+ by the table and the first object after that that's *not* covered
+ by the table, a count of how many objects of either type are
+ currently stored in the table, and an array of 120 entries pointing
+ either to objects or tables.
+
+ When we go to add an object to the table, we look to see if the
+ next object handle to be assigned is covered by the outermost
+ table. If it is, we find the place within that table where the
+ next handle should go, and if necessary create additional nodes in
+ the tree to contain the new handle. The pointer to the object is
+ then stored in the correct position.
+
+ Theoretically, we could have some code here to free up handle
+ tables as they go out of use, but by and large handle tables won't
+ go out of use, so this is being skipped for now. It shouldn't be
+ too hard to implement in the future if there's a different
+ application. */
+
+omapi_handle_table_t *omapi_handle_table;
+omapi_handle_t omapi_next_handle = 1; /* Next handle to be assigned. */
+
+#define FIND_HAND 0
+#define CLEAR_HAND 1
+
+static isc_result_t omapi_handle_lookup_in (omapi_object_t **,
+ omapi_handle_t,
+ omapi_handle_table_t *,
+ int);
+static isc_result_t omapi_object_handle_in_table (omapi_handle_t,
+ omapi_handle_table_t *,
+ omapi_object_t *);
+static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **);
+
+isc_result_t omapi_object_handle (omapi_handle_t *h, omapi_object_t *o)
+{
+ isc_result_t status;
+
+ if (o -> handle) {
+ *h = o -> handle;
+ return ISC_R_SUCCESS;
+ }
+
+ if (!omapi_handle_table) {
+ omapi_handle_table = dmalloc (sizeof *omapi_handle_table, MDL);
+ if (!omapi_handle_table)
+ return ISC_R_NOMEMORY;
+ memset (omapi_handle_table, 0, sizeof *omapi_handle_table);
+ omapi_handle_table -> first = 0;
+ omapi_handle_table -> limit = OMAPI_HANDLE_TABLE_SIZE;
+ omapi_handle_table -> leafp = 1;
+ }
+
+ /* If this handle doesn't fit in the outer table, we need to
+ make a new outer table. This is a while loop in case for
+ some reason we decide to do disjoint handle allocation,
+ where the next level of indirection still isn't big enough
+ to enclose the next handle ID. */
+
+ while (omapi_next_handle >= omapi_handle_table -> limit) {
+ omapi_handle_table_t *new;
+
+ new = dmalloc (sizeof *new, MDL);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, sizeof *new);
+ new -> first = 0;
+ new -> limit = (omapi_handle_table -> limit *
+ OMAPI_HANDLE_TABLE_SIZE);
+ new -> leafp = 0;
+ new -> children [0].table = omapi_handle_table;
+ omapi_handle_table = new;
+ }
+
+ /* Try to cram this handle into the existing table. */
+ status = omapi_object_handle_in_table (omapi_next_handle,
+ omapi_handle_table, o);
+ /* If it worked, return the next handle and increment it. */
+ if (status == ISC_R_SUCCESS) {
+ *h = omapi_next_handle;
+ omapi_next_handle++;
+ return ISC_R_SUCCESS;
+ }
+ if (status != ISC_R_NOSPACE)
+ return status;
+
+ status = omapi_handle_table_enclose (&omapi_handle_table);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_handle_in_table (omapi_next_handle,
+ omapi_handle_table, o);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ *h = omapi_next_handle;
+ omapi_next_handle++;
+
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t omapi_object_handle_in_table (omapi_handle_t h,
+ omapi_handle_table_t *table,
+ omapi_object_t *o)
+{
+ omapi_handle_table_t *inner;
+ omapi_handle_t scale, index;
+ isc_result_t status;
+
+ if (table -> first > h || table -> limit <= h)
+ return ISC_R_NOSPACE;
+
+ /* If this is a leaf table, just stash the object in the
+ appropriate place. */
+ if (table -> leafp) {
+ status = (omapi_object_reference
+ (&table -> children [h - table -> first].object,
+ o, MDL));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ o -> handle = h;
+ return ISC_R_SUCCESS;
+ }
+
+ /* Scale is the number of handles represented by each child of this
+ table. For a leaf table, scale would be 1. For a first level
+ of indirection, 120. For a second, 120 * 120. Et cetera. */
+ scale = (table -> limit - table -> first) / OMAPI_HANDLE_TABLE_SIZE;
+
+ /* So the next most direct table from this one that contains the
+ handle must be the subtable of this table whose index into this
+ table's array of children is the handle divided by the scale. */
+ index = (h - table -> first) / scale;
+ inner = table -> children [index].table;
+
+ /* If there is no more direct table than this one in the slot
+ we came up with, make one. */
+ if (!inner) {
+ inner = dmalloc (sizeof *inner, MDL);
+ if (!inner)
+ return ISC_R_NOMEMORY;
+ memset (inner, 0, sizeof *inner);
+ inner -> first = index * scale + table -> first;
+ inner -> limit = inner -> first + scale;
+ if (scale == OMAPI_HANDLE_TABLE_SIZE)
+ inner -> leafp = 1;
+ table -> children [index].table = inner;
+ }
+
+ status = omapi_object_handle_in_table (h, inner, o);
+ if (status == ISC_R_NOSPACE) {
+ status = (omapi_handle_table_enclose
+ (&table -> children [index].table));
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ return omapi_object_handle_in_table
+ (h, table -> children [index].table, o);
+ }
+ return status;
+}
+
+static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **table)
+{
+ omapi_handle_table_t *inner = *table;
+ omapi_handle_table_t *new;
+ int index, base, scale;
+
+ /* The scale of the table we're enclosing is going to be the
+ difference between its "first" and "limit" members. So the
+ scale of the table enclosing it is going to be that multiplied
+ by the table size. */
+ scale = (inner -> first - inner -> limit) * OMAPI_HANDLE_TABLE_SIZE;
+
+ /* The range that the enclosing table covers is going to be
+ the result of subtracting the remainder of dividing the
+ enclosed table's first entry number by the enclosing
+ table's scale. If handle IDs are being allocated
+ sequentially, the enclosing table's "first" value will be
+ the same as the enclosed table's "first" value. */
+ base = inner -> first - inner -> first % scale;
+
+ /* The index into the enclosing table at which the enclosed table
+ will be stored is going to be the difference between the "first"
+ value of the enclosing table and the enclosed table - zero, if
+ we are allocating sequentially. */
+ index = (base - inner -> first) / OMAPI_HANDLE_TABLE_SIZE;
+
+ new = dmalloc (sizeof *new, MDL);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, sizeof *new);
+ new -> first = base;
+ new -> limit = base + scale;
+ if (scale == OMAPI_HANDLE_TABLE_SIZE)
+ new -> leafp = 0;
+ new -> children [index].table = inner;
+ *table = new;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_handle_lookup (omapi_object_t **o, omapi_handle_t h)
+{
+ return(omapi_handle_lookup_in(o, h, omapi_handle_table, FIND_HAND));
+}
+
+static isc_result_t omapi_handle_lookup_in (omapi_object_t **o,
+ omapi_handle_t h,
+ omapi_handle_table_t *table,
+ int op)
+{
+ omapi_handle_t scale, index;
+
+ if (!table || table->first > h || table->limit <= h)
+ return(ISC_R_NOTFOUND);
+
+ /* If this is a leaf table, just grab the object. */
+ if (table->leafp) {
+ /* Not there? */
+ if (!table->children[h - table->first].object)
+ return(ISC_R_NOTFOUND);
+ if (op == CLEAR_HAND) {
+ table->children[h - table->first].object = NULL;
+ return(ISC_R_SUCCESS);
+ } else {
+ return(omapi_object_reference
+ (o, table->children[h - table->first].object,
+ MDL));
+ }
+ }
+
+ /* Scale is the number of handles represented by each child of this
+ table. For a leaf table, scale would be 1. For a first level
+ of indirection, 120. For a second, 120 * 120. Et cetera. */
+ scale = (table->limit - table->first) / OMAPI_HANDLE_TABLE_SIZE;
+
+ /* So the next most direct table from this one that contains the
+ handle must be the subtable of this table whose index into this
+ table's array of children is the handle divided by the scale. */
+ index = (h - table->first) / scale;
+
+ return(omapi_handle_lookup_in(o, h, table->children[index].table, op));
+}
+
+/* For looking up objects based on handles that have been sent on the wire. */
+isc_result_t omapi_handle_td_lookup (omapi_object_t **obj,
+ omapi_typed_data_t *handle)
+{
+ omapi_handle_t h;
+
+ if (handle->type == omapi_datatype_int)
+ h = handle->u.integer;
+ else if (handle->type == omapi_datatype_data &&
+ handle->u.buffer.len == sizeof h) {
+ memcpy(&h, handle->u.buffer.value, sizeof h);
+ h = ntohl(h);
+ } else
+ return(DHCP_R_INVALIDARG);
+ return(omapi_handle_lookup(obj, h));
+}
+
+isc_result_t omapi_handle_clear(omapi_handle_t h)
+{
+ return(omapi_handle_lookup_in(NULL, h, omapi_handle_table, CLEAR_HAND));
+}
diff --git a/omapip/hash.c b/omapip/hash.c
new file mode 100644
index 0000000..b75d102
--- /dev/null
+++ b/omapip/hash.c
@@ -0,0 +1,560 @@
+/* hash.c
+
+ Routines for manipulating hash tables... */
+
+/*
+ * Copyright (c) 2009-2010,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+#include <limits.h>
+#include <ctype.h>
+
+static unsigned
+find_length(const void *key,
+ unsigned (*do_hash)(const void *, unsigned, unsigned))
+{
+ if (do_hash == do_case_hash || do_hash == do_string_hash)
+ return strlen((const char *)key);
+ if (do_hash == do_number_hash)
+ return sizeof(unsigned);
+ if (do_hash == do_ip4_hash)
+ return 4;
+
+ log_debug("Unexpected hash function at %s:%d.", MDL);
+ /*
+ * If we get a hash function we don't specifically expect
+ * return a length of 0, this covers the case where a client
+ * id has a length of 0.
+ */
+ return 0;
+}
+
+int new_hash_table (tp, count, file, line)
+ struct hash_table **tp;
+ unsigned count;
+ const char *file;
+ int line;
+{
+ struct hash_table *rval;
+ unsigned extra;
+
+ if (!tp) {
+ log_error ("%s(%d): new_hash_table called with null pointer.",
+ file, line);
+#if defined (POINTER_DEBUG)
+ abort ();
+#endif
+ return 0;
+ }
+ if (*tp) {
+ log_error ("%s(%d): non-null target for new_hash_table.",
+ file, line);
+#if defined (POINTER_DEBUG)
+ abort ();
+#endif
+ }
+
+ /* There is one hash bucket in the structure. Allocate extra
+ * memory beyond the end of the structure to fulfill the requested
+ * count ("count - 1"). Do not let there be less than one.
+ */
+ if (count <= 1)
+ extra = 0;
+ else
+ extra = count - 1;
+
+ rval = dmalloc(sizeof(struct hash_table) +
+ (extra * sizeof(struct hash_bucket *)), file, line);
+ if (!rval)
+ return 0;
+ rval -> hash_count = count;
+ *tp = rval;
+ return 1;
+}
+
+void free_hash_table (tp, file, line)
+ struct hash_table **tp;
+ const char *file;
+ int line;
+{
+ struct hash_table *ptr = *tp;
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ int i;
+ struct hash_bucket *hbc, *hbn = (struct hash_bucket *)0;
+
+ for (i = 0; i < ptr -> hash_count; i++) {
+ for (hbc = ptr -> buckets [i]; hbc; hbc = hbn) {
+ hbn = hbc -> next;
+ if (ptr -> dereferencer && hbc -> value)
+ (*ptr -> dereferencer) (&hbc -> value, MDL);
+ }
+ for (hbc = ptr -> buckets [i]; hbc; hbc = hbn) {
+ hbn = hbc -> next;
+ free_hash_bucket (hbc, MDL);
+ }
+ ptr -> buckets [i] = (struct hash_bucket *)0;
+ }
+#endif
+
+ dfree((void *)ptr, MDL);
+ *tp = (struct hash_table *)0;
+}
+
+struct hash_bucket *free_hash_buckets;
+
+#if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+struct hash_bucket *hash_bucket_hunks;
+
+void relinquish_hash_bucket_hunks ()
+{
+ struct hash_bucket *c, *n, **p;
+
+ /* Account for all the hash buckets on the free list. */
+ p = &free_hash_buckets;
+ for (c = free_hash_buckets; c; c = c -> next) {
+ for (n = hash_bucket_hunks; n; n = n -> next) {
+ if (c > n && c < n + 127) {
+ *p = c -> next;
+ n -> len++;
+ break;
+ }
+ }
+ /* If we didn't delete the hash bucket from the free list,
+ advance the pointer. */
+ if (!n)
+ p = &c -> next;
+ }
+
+ for (c = hash_bucket_hunks; c; c = n) {
+ n = c -> next;
+ if (c -> len != 126) {
+ log_info ("hashbucket %lx hash_buckets %d free %u",
+ (unsigned long)c, 127, c -> len);
+ }
+ dfree (c, MDL);
+ }
+}
+#endif
+
+struct hash_bucket *new_hash_bucket (file, line)
+ const char *file;
+ int line;
+{
+ struct hash_bucket *rval;
+ int i = 0;
+ if (!free_hash_buckets) {
+ rval = dmalloc (127 * sizeof (struct hash_bucket),
+ file, line);
+ if (!rval)
+ return rval;
+# if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ rval -> next = hash_bucket_hunks;
+ hash_bucket_hunks = rval;
+ hash_bucket_hunks -> len = 0;
+ i++;
+ rval++;
+#endif
+ for (; i < 127; i++) {
+ rval -> next = free_hash_buckets;
+ free_hash_buckets = rval;
+ rval++;
+ }
+ }
+ rval = free_hash_buckets;
+ free_hash_buckets = rval -> next;
+ return rval;
+}
+
+void free_hash_bucket (ptr, file, line)
+ struct hash_bucket *ptr;
+ const char *file;
+ int line;
+{
+#if defined (DEBUG_MALLOC_POOL)
+ struct hash_bucket *hp;
+
+ for (hp = free_hash_buckets; hp; hp = hp -> next) {
+ if (hp == ptr) {
+ log_error ("hash bucket freed twice!");
+ abort ();
+ }
+ }
+#endif
+ ptr -> next = free_hash_buckets;
+ free_hash_buckets = ptr;
+}
+
+int new_hash(struct hash_table **rp,
+ hash_reference referencer,
+ hash_dereference dereferencer,
+ unsigned hsize,
+ unsigned (*hasher)(const void *, unsigned, unsigned),
+ const char *file, int line)
+{
+ if (hsize == 0)
+ hsize = DEFAULT_HASH_SIZE;
+
+ if (!new_hash_table (rp, hsize, file, line))
+ return 0;
+
+ memset ((*rp)->buckets, 0, hsize * sizeof(struct hash_bucket *));
+
+ (*rp)->referencer = referencer;
+ (*rp)->dereferencer = dereferencer;
+ (*rp)->do_hash = hasher;
+
+ if (hasher == do_case_hash)
+ (*rp)->cmp = casecmp;
+ else
+ (*rp)->cmp = memcmp;
+
+ return 1;
+}
+
+unsigned
+do_case_hash(const void *name, unsigned len, unsigned size)
+{
+ register unsigned accum = 0;
+ register const unsigned char *s = name;
+ int i = len;
+ register unsigned c;
+
+ while (i--) {
+ /* Make the hash case-insensitive. */
+ c = *s++;
+ if (isascii(c))
+ c = tolower(c);
+
+ /* Add the character in... */
+ accum = (accum << 1) + c;
+
+ /* Add carry back in... */
+ while (accum > 65535) {
+ accum = (accum & 65535) + (accum >> 16);
+ }
+
+ }
+ return accum % size;
+}
+
+unsigned
+do_string_hash(const void *name, unsigned len, unsigned size)
+{
+ register unsigned accum = 0;
+ register const unsigned char *s = (const unsigned char *)name;
+ int i = len;
+
+ while (i--) {
+ /* Add the character in... */
+ accum = (accum << 1) + *s++;
+
+ /* Add carry back in... */
+ while (accum > 65535) {
+ accum = (accum & 65535) + (accum >> 16);
+ }
+ }
+ return accum % size;
+}
+
+/* Client identifiers are generally 32-bits of ordinary
+ * non-randomness followed by 24-bits of unordinary randomness.
+ * So, end-align in 24-bit chunks, and xor any preceding data
+ * just to mix it up a little.
+ */
+unsigned
+do_id_hash(const void *name, unsigned len, unsigned size)
+{
+ register unsigned accum = 0;
+ register const unsigned char *s = (const unsigned char *)name;
+ const unsigned char *end = s + len;
+
+ if (len == 0)
+ return 0;
+
+ /*
+ * The switch handles our starting conditions, then we hash the
+ * remaining bytes in groups of 3
+ */
+
+ switch (len % 3) {
+ case 0:
+ break;
+ case 2:
+ accum ^= *s++ << 8;
+ case 1:
+ accum ^= *s++;
+ break;
+ }
+
+ while (s < end) {
+ accum ^= *s++ << 16;
+ accum ^= *s++ << 8;
+ accum ^= *s++;
+ }
+
+ return accum % size;
+}
+
+unsigned
+do_number_hash(const void *key, unsigned len, unsigned size)
+{
+ register unsigned number = *((const unsigned *)key);
+
+ return number % size;
+}
+
+unsigned
+do_ip4_hash(const void *key, unsigned len, unsigned size)
+{
+ u_int32_t number;
+
+ memcpy(&number, key, 4);
+
+ number = ntohl(number);
+
+ return number % size;
+}
+
+unsigned char *
+hash_report(struct hash_table *table)
+{
+ static unsigned char retbuf[sizeof("Contents/Size (%): "
+ "2147483647/2147483647 "
+ "(2147483647%). "
+ "Min/max: 2147483647/2147483647")];
+ unsigned curlen, pct, contents=0, minlen=UINT_MAX, maxlen=0;
+ unsigned i;
+ struct hash_bucket *bp;
+
+ if (table == NULL)
+ return (unsigned char *) "No table.";
+
+ if (table->hash_count == 0)
+ return (unsigned char *) "Invalid hash table.";
+
+ for (i = 0 ; i < table->hash_count ; i++) {
+ curlen = 0;
+
+ bp = table->buckets[i];
+ while (bp != NULL) {
+ curlen++;
+ bp = bp->next;
+ }
+
+ if (curlen < minlen)
+ minlen = curlen;
+ if (curlen > maxlen)
+ maxlen = curlen;
+
+ contents += curlen;
+ }
+
+ if (contents >= (UINT_MAX / 100))
+ pct = contents / ((table->hash_count / 100) + 1);
+ else
+ pct = (contents * 100) / table->hash_count;
+
+ if (contents > 2147483647 ||
+ table->hash_count > 2147483647 ||
+ pct > 2147483647 ||
+ minlen > 2147483647 ||
+ maxlen > 2147483647)
+ return (unsigned char *) "Report out of range for display.";
+
+ sprintf((char *)retbuf,
+ "Contents/Size (%%): %u/%u (%u%%). Min/max: %u/%u",
+ contents, table->hash_count, pct, minlen, maxlen);
+
+ return retbuf;
+}
+
+void add_hash (table, key, len, pointer, file, line)
+ struct hash_table *table;
+ unsigned len;
+ const void *key;
+ hashed_object_t *pointer;
+ const char *file;
+ int line;
+{
+ int hashno;
+ struct hash_bucket *bp;
+ void *foo;
+
+ if (!table)
+ return;
+
+ if (!len)
+ len = find_length(key, table->do_hash);
+
+ hashno = (*table->do_hash)(key, len, table->hash_count);
+ bp = new_hash_bucket (file, line);
+
+ if (!bp) {
+ log_error ("Can't add entry to hash table: no memory.");
+ return;
+ }
+ bp -> name = key;
+ if (table -> referencer) {
+ foo = &bp -> value;
+ (*(table -> referencer)) (foo, pointer, file, line);
+ } else
+ bp -> value = pointer;
+ bp -> next = table -> buckets [hashno];
+ bp -> len = len;
+ table -> buckets [hashno] = bp;
+}
+
+void delete_hash_entry (table, key, len, file, line)
+ struct hash_table *table;
+ unsigned len;
+ const void *key;
+ const char *file;
+ int line;
+{
+ int hashno;
+ struct hash_bucket *bp, *pbp = (struct hash_bucket *)0;
+ void *foo;
+
+ if (!table)
+ return;
+
+ if (!len)
+ len = find_length(key, table->do_hash);
+
+ hashno = (*table->do_hash)(key, len, table->hash_count);
+
+ /* Go through the list looking for an entry that matches;
+ if we find it, delete it. */
+ for (bp = table -> buckets [hashno]; bp; bp = bp -> next) {
+ if ((!bp -> len &&
+ !strcmp ((const char *)bp->name, key)) ||
+ (bp -> len == len &&
+ !(table -> cmp)(bp->name, key, len))) {
+ if (pbp) {
+ pbp -> next = bp -> next;
+ } else {
+ table -> buckets [hashno] = bp -> next;
+ }
+ if (bp -> value && table -> dereferencer) {
+ foo = &bp -> value;
+ (*(table -> dereferencer)) (foo, file, line);
+ }
+ free_hash_bucket (bp, file, line);
+ break;
+ }
+ pbp = bp; /* jwg, 9/6/96 - nice catch! */
+ }
+}
+
+int hash_lookup (vp, table, key, len, file, line)
+ hashed_object_t **vp;
+ struct hash_table *table;
+ const void *key;
+ unsigned len;
+ const char *file;
+ int line;
+{
+ int hashno;
+ struct hash_bucket *bp;
+
+ if (!table)
+ return 0;
+ if (!len)
+ len = find_length(key, table->do_hash);
+
+ if (*vp != NULL) {
+ log_fatal("Internal inconsistency: storage value has not been "
+ "initialized to zero (from %s:%d).", file, line);
+ }
+
+ hashno = (*table->do_hash)(key, len, table->hash_count);
+
+ for (bp = table -> buckets [hashno]; bp; bp = bp -> next) {
+ if (len == bp -> len
+ && !(*table->cmp)(bp->name, key, len)) {
+ if (table -> referencer)
+ (*table -> referencer) (vp, bp -> value,
+ file, line);
+ else
+ *vp = bp -> value;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int hash_foreach (struct hash_table *table, hash_foreach_func func)
+{
+ int i;
+ struct hash_bucket *bp, *next;
+ int count = 0;
+
+ if (!table)
+ return 0;
+
+ for (i = 0; i < table -> hash_count; i++) {
+ bp = table -> buckets [i];
+ while (bp) {
+ next = bp -> next;
+ if ((*func)(bp->name, bp->len, bp->value)
+ != ISC_R_SUCCESS)
+ return count;
+ bp = next;
+ count++;
+ }
+ }
+ return count;
+}
+
+int casecmp (const void *v1, const void *v2, size_t len)
+{
+ size_t i;
+ const unsigned char *s = v1;
+ const unsigned char *t = v2;
+
+ for (i = 0; i < len; i++)
+ {
+ int c1, c2;
+ if (isascii(s[i]))
+ c1 = tolower(s[i]);
+ else
+ c1 = s[i];
+
+ if (isascii(t[i]))
+ c2 = tolower(t[i]);
+ else
+ c2 = t[i];
+
+ if (c1 < c2)
+ return -1;
+ if (c1 > c2)
+ return 1;
+ }
+ return 0;
+}
diff --git a/omapip/inet_addr.c b/omapip/inet_addr.c
new file mode 100644
index 0000000..611d9ee
--- /dev/null
+++ b/omapip/inet_addr.c
@@ -0,0 +1,135 @@
+/* $NetBSD: inet_addr.c,v 1.6 1996/02/02 15:22:23 mrg Exp $ */
+
+/*
+ * Copyright (c) 1983, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "dhcpd.h"
+
+#include "omapip/omapip_p.h"
+
+#ifdef NEED_INET_ATON
+/*
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+int
+inet_aton(cp, addr)
+ const char *cp;
+ struct in_addr *addr;
+{
+ register u_long val;
+ register int base, n;
+ register char c;
+ u_int parts[4];
+ register u_int *pp = parts;
+
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, other=decimal.
+ */
+ val = 0; base = 10;
+ if (*cp == '0') {
+ if (*++cp == 'x' || *cp == 'X')
+ base = 16, cp++;
+ else
+ base = 8;
+ }
+ while ((c = *cp) != '\0') {
+ if (isascii(c) && isdigit((int)c)) {
+ val = (val * base) + (c - '0');
+ cp++;
+ continue;
+ }
+ if (base == 16 && isascii(c) && isxdigit((int)c)) {
+ val = (val << 4) +
+ (c + 10 - (islower((int)c) ? 'a' : 'A'));
+ cp++;
+ continue;
+ }
+ break;
+ }
+ if (*cp == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16-bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3 || val > 0xff)
+ return (0);
+ *pp++ = val, cp++;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (*cp && (!isascii(*cp) || !isspace((int)*cp)))
+ return (0);
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n) {
+
+ case 0:
+ return (0); /* initial nondigit */
+
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffff)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr)
+ addr->s_addr = htonl(val);
+ return (1);
+}
+#endif
diff --git a/omapip/isclib.c b/omapip/isclib.c
new file mode 100644
index 0000000..ce42e45
--- /dev/null
+++ b/omapip/isclib.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright(c) 2009-2010,2013-2014 by Internet Systems Consortium, Inc.("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * http://www.isc.org/
+ *
+ */
+
+/*Trying to figure out what we need to define to get things to work.
+ It looks like we want/need the export library but need the fdwatchcommand
+ which may be a problem */
+
+#include "dhcpd.h"
+
+#include <sys/time.h>
+#include <signal.h>
+
+dhcp_context_t dhcp_gbl_ctx;
+int shutdown_signal = 0;
+
+void
+isclib_cleanup(void)
+{
+#if defined (NSUPDATE)
+ if (dhcp_gbl_ctx.dnsclient != NULL)
+ dns_client_destroy((dns_client_t **)&dhcp_gbl_ctx.dnsclient);
+#endif
+
+ if (dhcp_gbl_ctx.task != NULL) {
+ isc_task_shutdown(dhcp_gbl_ctx.task);
+ isc_task_detach(&dhcp_gbl_ctx.task);
+ }
+
+ if (dhcp_gbl_ctx.timermgr != NULL)
+ isc_timermgr_destroy(&dhcp_gbl_ctx.timermgr);
+
+ if (dhcp_gbl_ctx.socketmgr != NULL)
+ isc_socketmgr_destroy(&dhcp_gbl_ctx.socketmgr);
+
+ if (dhcp_gbl_ctx.taskmgr != NULL)
+ isc_taskmgr_destroy(&dhcp_gbl_ctx.taskmgr);
+
+ if (dhcp_gbl_ctx.actx_started != ISC_FALSE) {
+ isc_app_ctxfinish(dhcp_gbl_ctx.actx);
+ dhcp_gbl_ctx.actx_started = ISC_FALSE;
+ }
+
+ if (dhcp_gbl_ctx.actx != NULL)
+ isc_appctx_destroy(&dhcp_gbl_ctx.actx);
+
+ if (dhcp_gbl_ctx.mctx != NULL)
+ isc_mem_detach(&dhcp_gbl_ctx.mctx);
+
+ return;
+}
+
+/* Installs a handler for a signal using sigaction */
+static void
+handle_signal(int sig, void (*handler)(int)) {
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handler;
+ sigfillset(&sa.sa_mask);
+ if (sigaction(sig, &sa, NULL) != 0) {
+ log_debug("handle_signal() failed for signal %d error: %s",
+ sig, strerror(errno));
+ }
+}
+
+isc_result_t
+dhcp_context_create(void) {
+ isc_result_t result;
+
+ /*
+ * Set up the error messages, this isn't the right place
+ * for this call but it is convienent for now.
+ */
+ result = dhcp_result_register();
+ if (result != ISC_R_SUCCESS) {
+ log_fatal("register_table() %s: %u", "failed", result);
+ }
+
+ memset(&dhcp_gbl_ctx, 0, sizeof (dhcp_gbl_ctx));
+
+ isc_lib_register();
+
+ /* get the current time for use as the random seed */
+ gettimeofday(&cur_tv, (struct timezone *)0);
+ isc_random_seed(cur_tv.tv_sec);
+
+ /* we need to create the memory context before
+ * the lib inits in case we aren't doing NSUPDATE
+ * in which case dst needs a memory context
+ */
+ result = isc_mem_create(0, 0, &dhcp_gbl_ctx.mctx);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+#if defined (NSUPDATE)
+ result = dns_lib_init();
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+#else
+ /* The dst library is inited as part of dns_lib_init, we don't
+ * need it if NSUPDATE is enabled */
+ result = dst_lib_init(dhcp_gbl_ctx.mctx, NULL, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+#endif
+
+ result = isc_appctx_create(dhcp_gbl_ctx.mctx, &dhcp_gbl_ctx.actx);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = isc_app_ctxstart(dhcp_gbl_ctx.actx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dhcp_gbl_ctx.actx_started = ISC_TRUE;
+
+ /* Not all OSs support suppressing SIGPIPE through socket
+ * options, so set the sigal action to be ignore. This allows
+ * broken connections to fail gracefully with EPIPE on writes */
+ handle_signal(SIGPIPE, SIG_IGN);
+
+ result = isc_taskmgr_createinctx(dhcp_gbl_ctx.mctx,
+ dhcp_gbl_ctx.actx,
+ 1, 0,
+ &dhcp_gbl_ctx.taskmgr);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = isc_socketmgr_createinctx(dhcp_gbl_ctx.mctx,
+ dhcp_gbl_ctx.actx,
+ &dhcp_gbl_ctx.socketmgr);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = isc_timermgr_createinctx(dhcp_gbl_ctx.mctx,
+ dhcp_gbl_ctx.actx,
+ &dhcp_gbl_ctx.timermgr);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = isc_task_create(dhcp_gbl_ctx.taskmgr, 0, &dhcp_gbl_ctx.task);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+#if defined (NSUPDATE)
+ result = dns_client_createx(dhcp_gbl_ctx.mctx,
+ dhcp_gbl_ctx.actx,
+ dhcp_gbl_ctx.taskmgr,
+ dhcp_gbl_ctx.socketmgr,
+ dhcp_gbl_ctx.timermgr,
+ 0,
+ &dhcp_gbl_ctx.dnsclient);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+#endif
+ return(ISC_R_SUCCESS);
+
+ cleanup:
+ /*
+ * Currently we don't try and cleanup, just return an error
+ * expecting that our caller will log the error and exit.
+ */
+
+ return(result);
+}
+
+/*
+ * Convert a string name into the proper structure for the isc routines
+ *
+ * Previously we allowed names without a trailing '.' however the current
+ * dns and dst code requires the names to end in a period. If the
+ * name doesn't have a trailing period add one as part of creating
+ * the dns name.
+ */
+
+isc_result_t
+dhcp_isc_name(unsigned char *namestr,
+ dns_fixedname_t *namefix,
+ dns_name_t **name)
+{
+ size_t namelen;
+ isc_buffer_t b;
+ isc_result_t result;
+
+ namelen = strlen((char *)namestr);
+ isc_buffer_init(&b, namestr, namelen);
+ isc_buffer_add(&b, namelen);
+ dns_fixedname_init(namefix);
+ *name = dns_fixedname_name(namefix);
+ result = dns_name_fromtext(*name, &b, dns_rootname, 0, NULL);
+ isc_buffer_invalidate(&b);
+ return(result);
+}
+
+isc_result_t
+isclib_make_dst_key(char *inname,
+ char *algorithm,
+ unsigned char *secret,
+ int length,
+ dst_key_t **dstkey)
+{
+ isc_result_t result;
+ dns_name_t *name;
+ dns_fixedname_t name0;
+ isc_buffer_t b;
+ unsigned int algorithm_code;
+
+ isc_buffer_init(&b, secret, length);
+ isc_buffer_add(&b, length);
+
+ if (strcasecmp(algorithm, DHCP_HMAC_MD5_NAME) == 0) {
+ algorithm_code = DST_ALG_HMACMD5;
+ } else if (strcasecmp(algorithm, DHCP_HMAC_SHA1_NAME) == 0) {
+ algorithm_code = DST_ALG_HMACSHA1;
+ } else if (strcasecmp(algorithm, DHCP_HMAC_SHA224_NAME) == 0) {
+ algorithm_code = DST_ALG_HMACSHA224;
+ } else if (strcasecmp(algorithm, DHCP_HMAC_SHA256_NAME) == 0) {
+ algorithm_code = DST_ALG_HMACSHA256;
+ } else if (strcasecmp(algorithm, DHCP_HMAC_SHA384_NAME) == 0) {
+ algorithm_code = DST_ALG_HMACSHA384;
+ } else if (strcasecmp(algorithm, DHCP_HMAC_SHA512_NAME) == 0) {
+ algorithm_code = DST_ALG_HMACSHA512;
+ } else {
+ return(DHCP_R_INVALIDARG);
+ }
+
+ result = dhcp_isc_name((unsigned char *)inname, &name0, &name);
+ if (result != ISC_R_SUCCESS) {
+ return(result);
+ }
+
+ return(dst_key_frombuffer(name, algorithm_code, DNS_KEYOWNER_ENTITY,
+ DNS_KEYPROTO_DNSSEC, dns_rdataclass_in,
+ &b, dhcp_gbl_ctx.mctx, dstkey));
+}
+
+/**
+ * signal handler that initiates server shutdown
+ *
+ * @param signal signal code that we received
+ */
+void dhcp_signal_handler(int signal) {
+ isc_appctx_t *ctx = dhcp_gbl_ctx.actx;
+ int prev = shutdown_signal;
+
+ if (prev != 0) {
+ /* Already in shutdown. */
+ return;
+ }
+ /* Possible race but does it matter? */
+ shutdown_signal = signal;
+
+ /* Use reload (aka suspend) for easier dispatch() reenter. */
+ if (ctx && ctx->methods && ctx->methods->ctxsuspend) {
+ (void) isc_app_ctxsuspend(ctx);
+ }
+}
diff --git a/omapip/iscprint.c b/omapip/iscprint.c
new file mode 100644
index 0000000..dd75e9f
--- /dev/null
+++ b/omapip/iscprint.c
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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: iscprint.c,v 1.2 2005/03/17 20:30:41 dhankins Exp $ */
+
+#include "dhcpd.h"
+
+#ifdef NO_SNPRINTF
+
+#ifndef LINT
+static char copyright[] =
+"$Id: iscprint.c,v 1.2 2005/03/17 20:30:41 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium, Inc. All rights reserved.";
+#endif
+
+#define INSIST(cond) REQUIRE(cond)
+#define REQUIRE(cond) if (!(cond)) { return 0; }
+
+/*
+ * Return length of string that would have been written if not truncated.
+ */
+
+int
+isc_print_snprintf(char *str, size_t size, const char *format, ...) {
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return (ret);
+}
+
+/*
+ * Return length of string that would have been written if not truncated.
+ */
+
+int
+isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
+ int h;
+ int l;
+ int q;
+ int alt;
+ int zero;
+ int left;
+ int plus;
+ int space;
+ int neg;
+ isc_int64_t tmpi;
+ isc_uint64_t tmpui;
+ unsigned long width;
+ unsigned long precision;
+ unsigned int length;
+ char buf[1024];
+ char c;
+ void *v;
+ char *save = str;
+ const char *cp;
+ const char *head;
+ int count = 0;
+ int pad;
+ int zeropad;
+ int dot;
+ double dbl;
+#ifdef HAVE_LONG_DOUBLE
+ long double ldbl;
+#endif
+ char fmt[32];
+
+ INSIST(str != NULL);
+ INSIST(format != NULL);
+
+ while (*format != '\0') {
+ if (*format != '%') {
+ if (size > 1) {
+ *str++ = *format;
+ size--;
+ }
+ count++;
+ format++;
+ continue;
+ }
+ format++;
+
+ /*
+ * Reset flags.
+ */
+ dot = neg = space = plus = left = zero = alt = h = l = q = 0;
+ width = precision = 0;
+ head = "";
+ length = pad = zeropad = 0;
+
+ do {
+ if (*format == '#') {
+ alt = 1;
+ format++;
+ } else if (*format == '-') {
+ left = 1;
+ zero = 0;
+ format++;
+ } else if (*format == ' ') {
+ if (!plus)
+ space = 1;
+ format++;
+ } else if (*format == '+') {
+ plus = 1;
+ space = 0;
+ format++;
+ } else if (*format == '0') {
+ if (!left)
+ zero = 1;
+ format++;
+ } else
+ break;
+ } while (1);
+
+ /*
+ * Width.
+ */
+ if (*format == '*') {
+ width = va_arg(ap, int);
+ format++;
+ } else if (isdigit((unsigned char)*format)) {
+ char *e;
+ width = strtoul(format, &e, 10);
+ format = e;
+ }
+
+ /*
+ * Precision.
+ */
+ if (*format == '.') {
+ format++;
+ dot = 1;
+ if (*format == '*') {
+ precision = va_arg(ap, int);
+ format++;
+ } else if (isdigit((unsigned char)*format)) {
+ char *e;
+ precision = strtoul(format, &e, 10);
+ format = e;
+ }
+ }
+
+ switch (*format) {
+ case '\0':
+ continue;
+ case '%':
+ if (size > 1) {
+ *str++ = *format;
+ size--;
+ }
+ count++;
+ break;
+ case 'q':
+ q = 1;
+ format++;
+ goto doint;
+ case 'h':
+ h = 1;
+ format++;
+ goto doint;
+ case 'l':
+ l = 1;
+ format++;
+ if (*format == 'l') {
+ q = 1;
+ format++;
+ }
+ goto doint;
+ case 'n':
+ case 'i':
+ case 'd':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ doint:
+ if (precision != 0)
+ zero = 0;
+ switch (*format) {
+ case 'n':
+ if (h) {
+ short int *p;
+ p = va_arg(ap, short *);
+ REQUIRE(p != NULL);
+ *p = str - save;
+ } else if (l) {
+ long int *p;
+ p = va_arg(ap, long *);
+ REQUIRE(p != NULL);
+ *p = str - save;
+ } else {
+ int *p;
+ p = va_arg(ap, int *);
+ REQUIRE(p != NULL);
+ *p = str - save;
+ }
+ break;
+ case 'i':
+ case 'd':
+ if (q)
+ tmpi = va_arg(ap, isc_int64_t);
+ else if (l)
+ tmpi = va_arg(ap, long int);
+ else
+ tmpi = va_arg(ap, int);
+ if (tmpi < 0) {
+ head = "-";
+ tmpui = -tmpi;
+ } else {
+ if (plus)
+ head = "+";
+ else if (space)
+ head = " ";
+ else
+ head = "";
+ tmpui = tmpi;
+ }
+ sprintf(buf, "%u", tmpui);
+ goto printint;
+ case 'o':
+ if (q)
+ tmpui = va_arg(ap, isc_uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, long int);
+ else
+ tmpui = va_arg(ap, int);
+ sprintf(buf, alt ? "%#o"
+ : "%o", tmpui);
+ goto printint;
+ case 'u':
+ if (q)
+ tmpui = va_arg(ap, isc_uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ sprintf(buf, "%u", tmpui);
+ goto printint;
+ case 'x':
+ if (q)
+ tmpui = va_arg(ap, isc_uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ if (alt) {
+ head = "0x";
+ if (precision > 2)
+ precision -= 2;
+ }
+ sprintf(buf, "%x", tmpui);
+ goto printint;
+ case 'X':
+ if (q)
+ tmpui = va_arg(ap, isc_uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ if (alt) {
+ head = "0X";
+ if (precision > 2)
+ precision -= 2;
+ }
+ sprintf(buf, "%X", tmpui);
+ goto printint;
+ printint:
+ if (precision != 0 || width != 0) {
+ length = strlen(buf);
+ if (length < precision)
+ zeropad = precision - length;
+ else if (length < width && zero)
+ zeropad = width - length;
+ if (width != 0) {
+ pad = width - length -
+ zeropad - strlen(head);
+ if (pad < 0)
+ pad = 0;
+ }
+ }
+ count += strlen(head) + strlen(buf) + pad +
+ zeropad;
+ if (!left) {
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ }
+ cp = head;
+ while (*cp != '\0' && size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (zeropad > 0 && size > 1) {
+ *str++ = '0';
+ size--;
+ zeropad--;
+ }
+ cp = buf;
+ while (*cp != '\0' && size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case 's':
+ cp = va_arg(ap, char *);
+ REQUIRE(cp != NULL);
+
+ if (precision != 0) {
+ /*
+ * cp need not be NULL terminated.
+ */
+ const char *tp;
+ unsigned long n;
+
+ n = precision;
+ tp = cp;
+ while (n != 0 && *tp != '\0')
+ n--, tp++;
+ length = precision - n;
+ } else {
+ length = strlen(cp);
+ }
+ if (width != 0) {
+ pad = width - length;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += pad + length;
+ if (!left)
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ if (precision != 0)
+ while (precision > 0 && *cp != '\0' &&
+ size > 1) {
+ *str++ = *cp++;
+ size--;
+ precision--;
+ }
+ else
+ while (*cp != '\0' && size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ case 'c':
+ c = va_arg(ap, int);
+ if (width > 0) {
+ count += width;
+ width--;
+ if (left) {
+ *str++ = c;
+ size--;
+ }
+ while (width-- > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ }
+ if (!left && size > 1) {
+ *str++ = c;
+ size--;
+ }
+ } else {
+ count++;
+ if (size > 1) {
+ *str++ = c;
+ size--;
+ }
+ }
+ break;
+ case 'p':
+ v = va_arg(ap, void *);
+ sprintf(buf, "%p", v);
+ length = strlen(buf);
+ if (precision > length)
+ zeropad = precision - length;
+ if (width > 0) {
+ pad = width - length - zeropad;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += length + pad + zeropad;
+ if (!left)
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ cp = buf;
+ if (zeropad > 0 && buf[0] == '0' &&
+ (buf[1] == 'x' || buf[1] == 'X')) {
+ if (size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ if (size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (zeropad > 0 && size > 1) {
+ *str++ = '0';
+ size--;
+ zeropad--;
+ }
+ }
+ while (*cp != '\0' && size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ case 'D': /*deprecated*/
+ INSIST("use %ld instead of %D" == NULL);
+ case 'O': /*deprecated*/
+ INSIST("use %lo instead of %O" == NULL);
+ case 'U': /*deprecated*/
+ INSIST("use %lu instead of %U" == NULL);
+
+ case 'L':
+#ifdef HAVE_LONG_DOUBLE
+ l = 1;
+#else
+ INSIST("long doubles are not supported" == NULL);
+#endif
+ /*FALLTHROUGH*/
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (!dot)
+ precision = 6;
+ /*
+ * IEEE floating point.
+ * MIN 2.2250738585072014E-308
+ * MAX 1.7976931348623157E+308
+ * VAX floating point has a smaller range than IEEE.
+ *
+ * precisions > 324 don't make much sense.
+ * if we cap the precision at 512 we will not
+ * overflow buf.
+ */
+ if (precision > 512)
+ precision = 512;
+ sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
+ plus ? "+" : space ? " " : "",
+ precision, l ? "L" : "", *format);
+ switch (*format) {
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+#ifdef HAVE_LONG_DOUBLE
+ if (l) {
+ ldbl = va_arg(ap, long double);
+ sprintf(buf, fmt, ldbl);
+ } else
+#endif
+ {
+ dbl = va_arg(ap, double);
+ sprintf(buf, fmt, dbl);
+ }
+ length = strlen(buf);
+ if (width > 0) {
+ pad = width - length;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += length + pad;
+ if (!left)
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ cp = buf;
+ while (*cp != ' ' && size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ format++;
+ }
+ if (size > 0)
+ *str = '\0';
+ return (count);
+}
+
+#endif
diff --git a/omapip/listener.c b/omapip/listener.c
new file mode 100644
index 0000000..8bdcdbd
--- /dev/null
+++ b/omapip/listener.c
@@ -0,0 +1,484 @@
+/* listener.c
+
+ Subroutines that support the generic listener object. */
+
+/*
+ * Copyright (c) 2012,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+#include <errno.h>
+
+#if defined (TRACING)
+omapi_array_t *trace_listeners;
+static void trace_listener_accept_input (trace_type_t *, unsigned, char *);
+static void trace_listener_remember (omapi_listener_object_t *,
+ const char *, int);
+static void trace_listener_accept_stop (trace_type_t *);
+trace_type_t *trace_listener_accept;
+#endif
+
+OMAPI_OBJECT_ALLOC (omapi_listener,
+ omapi_listener_object_t, omapi_type_listener)
+
+isc_result_t omapi_listen (omapi_object_t *h,
+ unsigned port,
+ int max)
+{
+ omapi_addr_t addr;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_listen(port=%d, max=%d)", port, max);
+#endif
+
+ addr.addrtype = AF_INET;
+ addr.addrlen = sizeof (struct in_addr);
+ memset (addr.address, 0, sizeof addr.address); /* INADDR_ANY */
+ addr.port = port;
+
+ return omapi_listen_addr (h, &addr, max);
+}
+
+isc_result_t omapi_listen_addr (omapi_object_t *h,
+ omapi_addr_t *addr,
+ int max)
+{
+ isc_result_t status;
+ omapi_listener_object_t *obj;
+ int i;
+
+ /* Currently only support IPv4 addresses. */
+ if (addr->addrtype != AF_INET)
+ return DHCP_R_INVALIDARG;
+
+ /* Get the handle. */
+ obj = (omapi_listener_object_t *)0;
+ status = omapi_listener_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ /*
+ * we could simply return here but by going to
+ * error_exit we keep the code check tools happy
+ * without removing the NULL check on obj at
+ * the exit, which we could skip curently but
+ * might want in the future.
+ */
+ goto error_exit;
+ obj->socket = -1;
+
+ /* Connect this object to the inner object. */
+ status = omapi_object_reference (&h -> outer,
+ (omapi_object_t *)obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ goto error_exit;
+ status = omapi_object_reference (&obj -> inner, h, MDL);
+ if (status != ISC_R_SUCCESS)
+ goto error_exit;
+
+ /* Set up the address on which we will listen... */
+ obj -> address.sin_port = htons (addr -> port);
+ memcpy (&obj -> address.sin_addr,
+ addr -> address, sizeof obj -> address.sin_addr);
+#if defined (HAVE_SA_LEN)
+ obj -> address.sin_len =
+ sizeof (struct sockaddr_in);
+#endif
+ obj -> address.sin_family = AF_INET;
+ memset (&(obj -> address.sin_zero), 0,
+ sizeof obj -> address.sin_zero);
+
+#if defined (TRACING)
+ /* If we're playing back a trace file, we remember the object
+ on the trace listener queue. */
+ if (trace_playback ()) {
+ trace_listener_remember (obj, MDL);
+ } else {
+#endif
+ /* Create a socket on which to listen. */
+ obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (obj->socket == -1) {
+ if (errno == EMFILE
+ || errno == ENFILE || errno == ENOBUFS)
+ status = ISC_R_NORESOURCES;
+ else
+ status = ISC_R_UNEXPECTED;
+ goto error_exit;
+ }
+
+#if defined (HAVE_SETFD)
+ if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
+ status = ISC_R_UNEXPECTED;
+ goto error_exit;
+ }
+#endif
+
+ /* Set the REUSEADDR option so that we don't fail to start if
+ we're being restarted. */
+ i = 1;
+ if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&i, sizeof i) < 0) {
+ status = ISC_R_UNEXPECTED;
+ goto error_exit;
+ }
+
+ /* Try to bind to the wildcard address using the port number
+ we were given. */
+ i = bind (obj -> socket,
+ (struct sockaddr *)&obj -> address,
+ sizeof obj -> address);
+ if (i < 0) {
+ if (errno == EADDRINUSE)
+ status = ISC_R_ADDRNOTAVAIL;
+ else if (errno == EPERM)
+ status = ISC_R_NOPERM;
+ else
+ status = ISC_R_UNEXPECTED;
+ goto error_exit;
+ }
+
+ /* Now tell the kernel to listen for connections. */
+ if (listen (obj -> socket, max)) {
+ status = ISC_R_UNEXPECTED;
+ goto error_exit;
+ }
+
+ if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
+ status = ISC_R_UNEXPECTED;
+ goto error_exit;
+ }
+
+ status = omapi_register_io_object ((omapi_object_t *)obj,
+ omapi_listener_readfd, 0,
+ omapi_accept, 0, 0);
+#if defined (TRACING)
+ }
+#endif
+
+ omapi_listener_dereference (&obj, MDL);
+ return status;
+
+error_exit:
+ if (obj != NULL) {
+ if (h->outer == (omapi_object_t *)obj) {
+ omapi_object_dereference((omapi_object_t **)&h->outer,
+ MDL);
+ }
+ if (obj->inner == h) {
+ omapi_object_dereference((omapi_object_t **)&obj->inner,
+ MDL);
+ }
+ if (obj->socket != -1) {
+ close(obj->socket);
+ }
+ omapi_listener_dereference(&obj, MDL);
+ }
+ return status;
+}
+
+/* Return the socket on which the dispatcher should wait for readiness
+ to read, for a listener object. */
+int omapi_listener_readfd (omapi_object_t *h)
+{
+ omapi_listener_object_t *l;
+
+ if (h -> type != omapi_type_listener)
+ return -1;
+ l = (omapi_listener_object_t *)h;
+
+ return l -> socket;
+}
+
+/* Reader callback for a listener object. Accept an incoming connection. */
+isc_result_t omapi_accept (omapi_object_t *h)
+{
+ isc_result_t status;
+ socklen_t len;
+ omapi_connection_object_t *obj;
+ omapi_listener_object_t *listener;
+ struct sockaddr_in addr;
+ int socket;
+
+ if (h -> type != omapi_type_listener)
+ return DHCP_R_INVALIDARG;
+ listener = (omapi_listener_object_t *)h;
+
+ /* Accept the connection. */
+ len = sizeof addr;
+ socket = accept (listener -> socket,
+ ((struct sockaddr *)&(addr)), &len);
+ if (socket < 0) {
+ if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
+ return ISC_R_NORESOURCES;
+ return ISC_R_UNEXPECTED;
+ }
+
+#if defined (TRACING)
+ /* If we're recording a trace, remember the connection. */
+ if (trace_record ()) {
+ trace_iov_t iov [3];
+ iov [0].buf = (char *)&addr.sin_port;
+ iov [0].len = sizeof addr.sin_port;
+ iov [1].buf = (char *)&addr.sin_addr;
+ iov [1].len = sizeof addr.sin_addr;
+ iov [2].buf = (char *)&listener -> address.sin_port;
+ iov [2].len = sizeof listener -> address.sin_port;
+ trace_write_packet_iov (trace_listener_accept,
+ 3, iov, MDL);
+ }
+#endif
+
+ obj = (omapi_connection_object_t *)0;
+ status = omapi_listener_connect (&obj, listener, socket, &addr);
+ if (status != ISC_R_SUCCESS) {
+ close (socket);
+ return status;
+ }
+
+ status = omapi_register_io_object ((omapi_object_t *)obj,
+ omapi_connection_readfd,
+ omapi_connection_writefd,
+ omapi_connection_reader,
+ omapi_connection_writer,
+ omapi_connection_reaper);
+
+ /* Lose our reference to the connection, so it'll be gc'd when it's
+ reaped. */
+ omapi_connection_dereference (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ omapi_disconnect ((omapi_object_t *)(obj), 1);
+ return status;
+}
+
+isc_result_t omapi_listener_connect (omapi_connection_object_t **obj,
+ omapi_listener_object_t *listener,
+ int socket,
+ struct sockaddr_in *remote_addr)
+{
+ isc_result_t status;
+ omapi_object_t *h = (omapi_object_t *)listener;
+ omapi_addr_t addr;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_accept()");
+#endif
+
+ /* Get the handle. */
+ status = omapi_connection_allocate (obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ (*obj) -> state = omapi_connection_connected;
+ (*obj) -> remote_addr = *remote_addr;
+ (*obj) -> socket = socket;
+
+ /* Verify that this host is allowed to connect. */
+ if (listener -> verify_addr) {
+ addr.addrtype = AF_INET;
+ addr.addrlen = sizeof (remote_addr -> sin_addr);
+ memcpy (addr.address, &remote_addr -> sin_addr,
+ sizeof (remote_addr -> sin_addr));
+ addr.port = ntohs(remote_addr -> sin_port);
+
+ status = (listener -> verify_addr) (h, &addr);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect ((omapi_object_t *)(*obj), 1);
+ omapi_connection_dereference (obj, MDL);
+ return status;
+ }
+ }
+
+ omapi_listener_reference (&(*obj) -> listener, listener, MDL);
+#if defined (TRACING)
+ omapi_connection_register (*obj, MDL);
+#endif
+ status = omapi_signal (h, "connect", (*obj));
+ return status;
+}
+
+#if defined (TRACING)
+OMAPI_ARRAY_TYPE(omapi_listener, omapi_listener_object_t)
+
+void omapi_listener_trace_setup (void) {
+ trace_listener_accept =
+ trace_type_register ("listener-accept", (void *)0,
+ trace_listener_accept_input,
+ trace_listener_accept_stop, MDL);
+}
+
+static void trace_listener_remember (omapi_listener_object_t *obj,
+ const char *file, int line)
+{
+ isc_result_t status;
+ if (!trace_listeners) {
+ status = omapi_listener_array_allocate (&trace_listeners,
+ file, line);
+ if (status != ISC_R_SUCCESS) {
+ foo:
+ log_error ("trace_listener_remember: %s",
+ isc_result_totext (status));
+ return;
+ }
+ }
+ status = omapi_listener_array_extend (trace_listeners, obj,
+ &obj -> index, MDL);
+ if (status != ISC_R_SUCCESS)
+ goto foo;
+}
+
+static void trace_listener_accept_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ struct in_addr *addr;
+ u_int16_t *remote_port;
+ u_int16_t *local_port;
+ omapi_connection_object_t *obj;
+ isc_result_t status;
+ struct sockaddr_in remote_addr;
+
+ addr = (struct in_addr *)buf;
+ remote_port = (u_int16_t *)(addr + 1);
+ local_port = remote_port + 1;
+
+ memset (&remote_addr, 0, sizeof remote_addr);
+ remote_addr.sin_addr = *addr;
+ remote_addr.sin_port = *remote_port;
+
+ omapi_array_foreach_begin (trace_listeners,
+ omapi_listener_object_t, lp) {
+ if (lp -> address.sin_port == *local_port) {
+ obj = (omapi_connection_object_t *)0;
+ status = omapi_listener_connect (&obj,
+ lp, 0, &remote_addr);
+ if (status != ISC_R_SUCCESS) {
+ log_error("%s:%d: OMAPI: Failed to connect "
+ "a listener.", MDL);
+ }
+ omapi_listener_dereference (&lp, MDL);
+ return;
+ }
+ } omapi_array_foreach_end (trace_listeners,
+ omapi_listener_object_t, lp);
+ log_error ("trace_listener_accept: %s from %s/%d to port %d",
+ "unexpected connect",
+ inet_ntoa (*addr), *remote_port, *local_port);
+}
+
+static void trace_listener_accept_stop (trace_type_t *ttype) { }
+
+
+#endif
+
+isc_result_t omapi_listener_configure_security (omapi_object_t *h,
+ isc_result_t (*verify_addr)
+ (omapi_object_t *,
+ omapi_addr_t *))
+{
+ omapi_listener_object_t *l;
+
+ if (h -> type != omapi_type_listener)
+ return DHCP_R_INVALIDARG;
+ l = (omapi_listener_object_t *)h;
+
+ l -> verify_addr = verify_addr;
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_listener_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ if (h -> type != omapi_type_listener)
+ return DHCP_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> set_value)
+ return (*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_listener_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ if (h -> type != omapi_type_listener)
+ return DHCP_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_listener_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_listener_object_t *l;
+
+ if (h -> type != omapi_type_listener)
+ return DHCP_R_INVALIDARG;
+ l = (omapi_listener_object_t *)h;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_listener_destroy()");
+#endif
+
+ if (l -> socket != -1) {
+ close (l -> socket);
+ l -> socket = -1;
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_listener_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ if (h -> type != omapi_type_listener)
+ return DHCP_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_listener_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *l)
+{
+ if (l -> type != omapi_type_listener)
+ return DHCP_R_INVALIDARG;
+
+ if (l -> inner && l -> inner -> type -> stuff_values)
+ return (*(l -> inner -> type -> stuff_values)) (c, id,
+ l -> inner);
+ return ISC_R_SUCCESS;
+}
+
diff --git a/omapip/message.c b/omapip/message.c
new file mode 100644
index 0000000..59ccdc2
--- /dev/null
+++ b/omapip/message.c
@@ -0,0 +1,762 @@
+/* message.c
+
+ Subroutines for dealing with message objects. */
+
+/*
+ * Copyright (c) 2004,2007,2009,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+
+OMAPI_OBJECT_ALLOC (omapi_message,
+ omapi_message_object_t, omapi_type_message)
+
+omapi_message_object_t *omapi_registered_messages;
+
+isc_result_t omapi_message_new (omapi_object_t **o, const char *file, int line)
+{
+ omapi_message_object_t *m;
+ omapi_object_t *g;
+ isc_result_t status;
+
+ m = (omapi_message_object_t *)0;
+ status = omapi_message_allocate (&m, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ g = (omapi_object_t *)0;
+ status = omapi_generic_new (&g, file, line);
+ if (status != ISC_R_SUCCESS) {
+ dfree (m, file, line);
+ return status;
+ }
+ status = omapi_object_reference (&m -> inner, g, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&m, file, line);
+ omapi_object_dereference (&g, file, line);
+ return status;
+ }
+ status = omapi_object_reference (&g -> outer,
+ (omapi_object_t *)m, file, line);
+
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&m, file, line);
+ omapi_object_dereference (&g, file, line);
+ return status;
+ }
+
+ status = omapi_object_reference (o, (omapi_object_t *)m, file, line);
+ omapi_message_dereference (&m, file, line);
+ omapi_object_dereference (&g, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ return status;
+}
+
+isc_result_t omapi_message_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ omapi_message_object_t *m;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_message)
+ return DHCP_R_INVALIDARG;
+ m = (omapi_message_object_t *)h;
+
+ /* Can't set authlen. */
+
+ /* Can set authenticator, but the value must be typed data. */
+ if (!omapi_ds_strcmp (name, "authenticator")) {
+ if (m -> authenticator)
+ omapi_typed_data_dereference (&m -> authenticator,
+ MDL);
+ omapi_typed_data_reference (&m -> authenticator, value, MDL);
+ return ISC_R_SUCCESS;
+
+ } else if (!omapi_ds_strcmp (name, "object")) {
+ if (value -> type != omapi_datatype_object)
+ return DHCP_R_INVALIDARG;
+ if (m -> object)
+ omapi_object_dereference (&m -> object, MDL);
+ omapi_object_reference (&m -> object, value -> u.object, MDL);
+ return ISC_R_SUCCESS;
+
+ } else if (!omapi_ds_strcmp (name, "notify-object")) {
+ if (value -> type != omapi_datatype_object)
+ return DHCP_R_INVALIDARG;
+ if (m -> notify_object)
+ omapi_object_dereference (&m -> notify_object, MDL);
+ omapi_object_reference (&m -> notify_object,
+ value -> u.object, MDL);
+ return ISC_R_SUCCESS;
+
+ /* Can set authid, but it has to be an integer. */
+ } else if (!omapi_ds_strcmp (name, "authid")) {
+ if (value -> type != omapi_datatype_int)
+ return DHCP_R_INVALIDARG;
+ m -> authid = value -> u.integer;
+ return ISC_R_SUCCESS;
+
+ /* Can set op, but it has to be an integer. */
+ } else if (!omapi_ds_strcmp (name, "op")) {
+ if (value -> type != omapi_datatype_int)
+ return DHCP_R_INVALIDARG;
+ m -> op = value -> u.integer;
+ return ISC_R_SUCCESS;
+
+ /* Handle also has to be an integer. */
+ } else if (!omapi_ds_strcmp (name, "handle")) {
+ if (value -> type != omapi_datatype_int)
+ return DHCP_R_INVALIDARG;
+ m -> h = value -> u.integer;
+ return ISC_R_SUCCESS;
+
+ /* Transaction ID has to be an integer. */
+ } else if (!omapi_ds_strcmp (name, "id")) {
+ if (value -> type != omapi_datatype_int)
+ return DHCP_R_INVALIDARG;
+ m -> id = value -> u.integer;
+ return ISC_R_SUCCESS;
+
+ /* Remote transaction ID has to be an integer. */
+ } else if (!omapi_ds_strcmp (name, "rid")) {
+ if (value -> type != omapi_datatype_int)
+ return DHCP_R_INVALIDARG;
+ m -> rid = value -> u.integer;
+ return ISC_R_SUCCESS;
+ }
+
+ /* Try to find some inner object that can take the value. */
+ if (h -> inner && h -> inner -> type -> set_value) {
+ status = ((*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value));
+ if (status == ISC_R_SUCCESS)
+ return status;
+ }
+
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_message_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ omapi_message_object_t *m;
+ if (h -> type != omapi_type_message)
+ return DHCP_R_INVALIDARG;
+ m = (omapi_message_object_t *)h;
+
+ /* Look for values that are in the message data structure. */
+ if (!omapi_ds_strcmp (name, "authlen"))
+ return omapi_make_int_value (value, name, (int)m -> authlen,
+ MDL);
+ else if (!omapi_ds_strcmp (name, "authenticator")) {
+ if (m -> authenticator)
+ return omapi_make_value (value, name,
+ m -> authenticator, MDL);
+ else
+ return ISC_R_NOTFOUND;
+ } else if (!omapi_ds_strcmp (name, "authid")) {
+ return omapi_make_int_value (value,
+ name, (int)m -> authid, MDL);
+ } else if (!omapi_ds_strcmp (name, "op")) {
+ return omapi_make_int_value (value, name, (int)m -> op, MDL);
+ } else if (!omapi_ds_strcmp (name, "handle")) {
+ return omapi_make_int_value (value, name, (int)m -> h, MDL);
+ } else if (!omapi_ds_strcmp (name, "id")) {
+ return omapi_make_int_value (value, name, (int)m -> id, MDL);
+ } else if (!omapi_ds_strcmp (name, "rid")) {
+ return omapi_make_int_value (value, name, (int)m -> rid, MDL);
+ }
+
+ /* See if there's an inner object that has the value. */
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_message_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_message_object_t *m;
+ if (h -> type != omapi_type_message)
+ return DHCP_R_INVALIDARG;
+ m = (omapi_message_object_t *)h;
+ if (m -> authenticator) {
+ omapi_typed_data_dereference (&m -> authenticator, file, line);
+ }
+ if (!m -> prev && omapi_registered_messages != m)
+ omapi_message_unregister (h);
+ if (m -> id_object)
+ omapi_object_dereference (&m -> id_object, file, line);
+ if (m -> object)
+ omapi_object_dereference (&m -> object, file, line);
+ if (m -> notify_object)
+ omapi_object_dereference (&m -> notify_object, file, line);
+ if (m -> protocol_object)
+ omapi_protocol_dereference (&m -> protocol_object, file, line);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_message_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ omapi_message_object_t *m;
+ if (h -> type != omapi_type_message)
+ return DHCP_R_INVALIDARG;
+ m = (omapi_message_object_t *)h;
+
+ if (!strcmp (name, "status")) {
+ if (m -> notify_object &&
+ m -> notify_object -> type -> signal_handler)
+ return ((m -> notify_object -> type -> signal_handler))
+ (m -> notify_object, name, ap);
+ else if (m -> object && m -> object -> type -> signal_handler)
+ return ((m -> object -> type -> signal_handler))
+ (m -> object, name, ap);
+ }
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_message_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *m)
+{
+ if (m -> type != omapi_type_message)
+ return DHCP_R_INVALIDARG;
+
+ if (m -> inner && m -> inner -> type -> stuff_values)
+ return (*(m -> inner -> type -> stuff_values)) (c, id,
+ m -> inner);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_message_register (omapi_object_t *mo)
+{
+ omapi_message_object_t *m;
+
+ if (mo -> type != omapi_type_message)
+ return DHCP_R_INVALIDARG;
+ m = (omapi_message_object_t *)mo;
+
+ /* Already registered? */
+ if (m -> prev || m -> next || omapi_registered_messages == m)
+ return DHCP_R_INVALIDARG;
+
+ if (omapi_registered_messages) {
+ omapi_object_reference
+ ((omapi_object_t **)&m -> next,
+ (omapi_object_t *)omapi_registered_messages, MDL);
+ omapi_object_reference
+ ((omapi_object_t **)&omapi_registered_messages -> prev,
+ (omapi_object_t *)m, MDL);
+ omapi_object_dereference
+ ((omapi_object_t **)&omapi_registered_messages, MDL);
+ }
+ omapi_object_reference
+ ((omapi_object_t **)&omapi_registered_messages,
+ (omapi_object_t *)m, MDL);
+ return ISC_R_SUCCESS;;
+}
+
+isc_result_t omapi_message_unregister (omapi_object_t *mo)
+{
+ omapi_message_object_t *m;
+ omapi_message_object_t *n;
+
+ if (mo -> type != omapi_type_message)
+ return DHCP_R_INVALIDARG;
+ m = (omapi_message_object_t *)mo;
+
+ /* Not registered? */
+ if (!m -> prev && omapi_registered_messages != m)
+ return DHCP_R_INVALIDARG;
+
+ n = (omapi_message_object_t *)0;
+ if (m -> next) {
+ omapi_object_reference ((omapi_object_t **)&n,
+ (omapi_object_t *)m -> next, MDL);
+ omapi_object_dereference ((omapi_object_t **)&m -> next, MDL);
+ omapi_object_dereference ((omapi_object_t **)&n -> prev, MDL);
+ }
+ if (m -> prev) {
+ omapi_message_object_t *tmp = (omapi_message_object_t *)0;
+ omapi_object_reference ((omapi_object_t **)&tmp,
+ (omapi_object_t *)m -> prev, MDL);
+ omapi_object_dereference ((omapi_object_t **)&m -> prev, MDL);
+ if (tmp -> next)
+ omapi_object_dereference
+ ((omapi_object_t **)&tmp -> next, MDL);
+ if (n)
+ omapi_object_reference
+ ((omapi_object_t **)&tmp -> next,
+ (omapi_object_t *)n, MDL);
+ omapi_object_dereference ((omapi_object_t **)&tmp, MDL);
+ } else {
+ omapi_object_dereference
+ ((omapi_object_t **)&omapi_registered_messages, MDL);
+ if (n)
+ omapi_object_reference
+ ((omapi_object_t **)&omapi_registered_messages,
+ (omapi_object_t *)n, MDL);
+ }
+ if (n)
+ omapi_object_dereference ((omapi_object_t **)&n, MDL);
+ return ISC_R_SUCCESS;
+}
+
+#ifdef DEBUG_PROTOCOL
+static const char *omapi_message_op_name(int op) {
+ switch (op) {
+ case OMAPI_OP_OPEN: return "OMAPI_OP_OPEN";
+ case OMAPI_OP_REFRESH: return "OMAPI_OP_REFRESH";
+ case OMAPI_OP_UPDATE: return "OMAPI_OP_UPDATE";
+ case OMAPI_OP_STATUS: return "OMAPI_OP_STATUS";
+ case OMAPI_OP_DELETE: return "OMAPI_OP_DELETE";
+ case OMAPI_OP_NOTIFY: return "OMAPI_OP_NOTIFY";
+ default: return "(unknown op)";
+ }
+}
+#endif
+
+static isc_result_t
+omapi_message_process_internal (omapi_object_t *, omapi_object_t *);
+
+isc_result_t omapi_message_process (omapi_object_t *mo, omapi_object_t *po)
+{
+ isc_result_t status;
+#if defined (DEBUG_MEMORY_LEAKAGE) && 0
+ unsigned long previous_outstanding = dmalloc_outstanding;
+#endif
+
+ status = omapi_message_process_internal (mo, po);
+
+#if defined (DEBUG_MEMORY_LEAKAGE) && 0
+ log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
+ dmalloc_generation,
+ dmalloc_outstanding - previous_outstanding,
+ dmalloc_outstanding, dmalloc_longterm);
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE) && 0
+ dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) && 0
+ dump_rc_history ();
+#endif
+
+ return status;
+}
+
+static isc_result_t
+omapi_message_process_internal (omapi_object_t *mo, omapi_object_t *po)
+{
+ omapi_message_object_t *message, *m;
+ omapi_object_t *object = (omapi_object_t *)0;
+ omapi_value_t *tv = (omapi_value_t *)0;
+ unsigned long create, update, exclusive;
+ unsigned long wsi;
+ isc_result_t status, waitstatus;
+ omapi_object_type_t *type;
+
+ if (mo -> type != omapi_type_message)
+ return DHCP_R_INVALIDARG;
+ message = (omapi_message_object_t *)mo;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_message_process(): "
+ "op=%s handle=%#x id=%#x rid=%#x",
+ omapi_message_op_name (message -> op),
+ message -> h, message -> id, message -> rid);
+#endif
+
+ if (message -> rid) {
+ for (m = omapi_registered_messages; m; m = m -> next)
+ if (m -> id == message -> rid)
+ break;
+ /* If we don't have a real message corresponding to
+ the message ID to which this message claims it is a
+ response, something's fishy. */
+ if (!m)
+ return ISC_R_NOTFOUND;
+ /* The authenticator on responses must match the initial
+ message. */
+ if (message -> authid != m -> authid)
+ return ISC_R_NOTFOUND;
+ } else {
+ m = (omapi_message_object_t *)0;
+
+ /* All messages must have an authenticator, with the exception
+ of messages that are opening a new authenticator. */
+ if (omapi_protocol_authenticated(po) &&
+ !message->id_object &&
+ message->op != OMAPI_OP_OPEN) {
+ return omapi_protocol_send_status
+ (po, message->id_object, DHCP_R_NOKEYS,
+ message->id, "No authenticator on message");
+ }
+ }
+
+ switch (message -> op) {
+ case OMAPI_OP_OPEN:
+ if (m) {
+ return omapi_protocol_send_status
+ (po, message->id_object, DHCP_R_INVALIDARG,
+ message->id, "OPEN can't be a response");
+ }
+
+ /* Get the type of the requested object, if one was
+ specified. */
+ status = omapi_get_value_str (mo, message -> id_object,
+ "type", &tv);
+ if (status == ISC_R_SUCCESS &&
+ (tv -> value -> type == omapi_datatype_data ||
+ tv -> value -> type == omapi_datatype_string)) {
+ for (type = omapi_object_types;
+ type; type = type -> next)
+ if (!omapi_td_strcmp (tv -> value,
+ type -> name))
+ break;
+ } else
+ type = (omapi_object_type_t *)0;
+ if (tv)
+ omapi_value_dereference (&tv, MDL);
+
+ /* If this object had no authenticator, the requested object
+ must be an authenticator object. */
+ if (omapi_protocol_authenticated(po) &&
+ !message->id_object &&
+ type != omapi_type_auth_key) {
+ return omapi_protocol_send_status
+ (po, message->id_object, DHCP_R_NOKEYS,
+ message->id, "No authenticator on message");
+ }
+
+ /* Get the create flag. */
+ status = omapi_get_value_str (mo, message -> id_object,
+ "create", &tv);
+ if (status == ISC_R_SUCCESS) {
+ status = omapi_get_int_value (&create, tv -> value);
+ omapi_value_dereference (&tv, MDL);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "invalid create flag value");
+ }
+ } else
+ create = 0;
+
+ /* Get the update flag. */
+ status = omapi_get_value_str (mo, message -> id_object,
+ "update", &tv);
+ if (status == ISC_R_SUCCESS) {
+ status = omapi_get_int_value (&update, tv -> value);
+ omapi_value_dereference (&tv, MDL);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "invalid update flag value");
+ }
+ } else
+ update = 0;
+
+ /* Get the exclusive flag. */
+ status = omapi_get_value_str (mo, message -> id_object,
+ "exclusive", &tv);
+ if (status == ISC_R_SUCCESS) {
+ status = omapi_get_int_value (&exclusive, tv -> value);
+ omapi_value_dereference (&tv, MDL);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "invalid exclusive flag value");
+ }
+ } else
+ exclusive = 0;
+
+ /* If we weren't given a type, look the object up with
+ the handle. */
+ if (!type) {
+ if (create) {
+ return omapi_protocol_send_status
+ (po, message->id_object,
+ DHCP_R_INVALIDARG,
+ message->id,
+ "type required on create");
+ }
+ goto refresh;
+ }
+
+ /* If the type doesn't provide a lookup method, we can't
+ look up the object. */
+ if (!type -> lookup) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ ISC_R_NOTIMPLEMENTED, message -> id,
+ "unsearchable object type");
+ }
+
+ status = (*(type -> lookup)) (&object, message -> id_object,
+ message -> object);
+
+ if (status != ISC_R_SUCCESS &&
+ status != ISC_R_NOTFOUND &&
+ status != DHCP_R_NOKEYS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "object lookup failed");
+ }
+
+ /* If we didn't find the object and we aren't supposed to
+ create it, return an error. */
+ if (status == ISC_R_NOTFOUND && !create) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ ISC_R_NOTFOUND, message -> id,
+ "no object matches specification");
+ }
+
+ /* If we found an object, we're supposed to be creating an
+ object, and we're not supposed to have found an object,
+ return an error. */
+ if (status == ISC_R_SUCCESS && create && exclusive) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ ISC_R_EXISTS, message -> id,
+ "specified object already exists");
+ }
+
+ /* If we're creating the object, do it now. */
+ if (!object) {
+ status = omapi_object_create (&object,
+ message -> id_object,
+ type);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't create new object");
+ }
+ }
+
+ /* If we're updating it, do so now. */
+ if (create || update) {
+ /* This check does not belong here. */
+ if (object -> type == omapi_type_auth_key) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't update object");
+ }
+
+ status = omapi_object_update (object,
+ message -> id_object,
+ message -> object,
+ message -> h);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't update object");
+ }
+ }
+
+ /* If this is an authenticator object, add it to the active
+ set for the connection. */
+ if (object -> type == omapi_type_auth_key) {
+ omapi_handle_t handle;
+ status = omapi_object_handle (&handle, object);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't select authenticator");
+ }
+
+ status = omapi_protocol_add_auth (po, object, handle);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't select authenticator");
+ }
+ }
+
+ /* Now send the new contents of the object back in
+ response. */
+ goto send;
+
+ case OMAPI_OP_REFRESH:
+ refresh:
+ status = omapi_handle_lookup (&object, message -> h);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "no matching handle");
+ }
+ send:
+ status = omapi_protocol_send_update (po, message -> id_object,
+ message -> id, object);
+ omapi_object_dereference (&object, MDL);
+ return status;
+
+ case OMAPI_OP_UPDATE:
+ if (m && m -> object) {
+ status = omapi_object_reference (&object, m -> object,
+ MDL);
+ } else {
+ status = omapi_handle_lookup (&object, message -> h);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "no matching handle");
+ }
+ }
+
+ if (object -> type == omapi_type_auth_key ||
+ (object -> inner &&
+ object -> inner -> type == omapi_type_auth_key)) {
+ if (!m) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "cannot update authenticator");
+ }
+
+ status = omapi_protocol_add_auth (po, object,
+ message -> h);
+ } else {
+ status = omapi_object_update (object,
+ message -> id_object,
+ message -> object,
+ message -> h);
+ }
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference (&object, MDL);
+ if (!message -> rid)
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't update object");
+ if (m)
+ omapi_signal ((omapi_object_t *)m,
+ "status", status,
+ (omapi_typed_data_t *)0);
+ return ISC_R_SUCCESS;
+ }
+ if (!message -> rid)
+ status = omapi_protocol_send_status
+ (po, message -> id_object, ISC_R_SUCCESS,
+ message -> id, (char *)0);
+ if (m) {
+ omapi_signal ((omapi_object_t *)m,
+ "status", ISC_R_SUCCESS,
+ (omapi_typed_data_t *)0);
+ omapi_message_unregister ((omapi_object_t *)m);
+ }
+
+ omapi_object_dereference (&object, MDL);
+
+ return status;
+
+ case OMAPI_OP_NOTIFY:
+ return omapi_protocol_send_status
+ (po, message -> id_object, ISC_R_NOTIMPLEMENTED,
+ message -> id, "notify not implemented yet");
+
+ case OMAPI_OP_STATUS:
+ /* The return status of a request. */
+ if (!m)
+ return ISC_R_UNEXPECTED;
+
+ /* Get the wait status. */
+ status = omapi_get_value_str (mo, message -> id_object,
+ "result", &tv);
+ if (status == ISC_R_SUCCESS) {
+ status = omapi_get_int_value (&wsi, tv -> value);
+ waitstatus = wsi;
+ omapi_value_dereference (&tv, MDL);
+ if (status != ISC_R_SUCCESS)
+ waitstatus = ISC_R_UNEXPECTED;
+ } else
+ waitstatus = ISC_R_UNEXPECTED;
+
+ status = omapi_get_value_str (mo, message -> id_object,
+ "message", &tv);
+ omapi_signal ((omapi_object_t *)m, "status", waitstatus, tv);
+ if (status == ISC_R_SUCCESS)
+ omapi_value_dereference (&tv, MDL);
+
+ omapi_message_unregister((omapi_object_t *)m);
+
+ return ISC_R_SUCCESS;
+
+ case OMAPI_OP_DELETE:
+ status = omapi_handle_lookup (&object, message -> h);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "no matching handle");
+ }
+
+ if (!object -> type -> remove)
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ ISC_R_NOTIMPLEMENTED, message -> id,
+ "no remove method for object");
+
+ status = (*(object -> type -> remove)) (object,
+ message -> id_object);
+ omapi_object_dereference (&object, MDL);
+
+ return omapi_protocol_send_status (po, message -> id_object,
+ status, message -> id,
+ (char *)0);
+ }
+ return ISC_R_NOTIMPLEMENTED;
+}
diff --git a/omapip/omapi.3 b/omapip/omapi.3
new file mode 100644
index 0000000..8fa8105
--- /dev/null
+++ b/omapip/omapi.3
@@ -0,0 +1,249 @@
+.\" omapi.3
+.\"
+.\" Copyright (c) 2009-2010,2014 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 2000-2003 by Internet Software Consortium
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+.\"
+.\" Internet Systems Consortium, Inc.
+.\" 950 Charter Street
+.\" Redwood City, CA 94063
+.\" <info@isc.org>
+.\" https://www.isc.org/
+.\"
+.\" This software has been written for Internet Systems Consortium
+.\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+.\"
+.\" Support and other services are available for ISC products - see
+.\" https://www.isc.org for more information or to learn more about ISC.
+.\"
+.TH omapi 3
+.SH NAME
+OMAPI - Object Management Application Programming Interface
+.SH DESCRIPTION
+.PP
+OMAPI is an programming layer designed for controlling remote
+applications, and for querying them for their state. It is currently
+used by the ISC DHCP server and this outline addresses the parts of
+OMAPI appropriate to the clients of DHCP server. It does this by also
+describing the use of a thin API layered on top of OMAPI called
+\'dhcpctl\'
+.PP
+OMAPI uses TCP/IP as the transport for server communication, and
+security can be imposed by having the client and server
+cryptographically sign messages using a shared secret.
+.PP
+dhcpctl works by presenting the client with handles to objects that
+act as surrogates for the real objects in the server. For example a
+client will create a handle for a lease object, and will request the
+server to fill the lease handle's state. The client application can
+then pull details such as the lease expiration time from the lease
+handle.
+.PP
+Modifications can be made to the server state by creating handles to
+new objects, or by modifying attributes of handles to existing
+objects, and then instructing the server to update itself according to
+the changes made.
+.SH USAGE
+.PP
+The client application must always call dhcpctl_initialize() before
+making calls to any other dhcpctl functions. This initializes
+various internal data structures.
+.PP
+To create the connection to the server the client must use
+dhcpctl_connect() function. As well as making the physical connection
+it will also set up the connection data structures to do
+authentication on each message, if that is required.
+.PP
+All the dhcpctl functions return an integer value of type
+isc_result_t. A successful call will yield a result of
+ISC_R_SUCCESS. If the call fails for a reason local to the client
+(e.g. insufficient local memory, or invalid arguments to the call)
+then the return value of the dhcpctl function will show that. If the
+call succeeds but the server couldn't process the request the error
+value from the server is returned through another way, shown below.
+.PP
+The easiest way to understand dhcpctl is to see it in action. The
+following program is fully functional, but almost all error checking
+has been removed to make is shorter and easier to understand. This
+program will query the server running on the localhost for the details
+of the lease for IP address 10.0.0.101. It will then print out the time
+the lease ends.
+.PP
+.nf
+ #include <stdarg.h>
+ #include <sys/time.h>
+ #include <sys/socket.h>
+ #include <stdio.h>
+ #include <netinet/in.h>
+
+ #include <isc/result.h>
+ #include <dhcpctl/dhcpctl.h>
+
+ int main (int argc, char **argv) {
+ dhcpctl_data_string ipaddrstring = NULL;
+ dhcpctl_data_string value = NULL;
+.fi
+.PP
+All modifications of handles and all accesses of handle data happen
+via dhcpctl_data_string objects.
+.PP
+.nf
+ dhcpctl_handle connection = NULL;
+ dhcpctl_handle lease = NULL;
+ isc_result_t waitstatus;
+ struct in_addr convaddr;
+ time_t thetime;
+
+ dhcpctl_initialize ();
+.fi
+.PP
+Required first step.
+.PP
+.nf
+ dhcpctl_connect (&connection, "127.0.0.1",
+ 7911, 0);
+.fi
+.PP
+Sets up the connection to the server. The server normally listens on
+port 7911 unless configured to do otherwise.
+.PP
+.nf
+ dhcpctl_new_object (&lease, connection,
+ "lease");
+.fi
+.PP
+Here we create a handle to a lease. This call just sets up local data
+structure. The server hasn't yet made any association between the
+client's data structure and any lease it has.
+.PP
+.nf
+ memset (&ipaddrstring, 0, sizeof
+ ipaddrstring);
+
+ inet_pton(AF_INET, "10.0.0.101",
+ &convaddr);
+
+ omapi_data_string_new (&ipaddrstring,
+ 4, MDL);
+.fi
+.PP
+Create a new data string to storing in the handle.
+.PP
+.nf
+ memcpy(ipaddrstring->value, &convaddr.s_addr, 4);
+
+ dhcpctl_set_value (lease, ipaddrstring,
+ "ip-address");
+.fi
+.PP
+We're setting the ip-address attribute of the lease handle to the
+given address. We've not set any other attributes so when the server
+makes the association the ip address will be all it uses to look up
+the lease in its tables.
+.PP
+.nf
+ dhcpctl_open_object (lease, connection, 0);
+.fi
+.PP
+Here we prime the connection with the request to look up the lease in
+the server and fill up the local handle with the attributes the server
+will send over in its answer.
+.PP
+.nf
+ dhcpctl_wait_for_completion (lease,
+ &waitstatus);
+.fi
+.PP
+This call causes the message to get sent to the server (the message to
+look up the lease and send back the attribute values in the
+answer). The value in the variable waitstatus when the function
+returns will be the result from the server. If the message could
+not be processed properly by the server then the error will be
+reflected here.
+.PP
+.nf
+ if (waitstatus != ISC_R_SUCCESS) {
+ /* server not authoritative */
+ exit (0);
+ }
+
+ dhcpctl_data_string_dereference(&ipaddrstring,
+ MDL);
+.fi
+.PP
+Clean-up memory we no longer need.
+.PP
+.nf
+ dhcpctl_get_value (&value, lease, "ends");
+.fi
+.PP
+Get the attribute named ``ends'' from the lease handle. This is a
+4-byte integer of the time (in unix epoch seconds) that the lease
+will expire.
+.PP
+.nf
+
+ memcpy(&thetime, value->value, value->len);
+ dhcpctl_data_string_dereference(&value, MDL);
+
+ fprintf (stdout, "ending time is %s",
+ ctime(&thetime));
+ }
+
+.fi
+.SH AUTHENTICATION
+If the server demands authenticated connections then before opening
+the connection the user must call dhcpctl_new_authenticator.
+.PP
+.nf
+ dhcpctl_handle authenticator = NULL;
+ const char *keyname = "a-key-name";
+ const char *algorithm = "hmac-md5";
+ const char *secret = "a-shared-secret";
+
+ dhcpctl_new_authenticator (&authenticator,
+ keyname,
+ algorithm,
+ secret,
+ strlen(secret) + 1);
+.fi
+.PP
+The keyname, algorithm and must all match what is specified in the server's
+dhcpd.conf file, excepting that the secret should appear in \'raw\' form, not
+in base64 as it would in dhcpd.conf:
+.PP
+.nf
+ key "a-key-name" {
+ algorithm hmac-md5;
+ secret "a-shared-secret";
+ };
+
+ # Set the omapi-key value to use
+ # authenticated connections
+ omapi-key a-key-name;
+.fi
+.PP
+The authenticator handle that is created by the call to
+dhcpctl_new_authenticator must be given as the last (the 4th) argument
+to the call to dhcpctl_connect(). All messages will then be signed
+with the given secret string using the specified algorithm.
+.SH SEE ALSO
+dhcpctl(3), omshell(1), dhcpd(8), dhclient(8), dhcpd.conf(5), dhclient.conf(5).
+.SH AUTHOR
+.B omapi
+is maintained by ISC. To learn more about Internet Systems Consortium,
+see
+.B https://www.isc.org
+
diff --git a/omapip/protocol.c b/omapip/protocol.c
new file mode 100644
index 0000000..908bcce
--- /dev/null
+++ b/omapip/protocol.c
@@ -0,0 +1,1314 @@
+/* protocol.c
+
+ Functions supporting the object management protocol... */
+
+/*
+ * Copyright (c) 2009,2012,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+
+OMAPI_OBJECT_ALLOC (omapi_protocol, omapi_protocol_object_t,
+ omapi_type_protocol)
+OMAPI_OBJECT_ALLOC (omapi_protocol_listener, omapi_protocol_listener_object_t,
+ omapi_type_protocol_listener)
+
+isc_result_t omapi_protocol_connect (omapi_object_t *h,
+ const char *server_name,
+ unsigned port,
+ omapi_object_t *a)
+{
+ isc_result_t rstatus, status;
+ omapi_protocol_object_t *obj;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_protocol_connect(%s port=%d)", server_name, port);
+#endif
+
+ obj = (omapi_protocol_object_t *)0;
+ status = omapi_protocol_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ rstatus = omapi_connect ((omapi_object_t *)obj, server_name, port);
+ if (rstatus != ISC_R_SUCCESS && rstatus != DHCP_R_INCOMPLETE) {
+ omapi_protocol_dereference (&obj, MDL);
+ return rstatus;
+ }
+ status = omapi_object_reference (&h -> outer,
+ (omapi_object_t *)obj, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_protocol_dereference (&obj, MDL);
+ return status;
+ }
+ status = omapi_object_reference (&obj -> inner, h, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_protocol_dereference (&obj, MDL);
+ return status;
+ }
+
+ /* If we were passed a default authenticator, store it now. We'll
+ open it once we're connected. */
+ if (a) {
+ obj -> default_auth =
+ dmalloc (sizeof(omapi_remote_auth_t), MDL);
+ if (!obj -> default_auth) {
+ omapi_protocol_dereference (&obj, MDL);
+ return ISC_R_NOMEMORY;
+ }
+
+ obj -> default_auth -> next = (omapi_remote_auth_t *)0;
+ status = omapi_object_reference (&obj -> default_auth -> a,
+ a, MDL);
+ if (status != ISC_R_SUCCESS) {
+ dfree (obj -> default_auth, MDL);
+ omapi_protocol_dereference (&obj, MDL);
+ return status;
+ }
+
+ obj -> insecure = 0;
+ rstatus = DHCP_R_INCOMPLETE;
+ } else {
+ obj -> insecure = 1;
+#if 0
+ status = ISC_R_SUCCESS;
+#endif
+ }
+
+ omapi_protocol_dereference (&obj, MDL);
+ return rstatus;
+}
+
+/* Send the protocol introduction message. */
+isc_result_t omapi_protocol_send_intro (omapi_object_t *h,
+ unsigned ver,
+ unsigned hsize)
+{
+ isc_result_t status;
+ omapi_protocol_object_t *p;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_protocol_send_intro()");
+#endif
+
+ if (h -> type != omapi_type_protocol)
+ return DHCP_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)h;
+
+ if (!h -> outer || h -> outer -> type != omapi_type_connection)
+ return ISC_R_NOTCONNECTED;
+
+ status = omapi_connection_put_uint32 (h -> outer, ver);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_connection_put_uint32 (h -> outer, hsize);
+
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ /* Require the other end to send an intro - this kicks off the
+ protocol input state machine. */
+ p -> state = omapi_protocol_intro_wait;
+ status = omapi_connection_require (h -> outer, 8);
+ if (status != ISC_R_SUCCESS && status != DHCP_R_NOTYET)
+ return status;
+
+ /* Make up an initial transaction ID for this connection. */
+ p -> next_xid = random ();
+ return ISC_R_SUCCESS;
+}
+
+#ifdef DEBUG_PROTOCOL
+extern const char *omapi_message_op_name(int);
+#endif /* DEBUG_PROTOCOL */
+
+isc_result_t omapi_protocol_send_message (omapi_object_t *po,
+ omapi_object_t *id,
+ omapi_object_t *mo,
+ omapi_object_t *omo)
+{
+ omapi_protocol_object_t *p;
+ omapi_object_t *c;
+ omapi_message_object_t *m, *om;
+ omapi_remote_auth_t *ra;
+ omapi_value_t *signature;
+ isc_result_t status;
+ unsigned auth_len;
+
+ if (po -> type != omapi_type_protocol ||
+ !po -> outer || po -> outer -> type != omapi_type_connection ||
+ mo -> type != omapi_type_message)
+ return DHCP_R_INVALIDARG;
+ if (omo && omo -> type != omapi_type_message)
+ return DHCP_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)po;
+ c = (omapi_object_t *)(po -> outer);
+ m = (omapi_message_object_t *)mo;
+ om = (omapi_message_object_t *)omo;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_protocol_send_message(): "
+ "op=%s handle=%#lx id=%#lx rid=%#lx",
+ omapi_message_op_name (m->op),
+ (long)(m -> object ? m -> object -> handle : m -> handle),
+ (long)p -> next_xid, (long)m -> rid);
+#endif
+
+ /* Find the authid to use for this message. */
+ if (id) {
+ for (ra = p -> remote_auth_list; ra; ra = ra -> next) {
+ if (ra -> a == id) {
+ break;
+ }
+ }
+
+ if (!ra)
+ return DHCP_R_KEY_UNKNOWN;
+ } else if (p -> remote_auth_list) {
+ ra = p -> default_auth;
+ } else {
+ ra = (omapi_remote_auth_t *)0;
+ }
+
+ if (ra) {
+ m -> authid = ra -> remote_handle;
+ status = omapi_object_reference (&m -> id_object,
+ ra -> a, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ /* Write the ID of the authentication key we're using. */
+ status = omapi_connection_put_uint32 (c, ra ? ra -> remote_handle : 0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Activate the authentication key on the connection. */
+ auth_len = 0;
+ if (ra) {
+ status = omapi_set_object_value (c, (omapi_object_t *)0,
+ "output-authenticator",
+ ra -> a);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ status = omapi_connection_output_auth_length (c, &auth_len);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+
+ /* Write the authenticator length */
+ status = omapi_connection_put_uint32 (c, auth_len);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Write the opcode. */
+ status = omapi_connection_put_uint32 (c, m -> op);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Write the handle. If we've been given an explicit handle, use
+ that. Otherwise, use the handle of the object we're sending.
+ The caller is responsible for arranging for one of these handles
+ to be set (or not). */
+ status = omapi_connection_put_uint32 (c, (m -> h
+ ? m -> h
+ : (m -> object
+ ? m -> object -> handle
+ : 0)));
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Set and write the transaction ID. */
+ m -> id = p -> next_xid++;
+ status = omapi_connection_put_uint32 (c, m -> id);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Write the transaction ID of the message to which this is a
+ response, if there is such a message. */
+ status = omapi_connection_put_uint32 (c, om ? om -> id : m -> rid);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Stuff out the name/value pairs specific to this message. */
+ status = omapi_stuff_values (c, id, (omapi_object_t *)m);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Write the zero-length name that terminates the list of name/value
+ pairs specific to the message. */
+ status = omapi_connection_put_uint16 (c, 0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Stuff out all the published name/value pairs in the object that's
+ being sent in the message, if there is one. */
+ if (m -> object) {
+ status = omapi_stuff_values (c, id, m -> object);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+
+ /* Write the zero-length name that terminates the list of name/value
+ pairs for the associated object. */
+ status = omapi_connection_put_uint16 (c, 0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ if (ra) {
+ /* Calculate the message signature. */
+ signature = (omapi_value_t *)0;
+ status = omapi_get_value_str (c, (omapi_object_t *)0,
+ "output-signature", &signature);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Write the authenticator... */
+ status = (omapi_connection_copyin
+ (c, signature -> value -> u.buffer.value,
+ signature -> value -> u.buffer.len));
+ omapi_value_dereference (&signature, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Dectivate the authentication key on the connection. */
+ status = omapi_set_value_str (c, (omapi_object_t *)0,
+ "output-authenticator",
+ (omapi_typed_data_t *)0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+
+ if (!omo) {
+ omapi_protocol_reference (&m -> protocol_object, p, MDL);
+ }
+ return ISC_R_SUCCESS;
+}
+
+
+isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ isc_result_t status;
+ omapi_protocol_object_t *p;
+ omapi_object_t *c;
+ omapi_message_object_t *m;
+ omapi_value_t *signature = NULL;
+ u_int16_t nlen;
+ u_int32_t vlen;
+ u_int32_t th;
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ unsigned long previous_outstanding = 0xDEADBEEF;
+ unsigned long connect_outstanding = 0xDEADBEEF;
+#endif
+
+ if (h -> type != omapi_type_protocol) {
+ /* XXX shouldn't happen. Put an assert here? */
+ return ISC_R_UNEXPECTED;
+ }
+ p = (omapi_protocol_object_t *)h;
+
+ if (!strcmp (name, "connect")) {
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ connect_outstanding = dmalloc_outstanding;
+#endif
+ /* Send the introductory message. */
+ status = omapi_protocol_send_intro
+ (h, OMAPI_PROTOCOL_VERSION,
+ sizeof (omapi_protocol_header_t));
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (p -> outer, 1);
+ return status;
+ }
+ return ISC_R_SUCCESS;
+ }
+
+ /* Should only receive these when opening the initial authenticator. */
+ if (!strcmp (name, "status")) {
+ status = va_arg (ap, isc_result_t);
+ if (status != ISC_R_SUCCESS) {
+ omapi_signal_in (h -> inner, "status", status,
+ (omapi_object_t *)0);
+ omapi_disconnect (p -> outer, 1);
+ return status;
+ } else {
+ return omapi_signal_in (h -> inner, "ready");
+ }
+ }
+
+ /* If we get a disconnect, dump memory usage. */
+ if (!strcmp (name, "disconnect")) {
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ if (connect_outstanding != 0xDEADBEEF) {
+ log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
+ dmalloc_generation,
+ dmalloc_outstanding - previous_outstanding,
+ dmalloc_outstanding, dmalloc_longterm, " long-term");
+ }
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
+ dump_rc_history (h);
+#endif
+ for (m = omapi_registered_messages; m; m = m -> next) {
+ if (m -> protocol_object == p) {
+ if (m -> object)
+ omapi_signal (m -> object, "disconnect");
+ }
+ }
+
+ /* XXX */
+ return ISC_R_SUCCESS;
+ }
+
+ /* Not a signal we recognize? */
+ if (strcmp (name, "ready")) {
+ if (p -> inner && p -> inner -> type -> signal_handler)
+ return (*(p -> inner -> type -> signal_handler)) (h,
+ name,
+ ap);
+ return ISC_R_NOTFOUND;
+ }
+
+ if (!p -> outer || p -> outer -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+ c = p -> outer;
+
+ /* We get here because we requested that we be woken up after
+ some number of bytes were read, and that number of bytes
+ has in fact been read. */
+ switch (p -> state) {
+ case omapi_protocol_intro_wait:
+ /* Get protocol version and header size in network
+ byte order. */
+ omapi_connection_get_uint32 (c, &p -> protocol_version);
+ omapi_connection_get_uint32 (c, &p -> header_size);
+
+ /* We currently only support the current protocol version. */
+ if (p -> protocol_version != OMAPI_PROTOCOL_VERSION) {
+ omapi_disconnect (c, 1);
+ return DHCP_R_VERSIONMISMATCH;
+ }
+
+ if (p -> header_size < sizeof (omapi_protocol_header_t)) {
+ omapi_disconnect (c, 1);
+ return DHCP_R_PROTOCOLERROR;
+ }
+
+ if (p -> default_auth) {
+ status = omapi_protocol_send_open
+ (h, (omapi_object_t *)0, "authenticator",
+ p -> default_auth -> a,
+ OMAPI_NOTIFY_PROTOCOL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ } else {
+ status = omapi_signal_in (h -> inner, "ready");
+ }
+
+ to_header_wait:
+ /* The next thing we're expecting is a message header. */
+ p -> state = omapi_protocol_header_wait;
+
+ /* Register a need for the number of bytes in a
+ header, and if we already have that many, process
+ them immediately. */
+ if ((omapi_connection_require (c, p -> header_size)) !=
+ ISC_R_SUCCESS)
+ break;
+ /* If we already have the data, fall through. */
+
+ case omapi_protocol_header_wait:
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ if (previous_outstanding != 0xDEADBEEF) {
+ log_info ("%s %ld: %ld new, %ld outstanding, %ld%s",
+ "generation", dmalloc_generation,
+ dmalloc_outstanding - previous_outstanding,
+ dmalloc_outstanding, dmalloc_longterm,
+ " long-term");
+#endif
+#if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
+ dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
+ dump_rc_history (h);
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ }
+ previous_outstanding = dmalloc_outstanding;
+#endif
+ status = omapi_message_new ((omapi_object_t **)&p -> message,
+ MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ p -> verify_result = ISC_R_SUCCESS;
+
+ /* Swap in the header... */
+ omapi_connection_get_uint32 (c, &p -> message -> authid);
+
+ /* Bind the authenticator to the message object. */
+ if (p -> message -> authid) {
+ status = (omapi_protocol_lookup_auth
+ (&p -> message -> id_object, h,
+ p -> message -> authid));
+ if (status != ISC_R_SUCCESS)
+ p -> verify_result = status;
+
+ /* Activate the authentication key. */
+ status = omapi_set_object_value
+ (c, (omapi_object_t *)0, "input-authenticator",
+ p -> message -> id_object);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+
+ omapi_connection_get_uint32 (c, &p -> message -> authlen);
+ omapi_connection_get_uint32 (c, &p -> message -> op);
+ omapi_connection_get_uint32 (c, &th);
+ p -> message -> h = th;
+ omapi_connection_get_uint32 (c, &p -> message -> id);
+ omapi_connection_get_uint32 (c, &p -> message -> rid);
+
+ /* If there was any extra header data, skip over it. */
+ if (p -> header_size > sizeof (omapi_protocol_header_t)) {
+ omapi_connection_copyout
+ (0, c, (p -> header_size -
+ sizeof (omapi_protocol_header_t)));
+ }
+
+ /* XXX must compute partial signature across the
+ XXX preceding bytes. Also, if authenticator
+ specifies encryption as well as signing, we may
+ have to decrypt the data on the way in. */
+
+ /* First we read in message-specific values, then object
+ values. */
+ p -> reading_message_values = 1;
+
+ need_name_length:
+ /* The next thing we're expecting is length of the
+ first name. */
+ p -> state = omapi_protocol_name_length_wait;
+
+ /* Wait for a 16-bit length. */
+ if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS)
+ break;
+ /* If it's already here, fall through. */
+
+ case omapi_protocol_name_length_wait:
+ omapi_connection_get_uint16 (c, &nlen);
+ /* A zero-length name means that we're done reading name+value
+ pairs. */
+ if (nlen == 0) {
+ /* If we've already read in the object, we are
+ done reading the message, but if we've just
+ finished reading in the values associated
+ with the message, we need to read the
+ object. */
+ if (p -> reading_message_values) {
+ p -> reading_message_values = 0;
+ goto need_name_length;
+ }
+
+ /* If the authenticator length is zero, there's no
+ signature to read in, so go straight to processing
+ the message. */
+ if (p -> message -> authlen == 0)
+ goto message_done;
+
+ /* The next thing we're expecting is the
+ message signature. */
+ p -> state = omapi_protocol_signature_wait;
+
+ /* Wait for the number of bytes specified for
+ the authenticator. If we already have it,
+ go read it in. */
+ if (omapi_connection_require
+ (c, p -> message -> authlen) == ISC_R_SUCCESS)
+ goto signature_wait;
+ break;
+ }
+
+ /* Allocate a buffer for the name. */
+ status = (omapi_data_string_new (&p -> name, nlen, MDL));
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return ISC_R_NOMEMORY;
+ }
+ p -> state = omapi_protocol_name_wait;
+ if (omapi_connection_require (c, nlen) != ISC_R_SUCCESS)
+ break;
+ /* If it's already here, fall through. */
+
+ case omapi_protocol_name_wait:
+ omapi_connection_copyout (p -> name -> value, c,
+ p -> name -> len);
+ /* Wait for a 32-bit length. */
+ p -> state = omapi_protocol_value_length_wait;
+ if ((omapi_connection_require (c, 4)) != ISC_R_SUCCESS)
+ break;
+ /* If it's already here, fall through. */
+
+ case omapi_protocol_value_length_wait:
+ omapi_connection_get_uint32 (c, &vlen);
+
+ /* Zero-length values are allowed - if we get one, we
+ don't have to read any data for the value - just
+ get the next one, if there is a next one. */
+ if (!vlen)
+ goto insert_new_value;
+
+ status = omapi_typed_data_new (MDL, &p -> value,
+ omapi_datatype_data,
+ vlen);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return ISC_R_NOMEMORY;
+ }
+
+ p -> state = omapi_protocol_value_wait;
+ if (omapi_connection_require (c, vlen) != ISC_R_SUCCESS)
+ break;
+ /* If it's already here, fall through. */
+
+ case omapi_protocol_value_wait:
+ omapi_connection_copyout (p -> value -> u.buffer.value, c,
+ p -> value -> u.buffer.len);
+
+ insert_new_value:
+ if (p -> reading_message_values) {
+ status = (omapi_set_value
+ ((omapi_object_t *)p -> message,
+ p -> message -> id_object,
+ p -> name, p -> value));
+ } else {
+ if (!p -> message -> object) {
+ /* We need a generic object to hang off of the
+ incoming message. */
+ status = (omapi_generic_new
+ (&p -> message -> object, MDL));
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+ status = (omapi_set_value
+ ((omapi_object_t *)p -> message -> object,
+ p -> message -> id_object,
+ p -> name, p -> value));
+ }
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ omapi_data_string_dereference (&p -> name, MDL);
+ if (p -> value)
+ omapi_typed_data_dereference (&p -> value, MDL);
+ goto need_name_length;
+
+ signature_wait:
+ case omapi_protocol_signature_wait:
+ if (p -> message -> id_object) {
+ /* Compute the signature of the message. */
+ status = omapi_get_value_str (c, (omapi_object_t *)0,
+ "input-signature",
+ &signature);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Disable the authentication key on the connection. */
+ status = omapi_set_value_str (c, (omapi_object_t *)0,
+ "input-authenticator",
+ (omapi_typed_data_t *)0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (&signature, MDL);
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+
+ /* Read the authenticator. */
+ status = omapi_typed_data_new (MDL,
+ &p -> message -> authenticator,
+ omapi_datatype_data,
+ p -> message -> authlen);
+
+ if (status != ISC_R_SUCCESS) {
+ if (signature != NULL) {
+ omapi_value_dereference (&signature, MDL);
+ }
+ omapi_disconnect (c, 1);
+ return ISC_R_NOMEMORY;
+ }
+ omapi_connection_copyout
+ (p -> message -> authenticator -> u.buffer.value, c,
+ p -> message -> authlen);
+
+ /* Verify the signature. */
+ if (p -> message -> id_object &&
+ ((signature -> value -> u.buffer.len !=
+ p -> message -> authlen) ||
+ (memcmp (signature -> value -> u.buffer.value,
+ p -> message -> authenticator -> u.buffer.value,
+ p -> message -> authlen) != 0))) {
+ /* Invalid signature. */
+ p->verify_result = DHCP_R_INVALIDKEY;
+ }
+
+ if (signature != NULL) {
+ omapi_value_dereference (&signature, MDL);
+ }
+
+ /* Process the message. */
+ message_done:
+ if (p -> verify_result != ISC_R_SUCCESS) {
+ status = omapi_protocol_send_status
+ (h, (omapi_object_t *)0, p -> verify_result,
+ p -> message -> id, (char *)0);
+ } else {
+ status = omapi_message_process
+ ((omapi_object_t *)p -> message, h);
+ }
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return ISC_R_NOMEMORY;
+ }
+
+ omapi_message_dereference (&p -> message, MDL);
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
+ dmalloc_generation,
+ dmalloc_outstanding - previous_outstanding,
+ dmalloc_outstanding, dmalloc_longterm, " long-term");
+#endif
+#if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
+ dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
+ dump_rc_history (h);
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ previous_outstanding = 0xDEADBEEF;
+#endif
+ /* Now wait for the next message. */
+ goto to_header_wait;
+
+ default:
+ /* XXX should never get here. Assertion? */
+ break;
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_protocol_add_auth (omapi_object_t *po,
+ omapi_object_t *ao,
+ omapi_handle_t handle)
+{
+ omapi_protocol_object_t *p;
+ omapi_remote_auth_t *r;
+ isc_result_t status;
+
+ if (ao -> type != omapi_type_auth_key &&
+ (!ao -> inner || ao -> inner -> type != omapi_type_auth_key))
+ return DHCP_R_INVALIDARG;
+
+ if (po -> type != omapi_type_protocol)
+ return DHCP_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)po;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_protocol_add_auth(name=%s)",
+ ((omapi_auth_key_t *)ao) -> name);
+#endif
+
+ if (p -> verify_auth) {
+ status = (p -> verify_auth) (po, (omapi_auth_key_t *)ao);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ /* If omapi_protocol_connect() was called with a default
+ authenticator, p -> default_auth will already be set,
+ but p -> remote_auth_list will not yet be initialized. */
+ if (p -> default_auth && !p -> remote_auth_list) {
+ if (p -> default_auth -> a != ao) {
+ /* Something just went horribly wrong. */
+ omapi_disconnect (p -> outer, 1);
+ return ISC_R_UNEXPECTED;
+ }
+
+ p -> remote_auth_list = p -> default_auth;
+ p -> default_auth -> remote_handle = handle;
+
+ return omapi_signal_in (p -> inner, "ready");
+ }
+
+ r = dmalloc (sizeof(*r), MDL);
+ if (!r)
+ return ISC_R_NOMEMORY;
+
+ status = omapi_object_reference (&r -> a, ao, MDL);
+ if (status != ISC_R_SUCCESS) {
+ dfree (r, MDL);
+ return status;
+ }
+
+ r -> remote_handle = handle;
+ r -> next = p -> remote_auth_list;
+ p -> remote_auth_list = r;
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_protocol_lookup_auth (omapi_object_t **a,
+ omapi_object_t *po,
+ omapi_handle_t handle)
+{
+ omapi_protocol_object_t *p;
+ omapi_remote_auth_t *r;
+
+ if (po -> type != omapi_type_protocol)
+ return DHCP_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)po;
+
+ for (r = p -> remote_auth_list; r; r = r -> next)
+ if (r -> remote_handle == handle)
+ return omapi_object_reference (a, r -> a, MDL);
+
+ return DHCP_R_KEY_UNKNOWN;
+}
+
+isc_result_t omapi_protocol_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ omapi_protocol_object_t *p;
+ omapi_remote_auth_t *r;
+
+ if (h -> type != omapi_type_protocol)
+ return DHCP_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)h;
+
+ if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
+ if (!value || value -> type != omapi_datatype_object)
+ return DHCP_R_INVALIDARG;
+
+ if (!value -> u.object) {
+ p -> default_auth = (omapi_remote_auth_t *)0;
+ } else {
+ for (r = p -> remote_auth_list; r; r = r -> next)
+ if (r -> a == value -> u.object)
+ break;
+
+ if (!r)
+ return DHCP_R_KEY_UNKNOWN;
+
+ p -> default_auth = r;
+ }
+
+ return ISC_R_SUCCESS;
+ }
+
+ if (h -> inner && h -> inner -> type -> set_value)
+ return (*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_protocol_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ omapi_protocol_object_t *p;
+
+ if (h -> type != omapi_type_protocol)
+ return DHCP_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)h;
+
+ if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
+ if (!p -> default_auth)
+ return ISC_R_NOTFOUND;
+
+ return omapi_make_object_value (value, name,
+ p -> default_auth -> a, MDL);
+ }
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_protocol_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_protocol_object_t *p;
+ if (h -> type != omapi_type_protocol)
+ return DHCP_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)h;
+ if (p -> message)
+ omapi_message_dereference (&p -> message, file, line);
+
+ /* This will happen if: 1) A default authenticator is supplied to
+ omapi_protocol_connect(), and 2) something goes wrong before
+ the authenticator can be opened. */
+ if (p -> default_auth && !p -> remote_auth_list)
+ dfree (p -> default_auth, file, line);
+
+ while (p -> remote_auth_list) {
+ omapi_remote_auth_t *r = p -> remote_auth_list;
+ p -> remote_auth_list = p -> remote_auth_list -> next;
+ omapi_object_dereference (&r -> a, file, line);
+ dfree (r, file, line);
+ }
+ return ISC_R_SUCCESS;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_protocol_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *p)
+{
+ if (p -> type != omapi_type_protocol)
+ return DHCP_R_INVALIDARG;
+
+ if (p -> inner && p -> inner -> type -> stuff_values)
+ return (*(p -> inner -> type -> stuff_values)) (c, id,
+ p -> inner);
+ return ISC_R_SUCCESS;
+}
+
+/* Returns a boolean indicating whether this protocol requires that
+ messages be authenticated or not. */
+
+isc_boolean_t omapi_protocol_authenticated (omapi_object_t *h)
+{
+ if (h -> type != omapi_type_protocol)
+ return isc_boolean_false;
+ if (((omapi_protocol_object_t *)h) -> insecure)
+ return isc_boolean_false;
+ else
+ return isc_boolean_true;
+}
+
+/* Sets the address and authenticator verification callbacks. The handle
+ is to a listener object, not a protocol object. */
+
+isc_result_t omapi_protocol_configure_security (omapi_object_t *h,
+ isc_result_t (*verify_addr)
+ (omapi_object_t *,
+ omapi_addr_t *),
+ isc_result_t (*verify_auth)
+ (omapi_object_t *,
+ omapi_auth_key_t *))
+{
+ omapi_protocol_listener_object_t *l;
+
+ if (h -> outer && h -> outer -> type == omapi_type_protocol_listener)
+ h = h -> outer;
+
+ if (h -> type != omapi_type_protocol_listener)
+ return DHCP_R_INVALIDARG;
+ l = (omapi_protocol_listener_object_t *)h;
+
+ l -> verify_auth = verify_auth;
+ l -> insecure = 0;
+
+ if (h -> outer != NULL) {
+ return omapi_listener_configure_security (h -> outer, verify_addr);
+ } else {
+ return DHCP_R_INVALIDARG;
+ }
+}
+
+
+/* Set up a listener for the omapi protocol. The handle stored points to
+ a listener object, not a protocol object. */
+
+isc_result_t omapi_protocol_listen (omapi_object_t *h,
+ unsigned port,
+ int max)
+{
+ isc_result_t status;
+ omapi_protocol_listener_object_t *obj;
+
+ obj = (omapi_protocol_listener_object_t *)0;
+ status = omapi_protocol_listener_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_reference (&h -> outer,
+ (omapi_object_t *)obj, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_protocol_listener_dereference (&obj, MDL);
+ return status;
+ }
+ status = omapi_object_reference (&obj -> inner, h, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_protocol_listener_dereference (&obj, MDL);
+ return status;
+ }
+
+ /* What a terrible default. */
+ obj -> insecure = 1;
+
+ status = omapi_listen ((omapi_object_t *)obj, port, max);
+ omapi_protocol_listener_dereference (&obj, MDL);
+ return status;
+}
+
+/* Signal handler for protocol listener - if we get a connect signal,
+ create a new protocol connection, otherwise pass the signal down. */
+
+isc_result_t omapi_protocol_listener_signal (omapi_object_t *o,
+ const char *name, va_list ap)
+{
+ isc_result_t status;
+ omapi_object_t *c;
+ omapi_protocol_object_t *obj;
+ omapi_protocol_listener_object_t *p;
+
+ if (!o || o -> type != omapi_type_protocol_listener)
+ return DHCP_R_INVALIDARG;
+ p = (omapi_protocol_listener_object_t *)o;
+
+ /* Not a signal we recognize? */
+ if (strcmp (name, "connect")) {
+ if (p -> inner && p -> inner -> type -> signal_handler)
+ return (*(p -> inner -> type -> signal_handler))
+ (p -> inner, name, ap);
+ return ISC_R_NOTFOUND;
+ }
+
+ c = va_arg (ap, omapi_object_t *);
+ if (!c || c -> type != omapi_type_connection)
+ return DHCP_R_INVALIDARG;
+
+ obj = (omapi_protocol_object_t *)0;
+ status = omapi_protocol_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ obj -> verify_auth = p -> verify_auth;
+ obj -> insecure = p -> insecure;
+
+ status = omapi_object_reference (&obj -> outer, c, MDL);
+ if (status != ISC_R_SUCCESS) {
+ lose:
+ omapi_protocol_dereference (&obj, MDL);
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ status = omapi_object_reference (&c -> inner,
+ (omapi_object_t *)obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ goto lose;
+
+ /* Send the introductory message. */
+ status = omapi_protocol_send_intro ((omapi_object_t *)obj,
+ OMAPI_PROTOCOL_VERSION,
+ sizeof (omapi_protocol_header_t));
+ if (status != ISC_R_SUCCESS)
+ goto lose;
+
+ omapi_protocol_dereference (&obj, MDL);
+ return status;
+}
+
+isc_result_t omapi_protocol_listener_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ if (h -> type != omapi_type_protocol_listener)
+ return DHCP_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> set_value)
+ return (*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_protocol_listener_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ if (h -> type != omapi_type_protocol_listener)
+ return DHCP_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_protocol_listener_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ if (h -> type != omapi_type_protocol_listener)
+ return DHCP_R_INVALIDARG;
+ return ISC_R_SUCCESS;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_protocol_listener_stuff (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *p)
+{
+ if (p -> type != omapi_type_protocol_listener)
+ return DHCP_R_INVALIDARG;
+
+ if (p -> inner && p -> inner -> type -> stuff_values)
+ return (*(p -> inner -> type -> stuff_values)) (c, id,
+ p -> inner);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_protocol_send_status (omapi_object_t *po,
+ omapi_object_t *id,
+ isc_result_t waitstatus,
+ unsigned rid, const char *msg)
+{
+ isc_result_t status;
+ omapi_message_object_t *message = (omapi_message_object_t *)0;
+ omapi_object_t *mo;
+
+ if (po -> type != omapi_type_protocol)
+ return DHCP_R_INVALIDARG;
+
+ status = omapi_message_new ((omapi_object_t **)&message, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ mo = (omapi_object_t *)message;
+
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "op", OMAPI_OP_STATUS);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "rid", (int)rid);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "result", (int)waitstatus);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ /* If a message has been provided, send it. */
+ if (msg) {
+ status = omapi_set_string_value (mo, (omapi_object_t *)0,
+ "message", msg);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+ }
+
+ status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
+ omapi_message_dereference (&message, MDL);
+ return status;
+}
+
+/* The OMAPI_NOTIFY_PROTOCOL flag will cause the notify-object for the
+ message to be set to the protocol object. This is used when opening
+ the default authenticator. */
+
+isc_result_t omapi_protocol_send_open (omapi_object_t *po,
+ omapi_object_t *id,
+ const char *type,
+ omapi_object_t *object,
+ unsigned flags)
+{
+ isc_result_t status;
+ omapi_message_object_t *message = (omapi_message_object_t *)0;
+ omapi_object_t *mo;
+
+ if (po -> type != omapi_type_protocol)
+ return DHCP_R_INVALIDARG;
+
+ status = omapi_message_new ((omapi_object_t **)&message, MDL);
+ mo = (omapi_object_t *)message;
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "op", OMAPI_OP_OPEN);
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_set_object_value (mo, (omapi_object_t *)0,
+ "object", object);
+
+ if ((flags & OMAPI_CREATE) && (status == ISC_R_SUCCESS))
+ status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
+ "create", 1);
+
+ if ((flags & OMAPI_UPDATE) && (status == ISC_R_SUCCESS))
+ status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
+ "update", 1);
+
+ if ((flags & OMAPI_EXCL) && (status == ISC_R_SUCCESS))
+ status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
+ "exclusive", 1);
+
+ if ((flags & OMAPI_NOTIFY_PROTOCOL) && (status == ISC_R_SUCCESS))
+ status = omapi_set_object_value (mo, (omapi_object_t *)0,
+ "notify-object", po);
+
+ if (type && (status == ISC_R_SUCCESS))
+ status = omapi_set_string_value (mo, (omapi_object_t *)0,
+ "type", type);
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_message_register (mo);
+
+ if (status == ISC_R_SUCCESS) {
+ status = omapi_protocol_send_message (po, id, mo,
+ (omapi_object_t *)0);
+ if (status != ISC_R_SUCCESS)
+ omapi_message_unregister (mo);
+ }
+
+ if (message)
+ omapi_message_dereference (&message, MDL);
+
+ return status;
+}
+
+isc_result_t omapi_protocol_send_update (omapi_object_t *po,
+ omapi_object_t *id,
+ unsigned rid,
+ omapi_object_t *object)
+{
+ isc_result_t status;
+ omapi_message_object_t *message = (omapi_message_object_t *)0;
+ omapi_object_t *mo;
+
+ if (po -> type != omapi_type_protocol)
+ return DHCP_R_INVALIDARG;
+
+ status = omapi_message_new ((omapi_object_t **)&message, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ mo = (omapi_object_t *)message;
+
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "op", OMAPI_OP_UPDATE);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ if (rid) {
+ omapi_handle_t handle;
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "rid", (int)rid);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ status = omapi_object_handle (&handle, object);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "handle", (int)handle);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+ }
+
+ status = omapi_set_object_value (mo, (omapi_object_t *)0,
+ "object", object);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
+ omapi_message_dereference (&message, MDL);
+ return status;
+}
diff --git a/omapip/result.c b/omapip/result.c
new file mode 100644
index 0000000..383279f
--- /dev/null
+++ b/omapip/result.c
@@ -0,0 +1,86 @@
+/* result.c
+ */
+
+/*
+ * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+/*
+ * In the previous code the results started at 36
+ * rather than ISC_RESULTCLASS_DHCP + 0
+ * ISC_R_NOTCONNECTED was + 4 (40), it has been superseeded by the isc version
+ */
+
+static const char *text[DHCP_R_NRESULTS] = {
+ "host unknown", /* 0 */
+ "protocol version mismatch", /* 1 */
+ "protocol error", /* 2 */
+ "invalid argument", /* 3 */
+ "data not yet available", /* 4 */
+ "object unchanged", /* 5 */
+ "more than one object matches key", /* 6 */
+ "key conflict", /* 7 */
+ "parse error(s) occurred", /* 8 */
+ "no key specified", /* 9 */
+ "zone TSIG key not known", /* 10 */
+ "invalid TSIG key", /* 11 */
+ "operation in progress", /* 12 */
+ "DNS format error", /* 13 */
+ "DNS server failed", /* 14 */
+ "no such domain", /* 15 */
+ "not implemented", /* 16 */
+ "refused", /* 17 */
+ "domain already exists", /* 18 */
+ "RRset already exists", /* 19 */
+ "no such RRset", /* 20 */
+ "not authorized", /* 21 */
+ "not a zone", /* 22 */
+ "bad DNS signature", /* 23 */
+ "bad DNS key", /* 24 */
+ "clock skew too great", /* 25 */
+ "no root zone", /* 26 */
+ "destination address required", /* 27 */
+ "cross-zone update", /* 28 */
+ "no TSIG signature", /* 29 */
+ "not equal", /* 30 */
+ "connection reset by peer", /* 31 */
+ "unknown attribute" /* 32 */
+};
+
+#define DHCP_RESULT_RESULTSET 2
+#define DHCP_RESULT_UNAVAILABLESET 3
+
+// This is a placeholder as we don't allow for external message catalogs yet
+isc_msgcat_t * dhcp_msgcat = NULL;
+
+isc_result_t
+dhcp_result_register(void) {
+ isc_result_t result;
+
+ result = isc_result_register(ISC_RESULTCLASS_DHCP, DHCP_R_NRESULTS,
+ text, dhcp_msgcat, DHCP_RESULT_RESULTSET);
+
+ return(result);
+}
diff --git a/omapip/support.c b/omapip/support.c
new file mode 100644
index 0000000..48592d4
--- /dev/null
+++ b/omapip/support.c
@@ -0,0 +1,853 @@
+/* support.c
+
+ Subroutines providing general support for objects. */
+
+/*
+ * Copyright (c) 2012,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+
+omapi_object_type_t *omapi_type_connection;
+omapi_object_type_t *omapi_type_listener;
+omapi_object_type_t *omapi_type_io_object;
+omapi_object_type_t *omapi_type_datagram;
+omapi_object_type_t *omapi_type_generic;
+omapi_object_type_t *omapi_type_protocol;
+omapi_object_type_t *omapi_type_protocol_listener;
+omapi_object_type_t *omapi_type_waiter;
+omapi_object_type_t *omapi_type_remote;
+omapi_object_type_t *omapi_type_message;
+omapi_object_type_t *omapi_type_auth_key;
+
+omapi_object_type_t *omapi_object_types;
+int omapi_object_type_count;
+
+#if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+void omapi_type_relinquish ()
+{
+ omapi_object_type_t *t, *n;
+
+ for (t = omapi_object_types; t; t = n) {
+ n = t -> next;
+ dfree (t, MDL);
+ }
+ omapi_object_types = (omapi_object_type_t *)0;
+}
+#endif
+
+isc_result_t omapi_init (void)
+{
+ isc_result_t status;
+
+ /* Register all the standard object types... */
+ status = omapi_object_type_register (&omapi_type_connection,
+ "connection",
+ omapi_connection_set_value,
+ omapi_connection_get_value,
+ omapi_connection_destroy,
+ omapi_connection_signal_handler,
+ omapi_connection_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof
+ (omapi_connection_object_t), 0,
+ RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_listener,
+ "listener",
+ omapi_listener_set_value,
+ omapi_listener_get_value,
+ omapi_listener_destroy,
+ omapi_listener_signal_handler,
+ omapi_listener_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_listener_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_io_object,
+ "io",
+ omapi_io_set_value,
+ omapi_io_get_value,
+ omapi_io_destroy,
+ omapi_io_signal_handler,
+ omapi_io_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_io_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_generic,
+ "generic",
+ omapi_generic_set_value,
+ omapi_generic_get_value,
+ omapi_generic_destroy,
+ omapi_generic_signal_handler,
+ omapi_generic_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_generic_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_protocol,
+ "protocol",
+ omapi_protocol_set_value,
+ omapi_protocol_get_value,
+ omapi_protocol_destroy,
+ omapi_protocol_signal_handler,
+ omapi_protocol_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_protocol_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = (omapi_object_type_register
+ (&omapi_type_protocol_listener, "protocol-listener",
+ omapi_protocol_listener_set_value,
+ omapi_protocol_listener_get_value,
+ omapi_protocol_listener_destroy,
+ omapi_protocol_listener_signal,
+ omapi_protocol_listener_stuff,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_protocol_listener_object_t), 0, RC_MISC));
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_message,
+ "message",
+ omapi_message_set_value,
+ omapi_message_get_value,
+ omapi_message_destroy,
+ omapi_message_signal_handler,
+ omapi_message_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_message_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_waiter,
+ "waiter",
+ 0,
+ 0,
+ 0,
+ omapi_waiter_signal_handler, 0,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_waiter_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_auth_key,
+ "authenticator",
+ 0,
+ omapi_auth_key_get_value,
+ omapi_auth_key_destroy,
+ 0,
+ omapi_auth_key_stuff_values,
+ omapi_auth_key_lookup,
+ 0, 0, 0, 0, 0,
+ sizeof (omapi_auth_key_t), 0,
+ RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+#if defined (TRACING)
+ omapi_listener_trace_setup ();
+ omapi_connection_trace_setup ();
+ omapi_buffer_trace_setup ();
+#endif
+
+ /* This seems silly, but leave it. */
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_object_type_register (omapi_object_type_t **type,
+ const char *name,
+ isc_result_t (*set_value)
+ (omapi_object_t *,
+ omapi_object_t *,
+ omapi_data_string_t *,
+ omapi_typed_data_t *),
+ isc_result_t (*get_value)
+ (omapi_object_t *,
+ omapi_object_t *,
+ omapi_data_string_t *,
+ omapi_value_t **),
+ isc_result_t (*destroy)
+ (omapi_object_t *,
+ const char *, int),
+ isc_result_t (*signal_handler)
+ (omapi_object_t *,
+ const char *, va_list),
+ isc_result_t (*stuff_values)
+ (omapi_object_t *,
+ omapi_object_t *,
+ omapi_object_t *),
+ isc_result_t (*lookup)
+ (omapi_object_t **,
+ omapi_object_t *,
+ omapi_object_t *),
+ isc_result_t (*create)
+ (omapi_object_t **,
+ omapi_object_t *),
+ isc_result_t (*remove)
+ (omapi_object_t *,
+ omapi_object_t *),
+ isc_result_t (*freer)
+ (omapi_object_t *,
+ const char *, int),
+ isc_result_t (*allocator)
+ (omapi_object_t **,
+ const char *, int),
+ isc_result_t (*sizer) (size_t),
+ size_t size,
+ isc_result_t (*initialize)
+ (omapi_object_t *,
+ const char *, int),
+ int rc_flag)
+{
+ omapi_object_type_t *t;
+
+ t = dmalloc (sizeof *t, MDL);
+ if (!t)
+ return ISC_R_NOMEMORY;
+ memset (t, 0, sizeof *t);
+
+ t -> name = name;
+ t -> set_value = set_value;
+ t -> get_value = get_value;
+ t -> destroy = destroy;
+ t -> signal_handler = signal_handler;
+ t -> stuff_values = stuff_values;
+ t -> lookup = lookup;
+ t -> create = create;
+ t -> remove = remove;
+ t -> next = omapi_object_types;
+ t -> sizer = sizer;
+ t -> size = size;
+ t -> freer = freer;
+ t -> allocator = allocator;
+ t -> initialize = initialize;
+ t -> rc_flag = rc_flag;
+ omapi_object_types = t;
+ if (type)
+ *type = t;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_signal (omapi_object_t *handle, const char *name, ...)
+{
+ va_list ap;
+ omapi_object_t *outer;
+ isc_result_t status;
+
+ va_start (ap, name);
+ for (outer = handle; outer -> outer; outer = outer -> outer)
+ ;
+ if (outer -> type -> signal_handler)
+ status = (*(outer -> type -> signal_handler)) (outer,
+ name, ap);
+ else
+ status = ISC_R_NOTFOUND;
+ va_end (ap);
+ return status;
+}
+
+isc_result_t omapi_signal_in (omapi_object_t *handle, const char *name, ...)
+{
+ va_list ap;
+ isc_result_t status;
+
+ if (!handle)
+ return ISC_R_NOTFOUND;
+ va_start (ap, name);
+
+ if (handle -> type -> signal_handler)
+ status = (*(handle -> type -> signal_handler)) (handle,
+ name, ap);
+ else
+ status = ISC_R_NOTFOUND;
+ va_end (ap);
+ return status;
+}
+
+isc_result_t omapi_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ omapi_object_t *outer;
+ isc_result_t status;
+
+#if defined (DEBUG)
+ if (!value) {
+ log_info ("omapi_set_value (%.*s, NULL)",
+ (int)name -> len, name -> value);
+ } else if (value -> type == omapi_datatype_int) {
+ log_info ("omapi_set_value (%.*s, %ld)",
+ (int)name -> len, name -> value,
+ (long)value -> u.integer);
+ } else if (value -> type == omapi_datatype_string) {
+ log_info ("omapi_set_value (%.*s, %.*s)",
+ (int)name -> len, name -> value,
+ (int)value -> u.buffer.len, value -> u.buffer.value);
+ } else if (value -> type == omapi_datatype_data) {
+ log_info ("omapi_set_value (%.*s, %ld %lx)",
+ (int)name -> len, name -> value,
+ (long)value -> u.buffer.len,
+ (unsigned long)value -> u.buffer.value);
+ } else if (value -> type == omapi_datatype_object) {
+ log_info ("omapi_set_value (%.*s, %s)",
+ (int)name -> len, name -> value,
+ value -> u.object
+ ? (value -> u.object -> type
+ ? value -> u.object -> type -> name
+ : "(unknown object)")
+ : "(unknown object)");
+ }
+#endif
+
+ for (outer = h; outer -> outer; outer = outer -> outer)
+ ;
+ if (outer -> type -> set_value)
+ status = (*(outer -> type -> set_value)) (outer,
+ id, name, value);
+ else
+ status = ISC_R_NOTFOUND;
+#if defined (DEBUG)
+ log_info (" ==> %s", isc_result_totext (status));
+#endif
+ return status;
+}
+
+isc_result_t omapi_set_value_str (omapi_object_t *h,
+ omapi_object_t *id,
+ const char *name,
+ omapi_typed_data_t *value)
+{
+ omapi_data_string_t *nds;
+ isc_result_t status;
+
+ nds = (omapi_data_string_t *)0;
+ status = omapi_data_string_new (&nds, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (nds -> value, name, strlen (name));
+
+ status = omapi_set_value (h, id, nds, value);
+ omapi_data_string_dereference (&nds, MDL);
+ return status;
+}
+
+isc_result_t omapi_set_boolean_value (omapi_object_t *h, omapi_object_t *id,
+ const char *name, int value)
+{
+ isc_result_t status;
+ omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
+ omapi_data_string_t *n = (omapi_data_string_t *)0;
+
+ status = omapi_data_string_new (&n, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (n -> value, name, strlen (name));
+
+ status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_data_string_dereference (&n, MDL);
+ return status;
+ }
+
+ status = omapi_set_value (h, id, n, tv);
+ omapi_data_string_dereference (&n, MDL);
+ omapi_typed_data_dereference (&tv, MDL);
+ return status;
+}
+
+isc_result_t omapi_set_int_value (omapi_object_t *h, omapi_object_t *id,
+ const char *name, int value)
+{
+ isc_result_t status;
+ omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
+ omapi_data_string_t *n = (omapi_data_string_t *)0;
+
+ status = omapi_data_string_new (&n, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (n -> value, name, strlen (name));
+
+ status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_data_string_dereference (&n, MDL);
+ return status;
+ }
+
+ status = omapi_set_value (h, id, n, tv);
+ omapi_data_string_dereference (&n, MDL);
+ omapi_typed_data_dereference (&tv, MDL);
+ return status;
+}
+
+isc_result_t omapi_set_object_value (omapi_object_t *h, omapi_object_t *id,
+ const char *name, omapi_object_t *value)
+{
+ isc_result_t status;
+ omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
+ omapi_data_string_t *n = (omapi_data_string_t *)0;
+
+ status = omapi_data_string_new (&n, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (n -> value, name, strlen (name));
+
+ status = omapi_typed_data_new (MDL, &tv, omapi_datatype_object, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_data_string_dereference (&n, MDL);
+ return status;
+ }
+
+ status = omapi_set_value (h, id, n, tv);
+ omapi_data_string_dereference (&n, MDL);
+ omapi_typed_data_dereference (&tv, MDL);
+ return status;
+}
+
+isc_result_t omapi_set_string_value (omapi_object_t *h, omapi_object_t *id,
+ const char *name, const char *value)
+{
+ isc_result_t status;
+ omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
+ omapi_data_string_t *n = (omapi_data_string_t *)0;
+
+ status = omapi_data_string_new (&n, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (n -> value, name, strlen (name));
+
+ status = omapi_typed_data_new (MDL, &tv, omapi_datatype_string, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_data_string_dereference (&n, MDL);
+ return status;
+ }
+
+ status = omapi_set_value (h, id, n, tv);
+ omapi_data_string_dereference (&n, MDL);
+ omapi_typed_data_dereference (&tv, MDL);
+ return status;
+}
+
+isc_result_t omapi_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ omapi_object_t *outer;
+
+ for (outer = h; outer -> outer; outer = outer -> outer)
+ ;
+ if (outer -> type -> get_value)
+ return (*(outer -> type -> get_value)) (outer,
+ id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_get_value_str (omapi_object_t *h,
+ omapi_object_t *id,
+ const char *name,
+ omapi_value_t **value)
+{
+ omapi_object_t *outer;
+ omapi_data_string_t *nds;
+ isc_result_t status;
+
+ nds = (omapi_data_string_t *)0;
+ status = omapi_data_string_new (&nds, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (nds -> value, name, strlen (name));
+
+ for (outer = h; outer -> outer; outer = outer -> outer)
+ ;
+ if (outer -> type -> get_value)
+ status = (*(outer -> type -> get_value)) (outer,
+ id, nds, value);
+ else
+ status = ISC_R_NOTFOUND;
+ omapi_data_string_dereference (&nds, MDL);
+ return status;
+}
+
+isc_result_t omapi_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *o)
+{
+ omapi_object_t *outer;
+
+ for (outer = o; outer -> outer; outer = outer -> outer)
+ ;
+ if (outer -> type -> stuff_values)
+ return (*(outer -> type -> stuff_values)) (c, id, outer);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_object_create (omapi_object_t **obj, omapi_object_t *id,
+ omapi_object_type_t *type)
+{
+ if (!type -> create)
+ return ISC_R_NOTIMPLEMENTED;
+ return (*(type -> create)) (obj, id);
+}
+
+isc_result_t omapi_object_update (omapi_object_t *obj, omapi_object_t *id,
+ omapi_object_t *src, omapi_handle_t handle)
+{
+ omapi_generic_object_t *gsrc;
+ isc_result_t status;
+ int i;
+
+ if (!src)
+ return DHCP_R_INVALIDARG;
+ if (src -> type != omapi_type_generic)
+ return ISC_R_NOTIMPLEMENTED;
+ gsrc = (omapi_generic_object_t *)src;
+ for (i = 0; i < gsrc -> nvalues; i++) {
+ status = omapi_set_value (obj, id,
+ gsrc -> values [i] -> name,
+ gsrc -> values [i] -> value);
+ if (status != ISC_R_SUCCESS && status != DHCP_R_UNCHANGED)
+ return status;
+ }
+
+ /*
+ * For now ignore the return value. I'm not sure if we want to
+ * generate an error if we can't set the handle value. If we
+ * do add a check we probably should allow unchanged and notfound
+ */
+ if (handle)
+ (void) omapi_set_int_value (obj, id, "remote-handle", (int)handle);
+ status = omapi_signal (obj, "updated");
+ if (status != ISC_R_NOTFOUND)
+ return status;
+ return ISC_R_SUCCESS;
+}
+
+int omapi_data_string_cmp (omapi_data_string_t *s1, omapi_data_string_t *s2)
+{
+ unsigned len;
+ int rv;
+
+ if (s1 -> len > s2 -> len)
+ len = s2 -> len;
+ else
+ len = s1 -> len;
+ rv = memcmp (s1 -> value, s2 -> value, len);
+ if (rv)
+ return rv;
+ if (s1 -> len > s2 -> len)
+ return 1;
+ else if (s1 -> len < s2 -> len)
+ return -1;
+ return 0;
+}
+
+int omapi_ds_strcmp (omapi_data_string_t *s1, const char *s2)
+{
+ unsigned len, slen;
+ int rv;
+
+ slen = strlen (s2);
+ if (slen > s1 -> len)
+ len = s1 -> len;
+ else
+ len = slen;
+ rv = memcmp (s1 -> value, s2, len);
+ if (rv)
+ return rv;
+ if (s1 -> len > slen)
+ return 1;
+ else if (s1 -> len < slen)
+ return -1;
+ return 0;
+}
+
+int omapi_td_strcmp (omapi_typed_data_t *s1, const char *s2)
+{
+ unsigned len, slen;
+ int rv;
+
+ /* If the data type is not compatible, never equal. */
+ if (s1 -> type != omapi_datatype_data &&
+ s1 -> type != omapi_datatype_string)
+ return -1;
+
+ slen = strlen (s2);
+ if (slen > s1 -> u.buffer.len)
+ len = s1 -> u.buffer.len;
+ else
+ len = slen;
+ rv = memcmp (s1 -> u.buffer.value, s2, len);
+ if (rv)
+ return rv;
+ if (s1 -> u.buffer.len > slen)
+ return 1;
+ else if (s1 -> u.buffer.len < slen)
+ return -1;
+ return 0;
+}
+
+int omapi_td_strcasecmp (omapi_typed_data_t *s1, const char *s2)
+{
+ unsigned len, slen;
+ int rv;
+
+ /* If the data type is not compatible, never equal. */
+ if (s1 -> type != omapi_datatype_data &&
+ s1 -> type != omapi_datatype_string)
+ return -1;
+
+ slen = strlen (s2);
+ if (slen > s1 -> u.buffer.len)
+ len = s1 -> u.buffer.len;
+ else
+ len = slen;
+ rv = casecmp (s1 -> u.buffer.value, s2, len);
+ if (rv)
+ return rv;
+ if (s1 -> u.buffer.len > slen)
+ return 1;
+ else if (s1 -> u.buffer.len < slen)
+ return -1;
+ return 0;
+}
+
+isc_result_t omapi_make_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value,
+ const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ if (value) {
+ status = omapi_typed_data_reference (&(*vp) -> value,
+ value, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_make_const_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ const unsigned char *value,
+ unsigned len,
+ const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ if (value) {
+ status = omapi_typed_data_new (file, line, &(*vp) -> value,
+ omapi_datatype_data, len);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ memcpy ((*vp) -> value -> u.buffer.value, value, len);
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_make_int_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ int value, const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ status = omapi_typed_data_new (file, line, &(*vp) -> value,
+ omapi_datatype_int, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_make_uint_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ unsigned int value,
+ const char *file, int line)
+{
+ return omapi_make_int_value (vp, name, (int)value, file, line);
+}
+
+isc_result_t omapi_make_object_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ omapi_object_t *value,
+ const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+
+ if (value) {
+ status = omapi_typed_data_new (file, line, &(*vp) -> value,
+ omapi_datatype_object, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_make_handle_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ omapi_object_t *value,
+ const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ if (value) {
+ status = omapi_typed_data_new (file, line, &(*vp) -> value,
+ omapi_datatype_int);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ status = (omapi_object_handle
+ ((omapi_handle_t *)&(*vp) -> value -> u.integer,
+ value));
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_make_string_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ const char *value,
+ const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ if (value) {
+ status = omapi_typed_data_new (file, line, &(*vp) -> value,
+ omapi_datatype_string, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_get_int_value (unsigned long *v, omapi_typed_data_t *t)
+{
+ u_int32_t rv;
+
+ if (t -> type == omapi_datatype_int) {
+ *v = t -> u.integer;
+ return ISC_R_SUCCESS;
+ } else if (t -> type == omapi_datatype_string ||
+ t -> type == omapi_datatype_data) {
+ if (t -> u.buffer.len != sizeof (rv))
+ return DHCP_R_INVALIDARG;
+ memcpy (&rv, t -> u.buffer.value, sizeof rv);
+ *v = ntohl (rv);
+ return ISC_R_SUCCESS;
+ }
+ return DHCP_R_INVALIDARG;
+}
diff --git a/omapip/test.c b/omapip/test.c
new file mode 100644
index 0000000..9183108
--- /dev/null
+++ b/omapip/test.c
@@ -0,0 +1,110 @@
+/* test.c
+
+ Test code for omapip... */
+
+/*
+ * Copyright (c) 2009-2010,2013-2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "config.h"
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <omapip/result.h>
+#include <sys/time.h>
+#include <omapip/omapip.h>
+#include <omapip/isclib.h>
+
+int main (int argc, char **argv)
+{
+ omapi_object_t *listener = (omapi_object_t*)0;
+ omapi_object_t *connection = (omapi_object_t*)0;
+ isc_result_t status;
+
+ status = dhcp_context_create();
+ if (status != ISC_R_SUCCESS) {
+ fprintf(stderr, "Can't initialize context: %s\n",
+ isc_result_totext(status));
+ exit(1);
+ }
+
+ status = omapi_init ();
+ if (status != ISC_R_SUCCESS) {
+ fprintf(stderr, "omapi_init failed: %s\n",
+ isc_result_totext(status));
+ exit(1);
+ }
+
+ if (argc > 1 && !strcmp (argv [1], "listen")) {
+ if (argc < 3) {
+ fprintf (stderr, "Usage: test listen port\n");
+ exit (1);
+ }
+ status = omapi_generic_new (&listener, MDL);
+ if (status != ISC_R_SUCCESS) {
+ fprintf (stderr, "omapi_generic_new: %s\n",
+ isc_result_totext (status));
+ exit (1);
+ }
+ status = omapi_protocol_listen (listener,
+ (unsigned)atoi (argv [2]), 1);
+ if (status != ISC_R_SUCCESS) {
+ fprintf (stderr, "omapi_listen: %s\n",
+ isc_result_totext (status));
+ exit (1);
+ }
+ omapi_dispatch (0);
+ } else if (argc > 1 && !strcmp (argv [1], "connect")) {
+ if (argc < 4) {
+ fprintf (stderr, "Usage: test listen address port\n");
+ exit (1);
+ }
+ status = omapi_generic_new (&connection, MDL);
+ if (status != ISC_R_SUCCESS) {
+ fprintf (stderr, "omapi_generic_new: %s\n",
+ isc_result_totext (status));
+ exit (1);
+ }
+ status = omapi_protocol_connect (connection,
+ argv [2],
+ (unsigned)atoi (argv [3]), 0);
+ fprintf (stderr, "connect: %s\n", isc_result_totext (status));
+ if (status != ISC_R_SUCCESS)
+ exit (1);
+ status = omapi_wait_for_completion (connection, 0);
+ fprintf (stderr, "completion: %s\n",
+ isc_result_totext (status));
+ if (status != ISC_R_SUCCESS)
+ exit (1);
+ /* ... */
+ } else {
+ fprintf (stderr, "Usage: test [listen | connect] ...\n");
+ exit (1);
+ }
+
+ return 0;
+}
diff --git a/omapip/toisc.c b/omapip/toisc.c
new file mode 100644
index 0000000..07aa251
--- /dev/null
+++ b/omapip/toisc.c
@@ -0,0 +1,211 @@
+/* toisc.c
+
+ Convert non-ISC result codes to ISC result codes. */
+
+/*
+ * Copyright (c) 2004,2007,2009,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2001-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+#include "arpa/nameser.h"
+#include "minires.h"
+
+#include <errno.h>
+
+isc_result_t uerr2isc (int err)
+{
+ switch (err) {
+ case EPERM:
+ return ISC_R_NOPERM;
+
+ case ENOENT:
+ return ISC_R_NOTFOUND;
+
+ case ESRCH:
+ return ISC_R_NOTFOUND;
+
+ case EIO:
+ return ISC_R_IOERROR;
+
+ case ENXIO:
+ return ISC_R_NOTFOUND;
+
+ case E2BIG:
+ return ISC_R_NOSPACE;
+
+ case ENOEXEC:
+ return DHCP_R_FORMERR;
+
+ case ECHILD:
+ return ISC_R_NOTFOUND;
+
+ case ENOMEM:
+ return ISC_R_NOMEMORY;
+
+ case EACCES:
+ return ISC_R_NOPERM;
+
+ case EFAULT:
+ return DHCP_R_INVALIDARG;
+
+ case EEXIST:
+ return ISC_R_EXISTS;
+
+ case EINVAL:
+ return DHCP_R_INVALIDARG;
+
+ case ENOTTY:
+ return DHCP_R_INVALIDARG;
+
+ case EFBIG:
+ return ISC_R_NOSPACE;
+
+ case ENOSPC:
+ return ISC_R_NOSPACE;
+
+ case EROFS:
+ return ISC_R_NOPERM;
+
+ case EMLINK:
+ return ISC_R_NOSPACE;
+
+ case EPIPE:
+ return ISC_R_NOTCONNECTED;
+
+ case EINPROGRESS:
+ return ISC_R_ALREADYRUNNING;
+
+ case EALREADY:
+ return ISC_R_ALREADYRUNNING;
+
+ case ENOTSOCK:
+ return ISC_R_INVALIDFILE;
+
+ case EDESTADDRREQ:
+ return DHCP_R_DESTADDRREQ;
+
+ case EMSGSIZE:
+ return ISC_R_NOSPACE;
+
+ case EPROTOTYPE:
+ return DHCP_R_INVALIDARG;
+
+ case ENOPROTOOPT:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case EPROTONOSUPPORT:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case ESOCKTNOSUPPORT:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case EOPNOTSUPP:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case EPFNOSUPPORT:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case EAFNOSUPPORT:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case EADDRINUSE:
+ return ISC_R_ADDRINUSE;
+
+ case EADDRNOTAVAIL:
+ return ISC_R_ADDRNOTAVAIL;
+
+ case ENETDOWN:
+ return ISC_R_NETDOWN;
+
+ case ENETUNREACH:
+ return ISC_R_NETUNREACH;
+
+ case ECONNABORTED:
+ return ISC_R_TIMEDOUT;
+
+ case ECONNRESET:
+ return DHCP_R_CONNRESET;
+
+ case ENOBUFS:
+ return ISC_R_NOSPACE;
+
+ case EISCONN:
+ return ISC_R_ALREADYRUNNING;
+
+ case ENOTCONN:
+ return ISC_R_NOTCONNECTED;
+
+ case ESHUTDOWN:
+ return ISC_R_SHUTTINGDOWN;
+
+ case ETIMEDOUT:
+ return ISC_R_TIMEDOUT;
+
+ case ECONNREFUSED:
+ return ISC_R_CONNREFUSED;
+
+ case EHOSTDOWN:
+ return ISC_R_HOSTDOWN;
+
+ case EHOSTUNREACH:
+ return ISC_R_HOSTUNREACH;
+
+#ifdef EDQUOT
+ case EDQUOT:
+ return ISC_R_QUOTA;
+#endif
+
+#ifdef EBADRPC
+ case EBADRPC:
+ return ISC_R_NOTIMPLEMENTED;
+#endif
+
+#ifdef ERPCMISMATCH
+ case ERPCMISMATCH:
+ return DHCP_R_VERSIONMISMATCH;
+#endif
+
+#ifdef EPROGMISMATCH
+ case EPROGMISMATCH:
+ return DHCP_R_VERSIONMISMATCH;
+#endif
+
+#ifdef EAUTH
+ case EAUTH:
+ return DHCP_R_NOTAUTH;
+#endif
+
+#ifdef ENEEDAUTH
+ case ENEEDAUTH:
+ return DHCP_R_NOTAUTH;
+#endif
+
+#ifdef EOVERFLOW
+ case EOVERFLOW:
+ return ISC_R_NOSPACE;
+#endif
+ }
+ return ISC_R_UNEXPECTED;
+}
diff --git a/omapip/trace.c b/omapip/trace.c
new file mode 100644
index 0000000..f4115c1
--- /dev/null
+++ b/omapip/trace.c
@@ -0,0 +1,719 @@
+/* trace.c
+
+ Subroutines that support tracing of OMAPI wire transactions and
+ provide a mechanism for programs using OMAPI to trace their own
+ transactions... */
+
+/*
+ * Copyright (c) 2012,2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2001-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ */
+
+#include "dhcpd.h"
+#include <omapip/omapip_p.h>
+#include <errno.h>
+
+#if defined (TRACING)
+void (*trace_set_time_hook) (TIME);
+static int tracing_stopped;
+static int traceoutfile;
+static int traceindex;
+static trace_type_t **trace_types;
+static int trace_type_count;
+static int trace_type_max;
+static trace_type_t *new_trace_types;
+static FILE *traceinfile;
+static tracefile_header_t tracefile_header;
+static int trace_playback_flag;
+trace_type_t trace_time_marker;
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+extern omapi_array_t *trace_listeners;
+extern omapi_array_t *omapi_connections;
+
+extern int errno;
+
+void trace_free_all ()
+{
+ trace_type_t *tp;
+ int i;
+ tp = new_trace_types;
+ while (tp) {
+ new_trace_types = tp -> next;
+ if (tp -> name) {
+ dfree (tp -> name, MDL);
+ tp -> name = (char *)0;
+ }
+ dfree (tp, MDL);
+ tp = new_trace_types;
+ }
+ for (i = 0; i < trace_type_count; i++) {
+ if (trace_types [i]) {
+ if (trace_types [i] -> name)
+ dfree (trace_types [i] -> name, MDL);
+ dfree (trace_types [i], MDL);
+ }
+ }
+ dfree (trace_types, MDL);
+ trace_types = (trace_type_t **)0;
+ trace_type_count = trace_type_max = 0;
+
+ omapi_array_free (&trace_listeners, MDL);
+ omapi_array_free (&omapi_connections, MDL);
+}
+#endif
+
+static isc_result_t trace_type_record (trace_type_t *,
+ unsigned, const char *, int);
+
+int trace_playback ()
+{
+ return trace_playback_flag;
+}
+
+int trace_record ()
+{
+ if (traceoutfile && !tracing_stopped)
+ return 1;
+ return 0;
+}
+
+isc_result_t trace_init (void (*set_time) (TIME),
+ const char *file, int line)
+{
+ trace_type_t *root_type;
+ static int root_setup = 0;
+
+ if (root_setup)
+ return ISC_R_SUCCESS;
+
+ trace_set_time_hook = set_time;
+
+ root_type = trace_type_register ("trace-index-mapping",
+ (void *)0, trace_index_map_input,
+ trace_index_stop_tracing, file, line);
+ if (!root_type)
+ return ISC_R_UNEXPECTED;
+ if (new_trace_types == root_type)
+ new_trace_types = new_trace_types -> next;
+ root_type -> index = 0;
+ trace_type_stash (root_type);
+
+ root_setup = 1;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t trace_begin (const char *filename,
+ const char *file, int line)
+{
+ tracefile_header_t tfh;
+ int status;
+ trace_type_t *tptr, *next;
+ isc_result_t result;
+
+ if (traceoutfile) {
+ log_error ("%s(%d): trace_begin called twice",
+ file, line);
+ return DHCP_R_INVALIDARG;
+ }
+
+ traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL, 0600);
+ if (traceoutfile < 0 && errno == EEXIST) {
+ log_error ("WARNING: Overwriting trace file \"%s\"", filename);
+ traceoutfile = open (filename, O_WRONLY | O_EXCL | O_TRUNC,
+ 0600);
+ }
+
+ if (traceoutfile < 0) {
+ log_error ("%s(%d): trace_begin: %s: %m",
+ file, line, filename);
+ return ISC_R_UNEXPECTED;
+ }
+#if defined (HAVE_SETFD)
+ if (fcntl (traceoutfile, F_SETFD, 1) < 0)
+ log_error ("Can't set close-on-exec on %s: %m", filename);
+#endif
+
+ tfh.magic = htonl (TRACEFILE_MAGIC);
+ tfh.version = htonl (TRACEFILE_VERSION);
+ tfh.hlen = htonl (sizeof (tracefile_header_t));
+ tfh.phlen = htonl (sizeof (tracepacket_t));
+
+ status = write (traceoutfile, &tfh, sizeof tfh);
+ if (status < 0) {
+ log_error ("%s(%d): trace_begin write failed: %m", file, line);
+ return ISC_R_UNEXPECTED;
+ } else if (status != sizeof tfh) {
+ log_error ("%s(%d): trace_begin: short write (%d:%ld)",
+ file, line, status, (long)(sizeof tfh));
+ trace_stop ();
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* Stash all the types that have already been set up. */
+ if (new_trace_types) {
+ next = new_trace_types;
+ new_trace_types = (trace_type_t *)0;
+ for (tptr = next; tptr; tptr = next) {
+ next = tptr -> next;
+ if (tptr -> index != 0) {
+ result = (trace_type_record
+ (tptr,
+ strlen (tptr -> name), file, line));
+ if (result != ISC_R_SUCCESS)
+ return status;
+ }
+ }
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t trace_write_packet (trace_type_t *ttype, unsigned length,
+ const char *buf, const char *file, int line)
+{
+ trace_iov_t iov;
+
+ iov.buf = buf;
+ iov.len = length;
+ return trace_write_packet_iov (ttype, 1, &iov, file, line);
+}
+
+isc_result_t trace_write_packet_iov (trace_type_t *ttype,
+ int count, trace_iov_t *iov,
+ const char *file, int line)
+{
+ tracepacket_t tmp;
+ int status;
+ int i;
+ int length;
+
+ /* Really shouldn't get called here, but it may be hard to turn off
+ tracing midstream if the trace file write fails or something. */
+ if (tracing_stopped)
+ return 0;
+
+ if (!ttype) {
+ log_error ("%s(%d): trace_write_packet with null trace type",
+ file ? file : "<unknown file>", line);
+ return DHCP_R_INVALIDARG;
+ }
+ if (!traceoutfile) {
+ log_error ("%s(%d): trace_write_packet with no tracefile.",
+ file ? file : "<unknown file>", line);
+ return DHCP_R_INVALIDARG;
+ }
+
+ /* Compute the total length of the iov. */
+ length = 0;
+ for (i = 0; i < count; i++)
+ length += iov [i].len;
+
+ /* We have to swap out the data, because it may be read back on a
+ machine of different endianness. */
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type_index = htonl (ttype -> index);
+ tmp.when = htonl (time ((time_t *)0)); /* XXX */
+ tmp.length = htonl (length);
+
+ status = write (traceoutfile, &tmp, sizeof tmp);
+ if (status < 0) {
+ log_error ("%s(%d): trace_write_packet write failed: %m",
+ file, line);
+ return ISC_R_UNEXPECTED;
+ } else if (status != sizeof tmp) {
+ log_error ("%s(%d): trace_write_packet: short write (%d:%ld)",
+ file, line, status, (long)(sizeof tmp));
+ trace_stop ();
+ }
+
+ for (i = 0; i < count; i++) {
+ status = write (traceoutfile, iov [i].buf, iov [i].len);
+ if (status < 0) {
+ log_error ("%s(%d): %s write failed: %m",
+ file, line, "trace_write_packet");
+ return ISC_R_UNEXPECTED;
+ } else if (status != iov [i].len) {
+ log_error ("%s(%d): %s: short write (%d:%d)",
+ file, line,
+ "trace_write_packet", status, length);
+ trace_stop ();
+ }
+ }
+
+ /* Write padding on the end of the packet to align the next
+ packet to an 8-byte boundary. This is in case we decide to
+ use mmap in some clever way later on. */
+ if (length % 8) {
+ static char zero [] = { 0, 0, 0, 0, 0, 0, 0 };
+ unsigned padl = 8 - (length % 8);
+
+ status = write (traceoutfile, zero, padl);
+ if (status < 0) {
+ log_error ("%s(%d): trace_write_packet write failed: %m",
+ file, line);
+ return ISC_R_UNEXPECTED;
+ } else if (status != padl) {
+ log_error ("%s(%d): trace_write_packet: short write (%d:%d)",
+ file, line, status, padl);
+ trace_stop ();
+ }
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+void trace_type_stash (trace_type_t *tptr)
+{
+ trace_type_t **vec;
+ int delta;
+ if (trace_type_max <= tptr -> index) {
+ delta = tptr -> index - trace_type_max + 10;
+ vec = dmalloc (((trace_type_max + delta) *
+ sizeof (trace_type_t *)), MDL);
+ if (!vec)
+ return;
+ memset (&vec [trace_type_max], 0,
+ (sizeof (trace_type_t *)) * delta);
+ trace_type_max += delta;
+ if (trace_types) {
+ memcpy (vec, trace_types,
+ trace_type_count * sizeof (trace_type_t *));
+ dfree (trace_types, MDL);
+ }
+ trace_types = vec;
+ }
+ trace_types [tptr -> index] = tptr;
+ if (tptr -> index >= trace_type_count)
+ trace_type_count = tptr -> index + 1;
+}
+
+trace_type_t *trace_type_register (const char *name,
+ void *baggage,
+ void (*have_packet) (trace_type_t *,
+ unsigned, char *),
+ void (*stop_tracing) (trace_type_t *),
+ const char *file, int line)
+{
+ trace_type_t *ttmp;
+ unsigned slen = strlen (name);
+ isc_result_t status;
+
+ ttmp = dmalloc (sizeof *ttmp, file, line);
+ if (!ttmp)
+ return ttmp;
+ ttmp -> index = -1;
+ ttmp -> name = dmalloc (slen + 1, file, line);
+ if (!ttmp -> name) {
+ dfree (ttmp, file, line);
+ return (trace_type_t *)0;
+ }
+ strcpy (ttmp -> name, name);
+ ttmp -> have_packet = have_packet;
+ ttmp -> stop_tracing = stop_tracing;
+
+ if (traceoutfile) {
+ status = trace_type_record (ttmp, slen, file, line);
+ if (status != ISC_R_SUCCESS) {
+ dfree (ttmp -> name, file, line);
+ dfree (ttmp, file, line);
+ return (trace_type_t *)0;
+ }
+ } else {
+ ttmp -> next = new_trace_types;
+ new_trace_types = ttmp;
+ }
+
+ return ttmp;
+}
+
+static isc_result_t trace_type_record (trace_type_t *ttmp, unsigned slen,
+ const char *file, int line)
+{
+ trace_index_mapping_t *tim;
+ isc_result_t status;
+
+ tim = dmalloc (slen + TRACE_INDEX_MAPPING_SIZE, file, line);
+ if (!tim)
+ return ISC_R_NOMEMORY;
+ ttmp -> index = ++traceindex;
+ trace_type_stash (ttmp);
+ tim -> index = htonl (ttmp -> index);
+ memcpy (tim -> name, ttmp -> name, slen);
+ status = trace_write_packet (trace_types [0],
+ slen + TRACE_INDEX_MAPPING_SIZE,
+ (char *)tim, file, line);
+ dfree (tim, file, line);
+ return status;
+}
+
+/* Stop all registered trace types from trying to trace. */
+
+void trace_stop (void)
+{
+ int i;
+
+ for (i = 0; i < trace_type_count; i++)
+ if (trace_types [i] -> stop_tracing)
+ (*(trace_types [i] -> stop_tracing))
+ (trace_types [i]);
+ tracing_stopped = 1;
+}
+
+void trace_index_map_input (trace_type_t *ttype, unsigned length, char *buf)
+{
+ trace_index_mapping_t *tmap;
+ unsigned len;
+ trace_type_t *tptr, **prev;
+
+ if (length < TRACE_INDEX_MAPPING_SIZE) {
+ log_error ("short trace index mapping");
+ return;
+ }
+ tmap = (trace_index_mapping_t *)buf;
+
+ prev = &new_trace_types;
+ for (tptr = new_trace_types; tptr; tptr = tptr -> next) {
+ len = strlen (tptr -> name);
+ if (len == length - TRACE_INDEX_MAPPING_SIZE &&
+ !memcmp (tptr -> name, tmap -> name, len)) {
+ tptr -> index = ntohl (tmap -> index);
+ trace_type_stash (tptr);
+ *prev = tptr -> next;
+ return;
+ }
+ prev = &tptr -> next;
+ }
+
+ log_error ("No registered trace type for type name %.*s",
+ (int)length - TRACE_INDEX_MAPPING_SIZE, tmap -> name);
+ return;
+}
+
+void trace_index_stop_tracing (trace_type_t *ttype) { }
+
+void trace_replay_init (void)
+{
+ trace_playback_flag = 1;
+}
+
+void trace_file_replay (const char *filename)
+{
+ tracepacket_t *tpkt = NULL;
+ int status;
+ char *buf = NULL;
+ unsigned buflen;
+ unsigned bufmax = 0;
+ trace_type_t *ttype = NULL;
+ isc_result_t result;
+ int len;
+
+ traceinfile = fopen (filename, "r");
+ if (!traceinfile) {
+ log_error("Can't open tracefile %s: %m", filename);
+ return;
+ }
+#if defined (HAVE_SETFD)
+ if (fcntl (fileno(traceinfile), F_SETFD, 1) < 0)
+ log_error("Can't set close-on-exec on %s: %m", filename);
+#endif
+ status = fread(&tracefile_header, 1,
+ sizeof tracefile_header, traceinfile);
+ if (status < sizeof tracefile_header) {
+ if (ferror(traceinfile))
+ log_error("Error reading trace file header: %m");
+ else
+ log_error("Short read on trace file header: %d %ld.",
+ status, (long)(sizeof tracefile_header));
+ goto out;
+ }
+ tracefile_header.magic = ntohl(tracefile_header.magic);
+ tracefile_header.version = ntohl(tracefile_header.version);
+ tracefile_header.hlen = ntohl(tracefile_header.hlen);
+ tracefile_header.phlen = ntohl(tracefile_header.phlen);
+
+ if (tracefile_header.magic != TRACEFILE_MAGIC) {
+ log_error("%s: not a dhcp trace file.", filename);
+ goto out;
+ }
+ if (tracefile_header.version > TRACEFILE_VERSION) {
+ log_error ("tracefile version %ld > current %ld.",
+ (long int)tracefile_header.version,
+ (long int)TRACEFILE_VERSION);
+ goto out;
+ }
+ if (tracefile_header.phlen < sizeof *tpkt) {
+ log_error("tracefile packet size too small - %ld < %ld",
+ (long int)tracefile_header.phlen,
+ (long int)sizeof *tpkt);
+ goto out;
+ }
+ len = (sizeof tracefile_header) - tracefile_header.hlen;
+ if (len < 0) {
+ log_error("tracefile header size too small - %ld < %ld",
+ (long int)tracefile_header.hlen,
+ (long int)sizeof tracefile_header);
+ goto out;
+ }
+ if (len > 0) {
+ status = fseek(traceinfile, (long)len, SEEK_CUR);
+ if (status < 0) {
+ log_error("can't seek past header: %m");
+ goto out;
+ }
+ }
+
+ tpkt = dmalloc((unsigned)tracefile_header.phlen, MDL);
+ if (tpkt == NULL) {
+ log_error ("can't allocate trace packet header.");
+ goto out;
+ }
+
+ while ((result = trace_get_next_packet(&ttype, tpkt, &buf, &buflen,
+ &bufmax)) == ISC_R_SUCCESS) {
+ (*ttype->have_packet)(ttype, tpkt->length, buf);
+ ttype = NULL;
+ }
+ out:
+ fclose(traceinfile);
+ if (buf != NULL)
+ dfree(buf, MDL);
+ if (tpkt != NULL)
+ dfree(tpkt, MDL);
+}
+
+/* Get the next packet from the file. If ttp points to a nonzero pointer
+ to a trace type structure, check the next packet to see if it's of the
+ expected type, and back off if not. */
+
+isc_result_t trace_get_next_packet (trace_type_t **ttp,
+ tracepacket_t *tpkt,
+ char **buf, unsigned *buflen,
+ unsigned *bufmax)
+{
+ trace_type_t *ttype;
+ unsigned paylen;
+ int status, curposok = 0;
+ fpos_t curpos;
+
+ while(1) {
+ curposok = 0;
+ status = fgetpos(traceinfile, &curpos);
+ if (status < 0) {
+ log_error("Can't save tracefile position: %m");
+ } else {
+ curposok = 1;
+ }
+
+ status = fread(tpkt, 1, (size_t)tracefile_header.phlen,
+ traceinfile);
+ if (status < tracefile_header.phlen) {
+ if (ferror(traceinfile))
+ log_error("Error reading trace packet header: "
+ "%m");
+ else if (status == 0)
+ return ISC_R_EOF;
+ else
+ log_error ("Short read on trace packet header:"
+ " %ld %ld.",
+ (long int)status,
+ (long int)tracefile_header.phlen);
+ return DHCP_R_PROTOCOLERROR;
+ }
+
+ /* Swap the packet. */
+ tpkt->type_index = ntohl(tpkt -> type_index);
+ tpkt->length = ntohl(tpkt -> length);
+ tpkt->when = ntohl(tpkt -> when);
+
+ /* See if there's a handler for this packet type. */
+ if (tpkt->type_index < trace_type_count &&
+ trace_types[tpkt->type_index])
+ ttype = trace_types[tpkt->type_index];
+ else {
+ log_error ("Trace packet with unknown index %ld",
+ (long int)tpkt->type_index);
+ return DHCP_R_PROTOCOLERROR;
+ }
+
+ /*
+ * Determine if we should try to expire any timer events.
+ * We do so if:
+ * we aren't looking for a specific type of packet
+ * we have a hook to use to update the timer
+ * the timestamp on the packet doesn't match the current time
+ * When we do so we rewind the file to the beginning of this
+ * packet and then try for a new packet. This allows
+ * any code triggered by a timeout to get the current packet
+ * while we get the next one.
+ */
+
+ if ((ttp != NULL) && (*ttp == NULL) &&
+ (tpkt->when != cur_tv.tv_sec) &&
+ (trace_set_time_hook != NULL)) {
+ if (curposok == 0) {
+ log_error("no curpos for fsetpos in "
+ "tracefile");
+ return DHCP_R_PROTOCOLERROR;
+ }
+
+ status = fsetpos(traceinfile, &curpos);
+ if (status < 0) {
+ log_error("fsetpos in tracefile failed: %m");
+ return DHCP_R_PROTOCOLERROR;
+ }
+
+ (*trace_set_time_hook) (tpkt->when);
+ continue;
+ }
+ break;
+ }
+
+ /* If we were supposed to get a particular kind of packet,
+ check to see that we got the right kind. */
+ if (ttp && *ttp && ttype != *ttp) {
+ log_error ("Read packet type %s when expecting %s",
+ ttype -> name, (*ttp) -> name);
+ status = fsetpos (traceinfile, &curpos);
+ if (status < 0) {
+ log_error ("fsetpos in tracefile failed: %m");
+ return DHCP_R_PROTOCOLERROR;
+ }
+ return ISC_R_UNEXPECTEDTOKEN;
+ }
+
+ paylen = tpkt -> length;
+ if (paylen % 8)
+ paylen += 8 - (tpkt -> length % 8);
+
+ /* allocate a buffer if we need one or current buffer is too small */
+ if ((*buf == NULL) || (paylen > (*bufmax))) {
+ if ((*buf))
+ dfree ((*buf), MDL);
+ (*bufmax) = ((paylen + 1023) & ~1023U);
+ (*buf) = dmalloc ((*bufmax), MDL);
+ if (!(*buf)) {
+ log_error ("Can't allocate input buffer sized %d",
+ (*bufmax));
+ return ISC_R_NOMEMORY;
+ }
+ }
+
+ status = fread ((*buf), 1, paylen, traceinfile);
+ if (status < paylen) {
+ if (ferror (traceinfile))
+ log_error ("Error reading trace payload: %m");
+ else
+ log_error ("Short read on trace payload: %d %d.",
+ status, paylen);
+ return DHCP_R_PROTOCOLERROR;
+ }
+
+ /* Store the actual length of the payload. */
+ *buflen = tpkt -> length;
+
+ if (ttp)
+ *ttp = ttype;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t trace_get_packet (trace_type_t **ttp,
+ unsigned *buflen, char **buf)
+{
+ tracepacket_t *tpkt;
+ unsigned bufmax = 0;
+ isc_result_t status;
+
+ if (!buf || *buf)
+ return DHCP_R_INVALIDARG;
+
+ tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
+ if (!tpkt) {
+ log_error ("can't allocate trace packet header.");
+ return ISC_R_NOMEMORY;
+ }
+
+ status = trace_get_next_packet (ttp, tpkt, buf, buflen, &bufmax);
+
+ dfree (tpkt, MDL);
+ return status;
+}
+
+/* Get a packet from the trace input file that contains a file with the
+ specified name. We don't hunt for the packet - it should be the next
+ packet in the tracefile. If it's not, or something else bad happens,
+ return an error code. */
+
+isc_result_t trace_get_file (trace_type_t *ttype,
+ const char *filename, unsigned *len, char **buf)
+{
+ fpos_t curpos;
+ unsigned max = 0;
+ tracepacket_t *tpkt;
+ int status;
+ isc_result_t result;
+
+ /* Disallow some obvious bogosities. */
+ if (!buf || !len || *buf)
+ return DHCP_R_INVALIDARG;
+
+ /* Save file position in case of filename mismatch. */
+ status = fgetpos (traceinfile, &curpos);
+ if (status < 0)
+ log_error ("Can't save tracefile position: %m");
+
+ tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
+ if (!tpkt) {
+ log_error ("can't allocate trace packet header.");
+ return ISC_R_NOMEMORY;
+ }
+
+ result = trace_get_next_packet (&ttype, tpkt, buf, len, &max);
+ /* done with tpkt, free it */
+ dfree (tpkt, MDL);
+ if (result != ISC_R_SUCCESS) {
+ if (*buf) {
+ dfree (*buf, MDL);
+ *buf = NULL;
+ }
+ return result;
+ }
+
+ /* Make sure the filename is right. */
+ if (strcmp (filename, *buf)) {
+ log_error ("Read file %s when expecting %s", *buf, filename);
+ dfree (*buf, MDL);
+ *buf = NULL;
+
+ status = fsetpos (traceinfile, &curpos);
+ if (status < 0) {
+ log_error ("fsetpos in tracefile failed: %m");
+ return DHCP_R_PROTOCOLERROR;
+ }
+ return ISC_R_UNEXPECTEDTOKEN;
+ }
+
+ return ISC_R_SUCCESS;
+}
+#endif /* TRACING */