From d1e7e16224c881ee3093658fe4cbf14db244cec7 Mon Sep 17 00:00:00 2001 From: Andrew Shadura Date: Tue, 17 Jun 2014 11:57:32 +0200 Subject: Update to the latest upstream snapshot --- .gitignore | 2 + AUTHORS | 14 +- BSDmakefile | 10 + GIT-Access | 7 +- README | 83 +- buildsys.mk.in | 394 +++--- configure.ac | 3 +- debian/changelog | 6 + doc/BOOST | 3 +- doc/design-concepts.txt | 5 + scripts/makerelease.sh | 2 +- src/examples/Makefile | 3 +- src/examples/async_resolver/async_resolver.c | 27 +- src/examples/echoserver/echoserver.c | 27 +- src/examples/formattertest/formattertest.c | 3 +- src/examples/futuretest/Makefile | 7 - src/examples/futuretest/futuretest.c | 89 -- src/examples/helpertest/helpertest.c | 32 +- src/examples/jsontest/Makefile | 7 + src/examples/jsontest/jsontest.c | 47 + src/examples/libevent-bench/bench.c | 82 +- src/examples/linetest/linetest.c | 27 +- src/examples/listsort/listsort.c | 24 +- src/examples/memslice-bench/memslice-bench.c | 56 +- src/examples/patriciatest/patriciatest.c | 32 +- src/examples/patriciatest2/patriciatest2.c | 40 +- src/examples/randomtest/randomtest.c | 8 +- src/examples/timertest/timertest.c | 9 +- src/examples/vio-udplistener/vio-udplistener.c | 15 +- src/libmowgli/Makefile | 4 +- src/libmowgli/base/argstack.c | 63 +- src/libmowgli/base/argstack.h | 14 +- src/libmowgli/base/bitvector.c | 46 +- src/libmowgli/base/bitvector.h | 4 +- src/libmowgli/base/formatter.c | 20 +- src/libmowgli/base/hash.c | 46 +- src/libmowgli/base/hook.c | 5 +- src/libmowgli/base/hook.h | 23 +- src/libmowgli/base/memslice.c | 11 +- src/libmowgli/base/memslice.h | 1 - src/libmowgli/base/mowgli_signal.c | 8 +- src/libmowgli/base/mowgli_signal.h | 2 +- src/libmowgli/base/random.c | 37 +- src/libmowgli/base/random.h | 4 +- src/libmowgli/container/dictionary.c | 97 +- src/libmowgli/container/dictionary.h | 29 +- src/libmowgli/container/index.c | 191 +-- src/libmowgli/container/index.h | 40 +- src/libmowgli/container/list.c | 180 +-- src/libmowgli/container/list.h | 20 +- src/libmowgli/container/patricia.c | 202 ++- src/libmowgli/container/patricia.h | 29 +- src/libmowgli/container/queue.c | 15 +- src/libmowgli/container/queue.h | 1 - src/libmowgli/dns/Makefile | 10 +- src/libmowgli/dns/dns.c | 24 +- src/libmowgli/dns/dns.h | 19 +- src/libmowgli/dns/dns_evloop_res.c | 1017 --------------- src/libmowgli/dns/dns_evloop_res.h | 44 - src/libmowgli/dns/dns_evloop_reslib.c | 1102 ----------------- src/libmowgli/dns/dns_evloop_reslib.h | 112 -- src/libmowgli/dns/dns_evloop_reslist_win32.c | 97 -- src/libmowgli/dns/evloop_res.c | 1094 ++++++++++++++++ src/libmowgli/dns/evloop_res.h | 49 + src/libmowgli/dns/evloop_reslib.c | 1220 ++++++++++++++++++ src/libmowgli/dns/evloop_reslib.h | 115 ++ src/libmowgli/dns/evloop_reslist_win32.c | 102 ++ src/libmowgli/eventloop/epoll_pollops.c | 46 +- src/libmowgli/eventloop/eventloop.c | 35 +- src/libmowgli/eventloop/eventloop.h | 148 ++- src/libmowgli/eventloop/helper.c | 20 +- src/libmowgli/eventloop/kqueue_pollops.c | 65 +- src/libmowgli/eventloop/null_pollops.c | 43 +- src/libmowgli/eventloop/poll_pollops.c | 75 +- src/libmowgli/eventloop/pollable.c | 62 +- src/libmowgli/eventloop/ports_pollops.c | 56 +- src/libmowgli/eventloop/qnx_pollops.c | 50 +- src/libmowgli/eventloop/select_pollops.c | 59 +- src/libmowgli/eventloop/timer.c | 47 +- src/libmowgli/eventloop/windows_pollops.c | 55 +- src/libmowgli/ext/Makefile | 7 +- src/libmowgli/ext/confparse.c | 197 ++- src/libmowgli/ext/confparse.h | 2 +- src/libmowgli/ext/error_backtrace.c | 8 +- src/libmowgli/ext/error_backtrace.h | 3 +- src/libmowgli/ext/getopt_long.c | 288 +++-- src/libmowgli/ext/getopt_long.h | 18 +- src/libmowgli/ext/global_storage.c | 8 +- src/libmowgli/ext/global_storage.h | 1 - src/libmowgli/ext/json-inline.h | 107 ++ src/libmowgli/ext/json.c | 1475 ++++++++++++++++++++++ src/libmowgli/ext/json.h | 151 +++ src/libmowgli/ext/proctitle.c | 142 ++- src/libmowgli/ext/proctitle.h | 7 +- src/libmowgli/ext/program_opts.c | 27 +- src/libmowgli/ext/program_opts.h | 3 +- src/libmowgli/linebuf/linebuf.c | 175 ++- src/libmowgli/linebuf/linebuf.h | 37 +- src/libmowgli/module/Makefile | 2 +- src/libmowgli/module/interface.c | 73 ++ src/libmowgli/module/loader_posix.c | 29 +- src/libmowgli/module/loader_win32.c | 21 +- src/libmowgli/module/module.h | 17 +- src/libmowgli/mowgli.h | 11 +- src/libmowgli/object/class.c | 59 +- src/libmowgli/object/class.h | 34 +- src/libmowgli/object/message.c | 68 +- src/libmowgli/object/message.h | 3 +- src/libmowgli/object/metadata.c | 36 +- src/libmowgli/object/metadata.h | 3 +- src/libmowgli/object/object.c | 18 +- src/libmowgli/object/object.h | 3 +- src/libmowgli/platform/Makefile | 12 +- src/libmowgli/platform/attributes.h | 69 ++ src/libmowgli/platform/cacheline.c | 72 ++ src/libmowgli/platform/cacheline.h | 29 + src/libmowgli/platform/constructor.h | 27 +- src/libmowgli/platform/machine.h | 474 +++---- src/libmowgli/platform/win32/Makefile | 2 +- src/libmowgli/platform/win32/fork.c | 41 +- src/libmowgli/platform/win32/gettimeofday.c | 66 - src/libmowgli/platform/win32/inet.c | 18 +- src/libmowgli/platform/win32/pipe.c | 4 +- src/libmowgli/platform/win32/setenv.c | 4 +- src/libmowgli/platform/win32/socketpair.c | 155 +-- src/libmowgli/platform/win32/win32_stdinc.h | 32 +- src/libmowgli/thread/mutex.c | 35 +- src/libmowgli/thread/mutex.h | 16 +- src/libmowgli/thread/null_mutexops.c | 18 +- src/libmowgli/thread/posix_mutexops.c | 81 +- src/libmowgli/thread/thread.h | 20 +- src/libmowgli/thread/win32_mutexops.c | 30 +- src/libmowgli/vio/vio.c | 133 +- src/libmowgli/vio/vio.h | 283 +++-- src/libmowgli/vio/vio_openssl.c | 200 ++- src/libmowgli/vio/vio_sockets.c | 229 ++-- uncrustify.cfg | 1578 ++++++++++++++++++++++++ 137 files changed, 9781 insertions(+), 4802 deletions(-) create mode 100644 BSDmakefile delete mode 100644 src/examples/futuretest/Makefile delete mode 100644 src/examples/futuretest/futuretest.c create mode 100644 src/examples/jsontest/Makefile create mode 100644 src/examples/jsontest/jsontest.c delete mode 100644 src/libmowgli/dns/dns_evloop_res.c delete mode 100644 src/libmowgli/dns/dns_evloop_res.h delete mode 100644 src/libmowgli/dns/dns_evloop_reslib.c delete mode 100644 src/libmowgli/dns/dns_evloop_reslib.h delete mode 100644 src/libmowgli/dns/dns_evloop_reslist_win32.c create mode 100644 src/libmowgli/dns/evloop_res.c create mode 100644 src/libmowgli/dns/evloop_res.h create mode 100644 src/libmowgli/dns/evloop_reslib.c create mode 100644 src/libmowgli/dns/evloop_reslib.h create mode 100644 src/libmowgli/dns/evloop_reslist_win32.c create mode 100644 src/libmowgli/ext/json-inline.h create mode 100644 src/libmowgli/ext/json.c create mode 100644 src/libmowgli/ext/json.h create mode 100644 src/libmowgli/module/interface.c create mode 100644 src/libmowgli/platform/attributes.h create mode 100644 src/libmowgli/platform/cacheline.c create mode 100644 src/libmowgli/platform/cacheline.h delete mode 100644 src/libmowgli/platform/win32/gettimeofday.c create mode 100644 uncrustify.cfg diff --git a/.gitignore b/.gitignore index b056935..232e8f5 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,8 @@ src/examples/memslice-bench/memslice-bench src/examples/vio-udplistener/vio-udplistener src/examples/futuretest/futuretest src/examples/async_resolver/async_resolver +src/examples/jsontest/jsontest +src/examples/jsontest/test.json .deps *.dylib *.o diff --git a/AUTHORS b/AUTHORS index e96e123..868bfb1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,6 +1,12 @@ -Patrick McFarland -William Pitcock +All names are listed in alphabetical order. + +The following people are active contributors to libmowgli: +Elizabeth Myers +William Pitcock Jonathan Schleifer -Pippijn van Steenhoven Jilles Tjoelker -Elizabeth Myers + +The following people have contributed to libmowgli in the past: +Patrick McFarland +Pippijn van Steenhoven +Andrew Wilcox diff --git a/BSDmakefile b/BSDmakefile new file mode 100644 index 0000000..b075051 --- /dev/null +++ b/BSDmakefile @@ -0,0 +1,10 @@ +# This BSDmakefile redirects to GNU make. + +all: .DEFAULT +.DEFAULT: + @case ${MAKE} in \ + gmake|*/gmake) \ + echo "BSDmakefile run using gmake??"; \ + exit 1;; \ + esac + gmake ${.MAKEFLAGS} ${.TARGETS} diff --git a/GIT-Access b/GIT-Access index e57914e..c84661b 100644 --- a/GIT-Access +++ b/GIT-Access @@ -1,6 +1,5 @@ The libmowgli GIT repository can be checked out using the following command: - git clone git://git.atheme.org/libmowgli-2.git libmowgli-2 + git clone git://github.com/atheme/libmowgli-2.git -libmowgli's GIT repository depot can be browsed over the internet at -the following address: - http://git.atheme.org/ +libmowgli's GIT repository can be browsed via HTTP at the following address: + https://github.com/atheme/libmowgli-2 diff --git a/README b/README index 424f23d..a76a749 100644 --- a/README +++ b/README @@ -19,42 +19,44 @@ libmowgli is a class library containing performance and usability oriented extensions to C. It contains: - - mowgli_alloc: A safe wrapper around malloc/free. - - mowgli_argstack: Safe serialization of valists. - - mowgli_assert: Various assertion routines that can be used. - - mowgli_bitvector: Bitmasks with an unlimited level of precision. - - mowgli_patricia: A keyword-backed definition hashtable class. - - mowgli_error_backtrace: Provide feedback to users on what caused the - error they are recieving. - - mowgli_exception: Assertions with user feedback. - - mowgli_formatter: A simple token formatter which is sometimes useful. - - mowgli_global_storage: A simple global storage library. - - mowgli_hash: A portable implementation of the FNV-1 hash. - - mowgli_heap: An optimistic heap-based memory allocator - - mowgli_hook: A simple hooks API you can use for your application, which - allows for hooks to provide both application data and user data. - - mowgli_list: A high performance linked lists implementation with O(1) scalability - for most common operations. - - mowgli_logger: An internal class for handling logging of exceptions. - - mowgli_module: A wrapper around dlopen(3) and dlsym(3). - - mowgli_object: A simple class which provides reference counted pointers and - polymorphism of structs. - - mowgli_object_class: Classing and subclassing for objects. - - mowgli_object_metadata: Metadata for objects. - - mowgli_object_messaging: Messaging and signalling for objects. - - mowgli_queue: A simple class which implements double-ended queues. - - mowgli_random: A high performance psuedo-random number generator. - - mowgli_signal: A wrapper for sigaction(2). - - mowgli_eventloop: A portable event loop implementation. - - mowgli_vio: An abstraction layer for I/O. - - mowgli_linebuf: A line-buffering implementation for clients. - - mowgli_thread: Minimal thread abstraction. - -More classes will be added with later releases. Please contact -nenolod -at- atheme.org if you have suggestions on what should be -implemented. - -More information is available at http://www.atheme.org/projects/mowgli.shtml. + - mowgli.alloc: A safe wrapper around malloc/free. + - mowgli.argstack: Safe serialization of valists. + - mowgli.assert: Various assertion routines that can be used. + - mowgli.bitvector: Bitmasks with an unlimited level of precision. + - mowgli.patricia: A dictionary implementation based on a modified + patricia tree algorithm (uses nibbles instead of + bits for branching). + - mowgli.error_backtrace: Provide feedback to users on what caused + the error they are recieving. + - mowgli.formatter: A simple token formatter which is sometimes useful. + - mowgli.global_storage: A simple global storage library. + - mowgli.hash: A portable implementation of the FNV-1 hash. + - mowgli.heap: An optimistic heap-based memory allocator + - mowgli.hook: A simple hooks API you can use for your application, + which allows for hooks to provide both application + data and user data. + - mowgli.json: A simple, flexible, reentrant JSON parser + - mowgli.list: A high performance linked lists implementation with + O(1) scalability for most common operations. + - mowgli.logger: An internal class for handling logging of exceptions. + - mowgli.module: A wrapper around dlopen(3) and dlsym(3). + - mowgli.object: A simple class which provides reference counted + pointers and polymorphism of structs. + - mowgli.object_class: Classing and subclassing for objects. + - mowgli.object_metadata: Metadata for objects. + - mowgli.object_messaging: Messaging and signalling for objects. + - mowgli.queue: A simple class which implements double-ended queues. + - mowgli.random: A high performance psuedo-random number generator. + - mowgli.signal: A wrapper for sigaction(2). + - mowgli.eventloop: A portable event loop implementation. + - mowgli.vio: An abstraction layer for I/O. + - mowgli.linebuf: A line-buffering implementation for clients. + - mowgli.thread: Minimal thread abstraction. + +More classes will be added with later releases. Please use GitHub's +issue tracker if you have suggestions on what should be implemented. + +More information is available at http://www.atheme.org/projects/mowgli. Installation @@ -66,14 +68,13 @@ Installation is fairly typical: $ make $ sudo make install -(If sudo isn't on your system, su to root. On GNU systems you can even -do "su -c 'make install'", which is basically the same thing as using -sudo.) +(If sudo isn't on your system, su to root. On GNU systems you can even do +"su -c 'make install'", which is basically the same thing as using sudo.) Bug Reports ----------- -Bugs can be reported on our tracker at http://jira.atheme.org against the -libmowgli product. +Bugs can be reported using the GitHub issue tracker on the libmowgli-2 +project page: https://github.com/atheme/libmowgli-2/issues diff --git a/buildsys.mk.in b/buildsys.mk.in index 7977b07..dc54919 100644 --- a/buildsys.mk.in +++ b/buildsys.mk.in @@ -21,6 +21,7 @@ # POSSIBILITY OF SUCH DAMAGE. # +#V=1 PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ AS = @AS@ @@ -104,19 +105,13 @@ MO_FILES = ${LOCALES:.po=.mo} .SILENT: .SUFFIXES: .SUFFIXES: .beam .c .c.dep .cc .cc.dep .class .cxx .cxx.dep .d .erl .lib.o .java .mo .m .m.dep .mm .mm.dep .o .plugin.o .po .py .pyc .rc .S .S.dep .xpm -.PHONY: all subdirs pre-depend depend install install-extra uninstall uninstall-extra clean distclean locales +.PHONY: all subdirs ${SUBDIRS} pre-depend depend install install-extra uninstall uninstall-extra clean distclean locales -all: - ${MAKE} ${MFLAGS} subdirs - ${MAKE} ${MFLAGS} depend - ${MAKE} ${STATIC_LIB} ${STATIC_LIB_NOINST} ${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST} ${SHARED_LIB} ${SHARED_LIB_NOINST} ${PLUGIN} ${PLUGIN_NOINST} ${PROG} ${PROG_NOINST} ${JARFILE} locales +all: subdirs depend ${STATIC_LIB} ${STATIC_LIB_NOINST} ${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST} ${SHARED_LIB} ${SHARED_LIB_NOINST} ${PLUGIN} ${PLUGIN_NOINST} ${PROG} ${PROG_NOINST} ${JARFILE} locales -subdirs: - for i in ${SUBDIRS}; do \ - ${DIR_ENTER}; \ - ${MAKE} ${MFLAGS} || exit $$?; \ - ${DIR_LEAVE}; \ - done +subdirs: ${SUBDIRS} +${SUBDIRS}: + ${MAKE} -C $@ ${MFLAGS} depend: pre-depend ${SRCS} regen=0; \ @@ -142,15 +137,36 @@ depend: pre-depend ${SRCS} fi; \ fi -.c.c.dep .cc.cc.dep .cxx.cxx.dep .m.m.dep .mm.mm.dep .S.S.dep: - ${CPP} ${CPPFLAGS} -M $< | \ +.c.c.dep: + ${CPP} ${CPPFLAGS} ${CFLAGS} -M $< | \ + sed 's/^\([^\.]*\)\.o:/\1.o \1.lib.o \1.plugin.o:/' >$@ || \ + { rm -f $@; false; } + +.cc.cc.dep .cxx.cxx.dep: + ${CPP} ${CPPFLAGS} ${CXXFLAGS} -M $< | \ + sed 's/^\([^\.]*\)\.o:/\1.o \1.lib.o \1.plugin.o:/' >$@ || \ + { rm -f $@; false; } + +.m.m.dep: + ${CPP} ${CPPFLAGS} ${OBJCFLAGS} -M $< | \ + sed 's/^\([^\.]*\)\.o:/\1.o \1.lib.o \1.plugin.o:/' >$@ || \ + { rm -f $@; false; } + +.mm.mm.dep: + ${CPP} ${CPPFLAGS} ${OBJCPPFLAGS} -M $< | \ + sed 's/^\([^\.]*\)\.o:/\1.o \1.lib.o \1.plugin.o:/' >$@ || \ + { rm -f $@; false; } + +.S.S.dep: + ${CPP} ${CPPFLAGS} ${ASFLAGS} -M $< | \ sed 's/^\([^\.]*\)\.o:/\1.o \1.lib.o \1.plugin.o:/' >$@ || \ { rm -f $@; false; } pre-depend: ${PROG} ${PROG_NOINST}: ${EXT_DEPS} ${OBJS} ${OBJS_EXTRA} - ${LINK_STATUS} + LDOBJS="${OBJS} ${OBJS_EXTRA}"; \ + ${LINK_STATUS}; \ if ${LD} -o $@ ${OBJS} ${OBJS_EXTRA} ${LDFLAGS} ${LIBS}; then \ ${LINK_OK}; \ else \ @@ -174,6 +190,7 @@ ${JARFILE}: ${EXT_DEPS} ${JAR_MANIFEST} ${OBJS} ${OBJS_EXTRA} fi ${SHARED_LIB} ${SHARED_LIB_NOINST}: ${EXT_DEPS} ${LIB_OBJS} ${LIB_OBJS_EXTRA} + LDOBJS="${LIB_OBJS} ${LIB_OBJS_EXTRA}"; \ ${LINK_STATUS}; \ objs=""; \ ars=""; \ @@ -209,7 +226,8 @@ ${SHARED_LIB} ${SHARED_LIB_NOINST}: ${EXT_DEPS} ${LIB_OBJS} ${LIB_OBJS_EXTRA} done ${PLUGIN} ${PLUGIN_NOINST}: ${EXT_DEPS} ${PLUGIN_OBJS} - ${LINK_STATUS} + LDOBJS="${PLUGIN_OBJS}"; \ + ${LINK_STATUS}; \ objs=""; \ ars=""; \ for i in ${PLUGIN_OBJS}; do \ @@ -244,8 +262,9 @@ ${PLUGIN} ${PLUGIN_NOINST}: ${EXT_DEPS} ${PLUGIN_OBJS} done ${STATIC_LIB} ${STATIC_LIB_NOINST}: ${EXT_DEPS} ${OBJS} ${OBJS_EXTRA} - ${LINK_STATUS} - rm -f $@ + LDOBJS="${OBJS} ${OBJS_EXTRA}"; \ + ${LINK_STATUS}; \ + rm -f $@; \ objs=""; \ ars=""; \ for i in ${OBJS} ${OBJS_EXTRA}; do \ @@ -281,7 +300,8 @@ ${STATIC_LIB} ${STATIC_LIB_NOINST}: ${EXT_DEPS} ${OBJS} ${OBJS_EXTRA} done ${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST}: ${EXT_DEPS} ${LIB_OBJS} ${LIB_OBJS_EXTRA} - ${LINK_STATUS} + LDOBJS="${LIB_OBJS} ${LIB_OBJS_EXTRA}"; \ + ${LINK_STATUS}; \ rm -f $@ objs=""; \ ars=""; \ @@ -320,192 +340,151 @@ ${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST}: ${EXT_DEPS} ${LIB_OBJS} ${LIB_OBJS_E locales: ${MO_FILES} .c.o: - ${COMPILE_STATUS} - if ${CC} ${CFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi + COMPILER="${CC}"; \ + COMPILER_FLAGS="${CFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .c.lib.o: - ${COMPILE_LIB_STATUS} - if ${CC} ${LIB_CFLAGS} ${CFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_LIB_OK}; \ - else \ - ${COMPILE_LIB_FAILED}; \ - fi + COMPILER="${CC}"; \ + COMPILER_FLAGS="${LIB_CFLAGS} ${CFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_LIB_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .c.plugin.o: - ${COMPILE_PLUGIN_STATUS} - if ${CC} ${PLUGIN_CFLAGS} ${CFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_PLUGIN_OK}; \ - else \ - ${COMPILE_PLUGIN_FAILED}; \ - fi + COMPILER="${CC}"; \ + COMPILER_FLAGS="${PLUGIN_CFLAGS} ${CFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_PLUGIN_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} .cc.o .cxx.o: - ${COMPILE_STATUS} - if ${CXX} ${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi + COMPILER="${CXX}"; \ + COMPILER_FLAGS="${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .cc.lib.o .cxx.lib.o: - ${COMPILE_LIB_STATUS} - if ${CXX} ${LIB_CFLAGS} ${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_LIB_OK}; \ - else \ - ${COMPILE_LIB_FAILED}; \ - fi + COMPILER="${CXX}"; \ + COMPILER_FLAGS="${LIB_CFLAGS} ${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_LIB_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .cc.plugin.o .cxx.plugin.o: - ${COMPILE_PLUGIN_STATUS} - if ${CXX} ${PLUGIN_CFLAGS} ${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_PLUGIN_OK}; \ - else \ - ${COMPILE_PLUGIN_FAILED}; \ - fi + COMPILER="${CXX}"; \ + COMPILER_FLAGS="${PLUGIN_CFLAGS} ${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_PLUGIN_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} .d.o: - ${COMPILE_STATUS} - if test x"$(basename ${DC})" = x"dmd"; then \ - if ${DC} ${DFLAGS} -c -of$@ $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi \ + COMPILER="${DC}"; \ + ${COMPILE_STATUS}; \ + if test x"$(basename ${COMPILER})" = x"dmd"; then \ + $${COMPILER} ${DFLAGS} -c -of$@ $<; \ else \ - if ${DC} ${DFLAGS} -c -o $@ $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi \ + $${COMPILER} ${DFLAGS} -c -o $@ $<; \ fi .erl.beam: - ${COMPILE_STATUS} - if ${ERLC} ${ERLCFLAGS} -o $@ $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi + COMPILER="${ERLC}"; \ + COMPILER_FLAGS="${ERLCFLAGS} -o $@ $<"; \ + ${COMPILE_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} .java.class: - ${COMPILE_STATUS} - if ${JAVAC} ${JAVACFLAGS} $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi + COMPILER="${JAVAC}"; \ + COMPILER_FLAGS="${JAVACFLAGS} $<"; \ + ${COMPILE_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} .m.o: - ${COMPILE_STATUS} - if ${OBJC} ${OBJCFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi + COMPILER="${OBJC}"; \ + COMPILER_FLAGS="${OBJCFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .m.lib.o: - ${COMPILE_LIB_STATUS} - if ${OBJC} ${LIB_CFLAGS} ${OBJCFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_LIB_OK}; \ - else \ - ${COMPILE_LIB_FAILED}; \ - fi + COMPILER="${OBJC}"; \ + COMPILER_FLAGS="${LIB_CFLAGS} ${OBJCFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_LIB_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .m.plugin.o: - ${COMPILE_PLUGIN_STATUS} - if ${OBJC} ${PLUGIN_CFLAGS} ${OBJCFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_PLUGIN_OK}; \ - else \ - ${COMPILE_PLUGIN_FAILED}; \ - fi + COMPILER="${OBJC}"; \ + COMPILER_FLAGS="${PLUGIN_CFLAGS} ${OBJCFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_PLUGIN_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} .mm.o: - ${COMPILE_STATUS} - if ${OBJCXX} ${OBJCXXFLAGS} ${OBJCFLAGS} ${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi + COMPILER="${OBJCXX}"; \ + COMPILER_FLAGS="${OBJCXXFLAGS} ${OBJCFLAGS} ${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .mm.lib.o: - ${COMPILE_LIB_STATUS} - if ${OBJCXX} ${LIB_CFLAGS} ${OBJCXXFLAGS} ${OBJCFLAGS} ${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_LIB_OK}; \ - else \ - ${COMPILE_LIB_FAILED}; \ - fi + COMPILER="${OBJCXX}"; \ + COMPILER_FLAGS="${LIB_CFLAGS} ${OBJCXXFLAGS} ${OBJCFLAGS} ${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_LIB_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .mm.plugin.o: - ${COMPILE_PLUGIN_STATUS} - if ${OBJCXX} ${PLUGIN_CFLAGS} ${OBJCXXFLAGS} ${OBJCFLAGS} ${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_PLUGIN_OK}; \ - else \ - ${COMPILE_PLUGIN_FAILED}; \ - fi + COMPILER="${OBJCXX}"; \ + COMPILER_FLAGS="${PLUGIN_CFLAGS} ${OBJCXXFLAGS} ${OBJCFLAGS} ${CXXFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_PLUGIN_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} .po.mo: - ${COMPILE_STATUS} - if ${MSGFMT} -c -o $@ $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi + COMPILER="${MSGFMT}"; \ + COMPILER_FLAGS="-c -o $@ $<"; \ + ${COMPILE_RESOURCE_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} .py.pyc: - ${COMPILE_STATUS} - if ${PYTHON} ${PYTHON_FLAGS} -c "import py_compile; py_compile.compile('$<')"; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi + COMPILER="${PYTHON}"; \ + COMPILER_FLAGS="${PYTHON_FLAGS}"; \ + ${COMPILE_RESOURCE_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} -c "import py_compile; py_compile.compile('$<')" .rc.o .rc.lib.o .rc.plugin.o: - ${COMPILE_STATUS} - if ${WINDRES} ${CPPFLAGS} -J rc -O coff -o $@ $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi + COMPILER="${WINDRES}"; \ + COMPILER_FLAGS="${CPPFLAGS} -J rc -O coff -o $@ $<"; \ + ${COMPILE_RESOURCE_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} .S.o: - ${COMPILE_STATUS} - if ${AS} ${ASFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi + COMPILER="${AS}"; \ + COMPILER_FLAGS="${ASFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .S.lib.o: - ${COMPILE_LIB_STATUS} - if ${AS} ${LIB_CFLAGS} ${ASFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_LIB_OK}; \ - else \ - ${COMPILE_LIB_FAILED}; \ - fi + COMPILER="${AS}"; \ + COMPILER_FLAGS="${LIB_CFLAGS} ${ASFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_LIB_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .S.plugin.o: - ${COMPILE_PLUGIN_STATUS} - if ${AS} ${PLUGIN_CFLAGS} ${ASFLAGS} ${CPPFLAGS} -c -o $@ $<; then \ - ${COMPILE_PLUGIN_OK}; \ - else \ - ${COMPILE_PLUGIN_FAILED}; \ - fi + COMPILER="${AS}"; \ + COMPILER_FLAGS="${PLUGIN_CFLAGS} ${ASFLAGS} ${CPPFLAGS} -c -o $@ $<"; \ + ${COMPILE_PLUGIN_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} .xpm.o: - ${COMPILE_STATUS} - if ${CC} ${CFLAGS} ${CPPFLAGS} -x c -c -o $@ $<; then \ - ${COMPILE_OK}; \ - else \ - ${COMPILE_FAILED}; \ - fi + COMPILER="${CC}"; \ + COMPILER_FLAGS="${CFLAGS} ${CPPFLAGS} -x c -c -o $@ $<"; \ + ${COMPILE_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .xpm.lib.o: - ${COMPILE_LIB_STATUS} - if ${CC} ${LIB_CFLAGS} ${CFLAGS} ${CPPFLAGS} -x c -c -o $@ $<; then \ - ${COMPILE_LIB_OK}; \ - else \ - ${COMPILE_LIB_FAILED}; \ - fi + COMPILER="${CC}"; \ + COMPILER_FLAGS="${LIB_CFLAGS} ${CFLAGS} ${CPPFLAGS} -x c -c -o $@ $<"; \ + ${COMPILE_LIB_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} + .xpm.plugin.o: - ${COMPILE_PLUGIN_STATUS} - if ${CC} ${PLUGIN_CFLAGS} ${CFLAGS} ${CPPFLAGS} -x c -c -o $@ $<; then \ - ${COMPILE_PLUGIN_OK}; \ - else \ - ${COMPILE_PLUGIN_FAILED}; \ - fi + COMPILER="${CC}"; \ + COMPILER_FLAGS="${PLUGIN_CFLAGS} ${CFLAGS} ${CPPFLAGS} -x c -c -o $@ $<"; \ + ${COMPILE_PLUGIN_STATUS}; \ + $${COMPILER} $${COMPILER_FLAGS} install: ${SHARED_LIB} ${STATIC_LIB} ${STATIC_PIC_LIB} ${PLUGIN} ${PROG} install-extra for i in ${SUBDIRS}; do \ @@ -715,27 +694,62 @@ distclean: clean fi \ done -DIR_ENTER = printf "@TERM_EL@@TERM_SETAF6@Entering directory @TERM_BOLD@$$i@TERM_SGR0@@TERM_SETAF6@.@TERM_SGR0@\n"; cd $$i || exit $$? -DIR_LEAVE = printf "@TERM_EL@@TERM_SETAF6@Leaving directory @TERM_BOLD@$$i@TERM_SGR0@@TERM_SETAF6@.@TERM_SGR0@\n"; cd .. || exit $$? -DEPEND_STATUS = printf "@TERM_EL@@TERM_SETAF3@Generating dependencies...@TERM_SGR0@\r" -DEPEND_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully generated dependencies.@TERM_SGR0@\n" -DEPEND_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to generate dependencies!@TERM_SGR0@\n"; exit $$err -COMPILE_STATUS = printf "@TERM_EL@@TERM_SETAF3@Compiling @TERM_BOLD@$<@TERM_SGR0@@TERM_SETAF3@...@TERM_SGR0@\r" -COMPILE_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully compiled @TERM_BOLD@$<@TERM_SGR0@@TERM_SETAF2@.@TERM_SGR0@\n" -COMPILE_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to compile @TERM_BOLD@$<@TERM_SGR0@@TERM_SETAF1@!@TERM_SGR0@\n"; exit $$err -COMPILE_LIB_STATUS = printf "@TERM_EL@@TERM_SETAF3@Compiling @TERM_BOLD@$<@TERM_SGR0@@TERM_SETAF3@ (lib)...@TERM_SGR0@\r" -COMPILE_LIB_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully compiled @TERM_BOLD@$<@TERM_SGR0@@TERM_SETAF2@ (lib).@TERM_SGR0@\n" -COMPILE_LIB_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to compile @TERM_BOLD@$<@TERM_SGR0@@TERM_SETAF1@ (lib)!@TERM_SGR0@\n"; exit $$err -COMPILE_PLUGIN_STATUS = printf "@TERM_EL@@TERM_SETAF3@Compiling @TERM_BOLD@$<@TERM_SGR0@@TERM_SETAF3@ (plugin)...@TERM_SGR0@\r" -COMPILE_PLUGIN_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully compiled @TERM_BOLD@$<@TERM_SGR0@@TERM_SETAF2@ (plugin).@TERM_SGR0@\n" -COMPILE_PLUGIN_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to compile @TERM_BOLD@$<@TERM_SGR0@@TERM_SETAF1@ (plugin)!@TERM_SGR0@\n"; exit $$err -LINK_STATUS = printf "@TERM_EL@@TERM_SETAF3@Linking @TERM_BOLD@$@@TERM_SGR0@@TERM_SETAF3@...@TERM_SGR0@\r" -LINK_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully linked @TERM_BOLD@$@@TERM_SGR0@@TERM_SETAF2@.@TERM_SGR0@\n" -LINK_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to link @TERM_BOLD@$@@TERM_SGR0@@TERM_SETAF1@!@TERM_SGR0@\n"; exit $$err -INSTALL_STATUS = printf "@TERM_EL@@TERM_SETAF3@Installing @TERM_BOLD@$$i@TERM_SGR0@@TERM_SETAF3@...@TERM_SGR0@\r" -INSTALL_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully installed @TERM_BOLD@$$i@TERM_SGR0@@TERM_SETAF2@.@TERM_SGR0@\n" -INSTALL_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to install @TERM_BOLD@$$i@TERM_SGR0@@TERM_SETAF1@!@TERM_SGR0@\n"; exit $$err -DELETE_OK = printf "@TERM_EL@@TERM_SETAF4@Deleted @TERM_BOLD@$$i@TERM_SGR0@@TERM_SETAF4@.@TERM_SGR0@\n" -DELETE_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to delete @TERM_BOLD@$$i@TERM_SGR0@@TERM_SETAF1@!@TERM_SGR0@\n"; exit $$err +ifndef V + +DIR_ENTER = cd $$i || exit $$? +DIR_LEAVE = cd .. || exit $$? +DEPEND_STATUS = true +DEPEND_OK = true +DEPEND_FAILED = exit $$? +COMPILE_STATUS = printf "CompileExe: $@\n" +COMPILE_OK = true +COMPILE_FAILED = exit $$? +COMPILE_LIB_STATUS = printf "CompileLib: $@\n" +COMPILE_LIB_OK = true +COMPILE_LIB_FAILED = exit $$? +COMPILE_PLUGIN_STATUS = printf "CompilePlugin: $@\n" +COMPILE_PLUGIN_OK = true +COMPILE_PLUGIN_FAILED = exit $$? +COMPILE_RESOURCE_STATUS = printf "CompileResource: $@\n" +COMPILE_RESOURCE_OK = true +COMPILE_RESOURCE_FAILED = exit $$? +LINK_STATUS = printf "Link: $@\n" +LINK_OK = true +LINK_FAILED = exit $$? +INSTALL_STATUS = printf "Install: $$i\n" +INSTALL_OK = true +INSTALL_FAILED = exit $$? +DELETE_OK = printf "Delete: $$i\n" +DELETE_FAILED = exit $$? + +else + +DIR_ENTER = cd $$i || exit $$? +DIR_LEAVE = cd .. || exit $$? +DEPEND_STATUS = true +DEPEND_OK = true +DEPEND_FAILED = exit $$? +COMPILE_STATUS = printf "CompileExe: $$COMPILER $${COMPILER_FLAGS}\n" +COMPILE_OK = true +COMPILE_FAILED = exit $$? +COMPILE_LIB_STATUS = printf "CompileLib: $$COMPILER $${COMPILER_FLAGS}\n" +COMPILE_LIB_OK = true +COMPILE_LIB_FAILED = exit $$? +COMPILE_PLUGIN_STATUS = printf "CompilePlugin: $$COMPILER $${COMPILER_FLAGS}\n" +COMPILE_PLUGIN_OK = true +COMPILE_PLUGIN_FAILED = exit $$? +COMPILE_RESOURCE_STATUS = printf "CompileResource: $$COMPILER $${COMPILER_FLAGS}\n" +COMPILE_RESOURCE_OK = true +COMPILE_RESOURCE_FAILED = exit $$? +LINK_STATUS = printf "Link: ${LD} $@ $$LDOBJS ${LDFLAGS} ${LIBS}\n" +LINK_OK = true +LINK_FAILED = exit $$? +INSTALL_STATUS = printf "Install: $$i\n" +INSTALL_OK = true +INSTALL_FAILED = exit $$? +DELETE_OK = printf "Delete: $$i\n" +DELETE_FAILED = exit $$? + +endif include .deps diff --git a/configure.ac b/configure.ac index be4b19a..9b3bc63 100644 --- a/configure.ac +++ b/configure.ac @@ -43,7 +43,7 @@ fi AC_PATH_PROG(AR, ar) AC_PATH_PROG(RANLIB, ranlib) -LIBMOWGLI_MODULES="core base container dns eventloop ext linebuf module object thread vio" +LIBMOWGLI_MODULES="core base container dns eventloop ext linebuf module object platform thread vio" AC_SUBST(LIBMOWGLI_MODULES) LIBMOWGLI_MODULE_BUILD="$(echo && echo x)" @@ -107,6 +107,7 @@ case "$target" in CPPFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" AC_CHECK_LIB(dl, dlopen, [LIBS="$LIBS -ldl"]) + AC_CHECK_LIB(rt, clock_gettime, [LIBS="$LIBS -lrt"]) ;; esac AC_SUBST([LIBMOWGLI_OS]) diff --git a/debian/changelog b/debian/changelog index ef52417..7f51d4c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +libmowgli-2 (2.0.0+git20140224.89982cf4-1) UNRELEASED; urgency=medium + + * New upstream release + + -- Andrew Shadura Tue, 17 Jun 2014 11:55:29 +0200 + libmowgli-2 (2.0.0-2) unstable; urgency=medium * Add missing licenses to debian/copyright (Closes: #741436). diff --git a/doc/BOOST b/doc/BOOST index e9569fd..160d4f1 100644 --- a/doc/BOOST +++ b/doc/BOOST @@ -1,5 +1,5 @@ This is a list of alphabetical libraries provided by Boost and their -equivilant in Mowgli: +equivalent in libmowgli: dynamic_bitset -> mowgli_bitvector pool -> mowgli_memorypool @@ -9,3 +9,4 @@ equivilant in Mowgli: Many boost libraries that are applicable to C have not yet been implemented. You can visit http://www.boost.org/libs/libraries.htm for a full list of libs. + diff --git a/doc/design-concepts.txt b/doc/design-concepts.txt index 5d596bd..1c8ba46 100644 --- a/doc/design-concepts.txt +++ b/doc/design-concepts.txt @@ -114,3 +114,8 @@ use a coroutine library, such as the work-in-progress mowgli.coroutine. Pretty much anything you can do with threads, you can do better with something, *anything* else. + +Please note the Mowgli team will generally not accept intrusive patches to +add any additional threading support aside from fixes and locking bugs. No +atomics, no making anything in the library use threads. Don't waste your time. + diff --git a/scripts/makerelease.sh b/scripts/makerelease.sh index 58f6039..eeeb19b 100755 --- a/scripts/makerelease.sh +++ b/scripts/makerelease.sh @@ -1,7 +1,7 @@ #!/bin/sh # mkrelease.sh: Creates a release suitable for distfiles.atheme.org. # -# Copyright (c) 2007 atheme.org +# Copyright (c) 2007-2012 atheme.org # # Permission to use, copy, modify, and/or distribute this software for # any purpose with or without fee is hereby granted, provided that the above diff --git a/src/examples/Makefile b/src/examples/Makefile index 8512305..4fb1edd 100644 --- a/src/examples/Makefile +++ b/src/examples/Makefile @@ -1,3 +1,2 @@ -SUBDIRS = echoserver vio-udplistener async_resolver formattertest helpertest libevent-bench linetest listsort memslice-bench patriciatest patriciatest2 randomtest timertest futuretest - +SUBDIRS = echoserver vio-udplistener async_resolver formattertest helpertest jsontest libevent-bench linetest listsort memslice-bench patriciatest patriciatest2 randomtest timertest include ../../buildsys.mk diff --git a/src/examples/async_resolver/async_resolver.c b/src/examples/async_resolver/async_resolver.c index 1a05236..8bd0b12 100644 --- a/src/examples/async_resolver/async_resolver.c +++ b/src/examples/async_resolver/async_resolver.c @@ -8,7 +8,8 @@ typedef struct mowgli_dns_query_t query; } dns_query; -static void resolve_cb(mowgli_dns_reply_t *reply, int reason, void *vptr) +static void +resolve_cb(mowgli_dns_reply_t *reply, int reason, void *vptr) { char buf[2048]; dns_query *dnsquery = vptr; @@ -17,6 +18,7 @@ static void resolve_cb(mowgli_dns_reply_t *reply, int reason, void *vptr) if (reply == NULL) { printf("Got null reply for %s\n", dnsquery->domain); + switch (reason) { case MOWGLI_DNS_RES_NXDOMAIN: @@ -29,6 +31,7 @@ static void resolve_cb(mowgli_dns_reply_t *reply, int reason, void *vptr) printf("Timed out\n"); break; } + goto end; } @@ -37,12 +40,12 @@ static void resolve_cb(mowgli_dns_reply_t *reply, int reason, void *vptr) if (reply->addr.addr.ss_family == AF_INET) { - const struct sockaddr_in *saddr = (const struct sockaddr_in *)&reply->addr.addr; + const struct sockaddr_in *saddr = (const struct sockaddr_in *) &reply->addr.addr; sockptr = &saddr->sin_addr; } else if (reply->addr.addr.ss_family == AF_INET6) { - const struct sockaddr_in6 *saddr = (const struct sockaddr_in6 *)&reply->addr.addr; + const struct sockaddr_in6 *saddr = (const struct sockaddr_in6 *) &reply->addr.addr; sockptr = &saddr->sin6_addr; } else @@ -59,7 +62,8 @@ end: mowgli_free(vptr); } -static void read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +static void +read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) { mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(io); mowgli_dns_t *dns = userdata; @@ -76,11 +80,14 @@ static void read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, return; } else if (ret == 0) + { return; + } buf[--ret] = '\0'; ch = strtok(buf, " "); + while (ch != NULL) { dns_query *dnsquery = mowgli_alloc(sizeof(dns_query)); @@ -99,15 +106,15 @@ static void read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, void *addrptr; struct sockaddr_storage addr; - if(strchr(++ch, ':') != NULL) + if (strchr(++ch, ':') != NULL) { - struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)&addr; + struct sockaddr_in6 *saddr = (struct sockaddr_in6 *) &addr; type = AF_INET6; addrptr = &saddr->sin6_addr; } else { - struct sockaddr_in *saddr = (struct sockaddr_in *)&addr; + struct sockaddr_in *saddr = (struct sockaddr_in *) &addr; type = AF_INET; addrptr = &saddr->sin_addr; } @@ -127,18 +134,22 @@ static void read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_dns_gethost_byaddr(dns, &addr, query); } else + { mowgli_dns_gethost_byname(dns, ch, query, MOWGLI_DNS_T_A); + } dnsquery->domain = mowgli_strdup(ch); ch = strtok(NULL, " "); } } -int main (void) +int +main(void) { mowgli_eventloop_t *evloop = mowgli_eventloop_create(); mowgli_dns_t *dns = mowgli_dns_create(evloop, MOWGLI_DNS_TYPE_ASYNC); mowgli_eventloop_pollable_t *stdin_pollable = mowgli_pollable_create(evloop, STDIN_FILENO, dns); + mowgli_pollable_set_nonblocking(stdin_pollable, true); mowgli_pollable_setselect(evloop, stdin_pollable, MOWGLI_EVENTLOOP_IO_READ, read_data); diff --git a/src/examples/echoserver/echoserver.c b/src/examples/echoserver/echoserver.c index dd1fc05..053b33b 100644 --- a/src/examples/echoserver/echoserver.c +++ b/src/examples/echoserver/echoserver.c @@ -26,23 +26,27 @@ mowgli_eventloop_t *base_eventloop; mowgli_eventloop_pollable_t *listener; -typedef struct { +typedef struct +{ mowgli_eventloop_io_t *io; char buf[1024]; } client_t; #ifdef DEBUG -static void timer_tick(void *unused) +static void +timer_tick(void *unused) { static int ticks = 0; printf("tick: %d\n", ++ticks); } + #endif -static int setup_listener(void) +static int +setup_listener(void) { - struct sockaddr_in in = {}; + struct sockaddr_in in = { }; int fd = socket(AF_INET, SOCK_STREAM, 0); in.sin_family = AF_INET; @@ -59,7 +63,8 @@ static int setup_listener(void) return fd; } -static void write_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +static void +write_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) { mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(io); client_t *client = userdata; @@ -72,7 +77,8 @@ static void write_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_pollable_setselect(base_eventloop, client->io, MOWGLI_EVENTLOOP_IO_WRITE, NULL); } -static void read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +static void +read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) { mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(io); int ret; @@ -90,13 +96,15 @@ static void read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_pollable_setselect(base_eventloop, client->io, MOWGLI_EVENTLOOP_IO_WRITE, write_data); } -static void client_error(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +static void +client_error(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) { mowgli_free(userdata); mowgli_pollable_destroy(eventloop, io); } -static void accept_client(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +static void +accept_client(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) { mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(io); client_t *client; @@ -115,7 +123,8 @@ static void accept_client(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t * mowgli_pollable_setselect(base_eventloop, client->io, MOWGLI_EVENTLOOP_IO_ERROR, client_error); } -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { int fd; diff --git a/src/examples/formattertest/formattertest.c b/src/examples/formattertest/formattertest.c index 9ec014c..f56b671 100644 --- a/src/examples/formattertest/formattertest.c +++ b/src/examples/formattertest/formattertest.c @@ -33,7 +33,8 @@ #include -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { char buf[65535]; diff --git a/src/examples/futuretest/Makefile b/src/examples/futuretest/Makefile deleted file mode 100644 index 3be7e23..0000000 --- a/src/examples/futuretest/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -PROG_NOINST = futuretest${PROG_SUFFIX} -SRCS = futuretest.c - -include ../../../buildsys.mk - -CPPFLAGS += -I../../libmowgli -LIBS += -L../../libmowgli -lmowgli-2 diff --git a/src/examples/futuretest/futuretest.c b/src/examples/futuretest/futuretest.c deleted file mode 100644 index e426733..0000000 --- a/src/examples/futuretest/futuretest.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * futuretest: Combustable lemons - * - * Copyright (c) 2012 Patrick McFarland - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 - -#include - -int main(int argc, char *argv[]) { - char *text = "hello world"; - - printf("create future: "); - mowgli_future_t *future = mowgli_future_create(); - if(future != NULL) - printf("correctly created future\n"); - else - printf("error: abandon all hope\n"); - - printf("get state manually of waiting future: "); - if(mowgli_future_state(future) == MOWGLI_FUTURE_STATE_WAITING) - printf("correctly waiting\n"); - else - printf("error: %i\n", mowgli_future_state(future)); - - printf("finish future: "); - if(mowgli_future_finish(future, text) == MOWGLI_FUTURE_STATE_FINISHED) - printf("correctly finished\n"); - else - printf("error: %i\n", mowgli_future_state(future)); - - printf("get result of finished future: "); - if(mowgli_future_result(future) == text) - printf("correct: %s\n", text); - else - printf("error: %s\n", (char *)mowgli_future_result(future)); - - printf("get state of finished future: "); - if(mowgli_future_state(future) == MOWGLI_FUTURE_STATE_FINISHED) - printf("correctly finished\n"); - else - printf("error: %i\n", mowgli_future_state(future)); - - printf("reinit then cancel: "); - if(mowgli_future_init(future) == 0) { - if(mowgli_future_cancel(future) == MOWGLI_FUTURE_STATE_CANCELED) - printf("correctly canceled\n"); - else - printf("error: failed to cancel: %i\n", mowgli_future_state(future)); - - printf("try to finish on canceled future: "); - if(mowgli_future_finish(future, text) == MOWGLI_FUTURE_STATE_CANCELED) - printf("correctly caught cancel\n"); - else - printf("error: failed to cancel: %s\n", text); - } else { - printf("error: failed to reinit\n"); - } - - printf("reinit then finish twice: "); - if(mowgli_future_init(future) == 0) { - mowgli_future_finish(future, text); - - if(mowgli_future_finish(future, text) == MOWGLI_FUTURE_STATE_CONSISTENCY_FAILURE) - printf("correctly raised consistency failure\n"); - else - printf("error: finished twice: %s\n", text); - } else { - printf("error: failed to reinit\n"); - } -} diff --git a/src/examples/helpertest/helpertest.c b/src/examples/helpertest/helpertest.c index 9106000..fde9b15 100644 --- a/src/examples/helpertest/helpertest.c +++ b/src/examples/helpertest/helpertest.c @@ -25,40 +25,44 @@ int helper_count = 0; -void timer_oneshot(mowgli_eventloop_helper_proc_t *helper) +void +timer_oneshot(mowgli_eventloop_helper_proc_t *helper) { - mowgli_writef(helper->out_fd, "oneshot timer hit\n"); + mowgli_writef(helper->fd, "oneshot timer hit\n"); } -void timer_tick(mowgli_eventloop_helper_proc_t *helper) +void +timer_tick(mowgli_eventloop_helper_proc_t *helper) { static int ticks = 0; - mowgli_writef(helper->out_fd, "tick: %d\n", ++ticks); + mowgli_writef(helper->fd, "tick: %d\n", ++ticks); if (ticks > 10) mowgli_eventloop_break(helper->eventloop); } -void helper_start(mowgli_eventloop_helper_proc_t *helper, void *userdata) +void +helper_start(mowgli_eventloop_helper_proc_t *helper, void *userdata) { mowgli_eventloop_t *eventloop = helper->eventloop; - mowgli_writef(helper->out_fd, "hi from pid %d\n", getpid()); + mowgli_writef(helper->fd, "hi from pid %d\n", getpid()); mowgli_timer_add(eventloop, "timer_tick", (mowgli_event_dispatch_func_t *) timer_tick, helper, 1); mowgli_timer_add_once(eventloop, "timer_oneshot", (mowgli_event_dispatch_func_t *) timer_oneshot, helper, 5); mowgli_eventloop_run(eventloop); - mowgli_writef(helper->out_fd, "eventloop halted\n"); + mowgli_writef(helper->fd, "eventloop halted\n"); mowgli_eventloop_destroy(eventloop); } void helper_read(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata); -void helper_spawn(mowgli_eventloop_t *eventloop) +void +helper_spawn(mowgli_eventloop_t *eventloop) { mowgli_eventloop_helper_proc_t *helper; @@ -71,17 +75,20 @@ void helper_spawn(mowgli_eventloop_t *eventloop) helper_count++; } -void helper_read(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +void +helper_read(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) { size_t r; char buf[16384]; mowgli_eventloop_helper_proc_t *helper = mowgli_eventloop_io_helper(io); bzero(buf, sizeof buf); - r = read(helper->in_fd, buf, sizeof buf); + r = read(helper->fd, buf, sizeof buf); if (r > 0) - printf("helper %p [%d/%d]: %s", helper, helper->child->pid, helper->in_fd, buf); + { + printf("helper %p [%d/%d]: %s", helper, helper->child->pid, helper->fd, buf); + } else if (r <= 0) { helper_count--; @@ -92,7 +99,8 @@ void helper_read(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgl helper_spawn(eventloop); } -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { mowgli_eventloop_t *base_eventloop; diff --git a/src/examples/jsontest/Makefile b/src/examples/jsontest/Makefile new file mode 100644 index 0000000..eb5d82d --- /dev/null +++ b/src/examples/jsontest/Makefile @@ -0,0 +1,7 @@ +PROG_NOINST = jsontest${PROG_SUFFIX} +SRCS = jsontest.c + +include ../../../buildsys.mk + +CPPFLAGS += -I../../libmowgli +LIBS += -L../../libmowgli -lmowgli-2 diff --git a/src/examples/jsontest/jsontest.c b/src/examples/jsontest/jsontest.c new file mode 100644 index 0000000..a63dbc5 --- /dev/null +++ b/src/examples/jsontest/jsontest.c @@ -0,0 +1,47 @@ +#include + +void +out_string(mowgli_json_output_t *out, const char *str, size_t len) +{ + fwrite(str, 1, len, stdout); +} + +void +out_char(mowgli_json_output_t *out, const char c) +{ + fputc(c, stdout); +} + +mowgli_json_output_t out = +{ + .append = out_string, + .append_char = out_char, +}; + +int +main(int argc, char *argv[]) +{ + int i; + mowgli_json_t *n; + + if (argc < 2) + { + printf("Usage: %s file [file ...]\n", argv[0]); + return 1; + } + + for (i = 1; i < argc; i++) + { + n = mowgli_json_parse_file(argv[i]); + + if (n != NULL) + { + mowgli_json_serialize(n, &out, 1); + putchar('\n'); + } + + mowgli_json_decref(n); + } + + return 0; +} diff --git a/src/examples/libevent-bench/bench.c b/src/examples/libevent-bench/bench.c index 0e2cb08..9940b45 100644 --- a/src/examples/libevent-bench/bench.c +++ b/src/examples/libevent-bench/bench.c @@ -28,6 +28,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ + /* * Copyright 2003 Niels Provos * All rights reserved. @@ -63,19 +64,20 @@ * */ -#define timersub(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ - if ((vvp)->tv_usec < 0) { \ - (vvp)->tv_sec--; \ - (vvp)->tv_usec += 1000000; \ - } \ +#define timersub(tvp, uvp, vvp) \ + do \ + { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) \ + { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ } while (0) #include - static int count, writes, fired; static mowgli_eventloop_t *base_eventloop; static mowgli_descriptor_t *pipes; @@ -93,13 +95,17 @@ void read_cb(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *arg) { mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(io); + int idx = (int) (long) arg, widx = idx + 1; u_char ch; count += read(pollable->fd, &ch, sizeof(ch)); - if (writes) { + + if (writes) + { if (widx >= num_pipes) widx -= num_pipes; + write(pipes[2 * widx + 1], "e", 1); writes--; fired++; @@ -110,24 +116,28 @@ read_cb(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventlo void read_thunk(struct ev_io *w, int revents) { - read_cb (w->fd, revents, w->data); + read_cb(w->fd, revents, w->data); } void -timer_cb (struct ev_timer *w, int revents) +timer_cb(struct ev_timer *w, int revents) { - /* nop */ + /* nop */ } + #endif struct timeval * run_once(void) { int *cp, i, space; + static struct timeval ta, ts, te; gettimeofday(&ta, NULL); - for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { + + for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) + { if (events[i] != NULL) mowgli_pollable_destroy(base_eventloop, events[i]); @@ -138,6 +148,7 @@ run_once(void) fired = 0; space = num_pipes / num_active; space = space * 2; + for (i = 0; i < num_active; i++, fired++) write(pipes[i * space + 1], "e", 1); @@ -146,7 +157,9 @@ run_once(void) int xcount = 0; gettimeofday(&ts, NULL); - do { + + do + { mowgli_eventloop_run_once(base_eventloop); xcount++; } while (count != fired); @@ -158,15 +171,16 @@ run_once(void) fprintf(stdout, "%ld\t%ld\n", ta.tv_sec * 1000000L + ta.tv_usec, ts.tv_sec * 1000000L + ts.tv_usec - ); + ); - return (&te); + return &te; } int -main (int argc, char **argv) +main(int argc, char **argv) { struct rlimit rl; + int i, c; int *cp; extern char *optarg; @@ -174,8 +188,11 @@ main (int argc, char **argv) num_pipes = 100; num_active = 1; num_writes = num_pipes; - while ((c = getopt(argc, argv, "n:a:w:te")) != -1) { - switch (c) { + + while ((c = getopt(argc, argv, "n:a:w:te")) != -1) + { + switch (c) + { case 'n': num_pipes = atoi(optarg); break; @@ -186,7 +203,7 @@ main (int argc, char **argv) num_writes = atoi(optarg); break; case 't': - timers = 1; + timers = 1; break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); @@ -196,14 +213,17 @@ main (int argc, char **argv) #if 1 rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50; - if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { + + if (setrlimit(RLIMIT_NOFILE, &rl) == -1) perror("setrlimit"); - } + #endif events = calloc(num_pipes * 2, sizeof(mowgli_eventloop_pollable_t *)); pipes = calloc(num_pipes * 2, sizeof(mowgli_descriptor_t)); - if (events == NULL || pipes == NULL) { + + if ((events == NULL) || (pipes == NULL)) + { perror("malloc"); exit(1); } @@ -211,20 +231,24 @@ main (int argc, char **argv) mowgli_thread_set_policy(MOWGLI_THREAD_POLICY_DISABLED); base_eventloop = mowgli_eventloop_create(); - for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { + for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) + { #ifdef USE_PIPES - if (pipe(cp) == -1) { + + if (pipe(cp) == -1) + { #else - if (socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) { + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) + { #endif perror("pipe"); exit(1); } } - for (i = 0; i < 2; i++) { + for (i = 0; i < 2; i++) run_once(); - } exit(0); } diff --git a/src/examples/linetest/linetest.c b/src/examples/linetest/linetest.c index 98b8064..3175b84 100644 --- a/src/examples/linetest/linetest.c +++ b/src/examples/linetest/linetest.c @@ -27,22 +27,26 @@ mowgli_eventloop_t *base_eventloop; char buf[512]; -typedef struct { +typedef struct +{ mowgli_linebuf_t *linebuf; } client_t; void eat_line(mowgli_linebuf_t *linebuf, char *line, size_t len, void *userdata); -void write_line(mowgli_linebuf_t *linebuf, char *buf, size_t len) +void +write_line(mowgli_linebuf_t *linebuf, char *buf, size_t len) { - printf("> %s\n", buf); + printf("-> %s\n", buf); mowgli_linebuf_write(linebuf, buf, len); } -client_t * create_client(const char *server, const char *port, const char *nick, const char *user, const char *realname) +client_t * +create_client(const char *server, const char *port, const char *nick, const char *user, const char *realname) { client_t *client; struct addrinfo hints, *res; + bool use_ssl = false; mowgli_vio_sockaddr_t addr; int ret; @@ -77,12 +81,11 @@ client_t * create_client(const char *server, const char *port, const char *nick, /* Wrap the VIO object */ if (use_ssl) - { - if (mowgli_vio_openssl_setssl(linebuf->vio, NULL) != 0) + if (mowgli_vio_openssl_setssl(linebuf->vio, NULL, NULL) != 0) return NULL; - } /* We have to have a socket before starting the linebuf */ + if (mowgli_vio_socket(linebuf->vio, res->ai_family, res->ai_socktype, res->ai_protocol) != 0) return NULL; @@ -103,7 +106,8 @@ client_t * create_client(const char *server, const char *port, const char *nick, return client; } -void eat_line(mowgli_linebuf_t *linebuf, char *line, size_t len, void *userdata) +void +eat_line(mowgli_linebuf_t *linebuf, char *line, size_t len, void *userdata) { char str[512]; @@ -114,12 +118,13 @@ void eat_line(mowgli_linebuf_t *linebuf, char *line, size_t len, void *userdata) strncpy(str, line, sizeof(str)); str[len + 1] = '\0'; - printf("-> %s\n", str); + printf("<- %s\n", str); /* Since this is just a basic example, we don't have a real dispatcher :p */ if (strstr(str, "PING")) { char *pos = strpbrk(str, ":"); + if (pos) { char buf[512]; @@ -131,7 +136,8 @@ void eat_line(mowgli_linebuf_t *linebuf, char *line, size_t len, void *userdata) return; } -int main(int argc, const char *argv[]) +int +main(int argc, const char *argv[]) { client_t *client; const char *serv, *port; @@ -150,6 +156,7 @@ int main(int argc, const char *argv[]) port = argv[2]; client = create_client(serv, port, "Mowglibot", "Mowglibot", "The libmowgli example bot that does nothing useful"); + if (client == NULL) return EXIT_FAILURE; diff --git a/src/examples/listsort/listsort.c b/src/examples/listsort/listsort.c index 7aa44c2..17768b5 100644 --- a/src/examples/listsort/listsort.c +++ b/src/examples/listsort/listsort.c @@ -34,18 +34,21 @@ #include #ifdef _WIN32 -#define strcasecmp _stricmp +# define strcasecmp _stricmp #endif -int str_comparator(mowgli_node_t *n, mowgli_node_t *n2, void *opaque) +int +str_comparator(mowgli_node_t *n, mowgli_node_t *n2, void *opaque) { - int ret; + int ret; + ret = strcasecmp(n->data, n2->data); return ret; } -void test_strings(void) +void +test_strings(void) { mowgli_list_t l = { NULL, NULL, 0 }; mowgli_node_t *n, *tn; @@ -73,12 +76,13 @@ void test_strings(void) MOWGLI_LIST_FOREACH_SAFE(n, tn, l.head) { - printf(" %s\n", (char*) n->data); + printf(" %s\n", (char *) n->data); mowgli_node_delete(n, &l); } } -int int_comparator(mowgli_node_t *n, mowgli_node_t *n2, void *opaque) +int +int_comparator(mowgli_node_t *n, mowgli_node_t *n2, void *opaque) { long a = (long) n->data; long b = (long) n2->data; @@ -86,11 +90,12 @@ int int_comparator(mowgli_node_t *n, mowgli_node_t *n2, void *opaque) return a - b; } -void test_integers(void) +void +test_integers(void) { mowgli_list_t l = { NULL, NULL, 0 }; mowgli_node_t *n, *tn; - + mowgli_node_add((void *) 3, mowgli_node_create(), &l); mowgli_node_add((void *) 2, mowgli_node_create(), &l); mowgli_node_add((void *) 4, mowgli_node_create(), &l); @@ -107,7 +112,8 @@ void test_integers(void) } } -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { test_strings(); test_integers(); diff --git a/src/examples/memslice-bench/memslice-bench.c b/src/examples/memslice-bench/memslice-bench.c index 3fb05d5..3ed95fc 100644 --- a/src/examples/memslice-bench/memslice-bench.c +++ b/src/examples/memslice-bench/memslice-bench.c @@ -18,15 +18,17 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#define timersub(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ - if ((vvp)->tv_usec < 0) { \ - (vvp)->tv_sec--; \ - (vvp)->tv_usec += 1000000; \ - } \ - } while (0) +#define timersub(tvp, uvp, vvp) \ + do \ + { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) \ + { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) #include @@ -37,10 +39,11 @@ int main(int argc, char *argv[]) { size_t i; + size_t objects; size_t *obj_sizes; void **ptrs; - struct timeval ts, te; + struct timeval ts, te; mowgli_thread_set_policy(MOWGLI_THREAD_POLICY_DISABLED); @@ -66,52 +69,57 @@ main(int argc, char *argv[]) printf("Going to allocate %zu objects of random sizes < 256\n", objects); printf("Assigning sizes...\n"); - for (i = 0; i < objects; i++) { + + for (i = 0; i < objects; i++) obj_sizes[i] = rand() % 256; - } + printf("Done! Lets benchmark.\n"); /* allocate using sysmalloc */ gettimeofday(&ts, NULL); - for (i = 0; i < objects; i++) { + + for (i = 0; i < objects; i++) ptrs[i] = mowgli_alloc_using_policy(sysmalloc, obj_sizes[i]); - } + gettimeofday(&te, NULL); timersub(&te, &ts, &ts); printf("sysmalloc alloc time: %ld usec\n", - ts.tv_sec * 1000000L + ts.tv_usec); + ts.tv_sec * 1000000L + ts.tv_usec); gettimeofday(&ts, NULL); - for (i = 0; i < objects; i++) { + + for (i = 0; i < objects; i++) mowgli_free(ptrs[i]); - } + gettimeofday(&te, NULL); timersub(&te, &ts, &ts); printf("sysmalloc free time: %ld usec\n", - ts.tv_sec * 1000000L + ts.tv_usec); + ts.tv_sec * 1000000L + ts.tv_usec); /* allocate using memslice */ gettimeofday(&ts, NULL); - for (i = 0; i < objects; i++) { + + for (i = 0; i < objects; i++) ptrs[i] = mowgli_alloc_using_policy(memslice, obj_sizes[i]); - } + gettimeofday(&te, NULL); timersub(&te, &ts, &ts); printf("memslice alloc time: %ld usec\n", - ts.tv_sec * 1000000L + ts.tv_usec); + ts.tv_sec * 1000000L + ts.tv_usec); gettimeofday(&ts, NULL); - for (i = 0; i < objects; i++) { + + for (i = 0; i < objects; i++) mowgli_free(ptrs[i]); - } + gettimeofday(&te, NULL); timersub(&te, &ts, &ts); printf("memslice free time: %ld usec\n", - ts.tv_sec * 1000000L + ts.tv_usec); + ts.tv_sec * 1000000L + ts.tv_usec); return EXIT_SUCCESS; } diff --git a/src/examples/patriciatest/patriciatest.c b/src/examples/patriciatest/patriciatest.c index 98c5f65..4dbb212 100644 --- a/src/examples/patriciatest/patriciatest.c +++ b/src/examples/patriciatest/patriciatest.c @@ -35,18 +35,21 @@ int errors = 0; -void str_canon(char *key) +void +str_canon(char *key) { return; } -void statscb(const char *line, void *data) +void +statscb(const char *line, void *data) { printf("%s\n", line); } /* assumes data is key */ -static void check_all_retrievable(mowgli_patricia_t *dtree) +static void +check_all_retrievable(mowgli_patricia_t *dtree) { mowgli_patricia_iteration_state_t state; void *elem, *elem2; @@ -58,37 +61,45 @@ static void check_all_retrievable(mowgli_patricia_t *dtree) n2 = mowgli_patricia_size(dtree); MOWGLI_PATRICIA_FOREACH(elem, &state, dtree) { - elem2 = mowgli_patricia_retrieve(dtree, (const char *)elem); + elem2 = mowgli_patricia_retrieve(dtree, (const char *) elem); + if (elem2 == NULL) { errors++; printf("failed to find element %s\n", - (const char *)elem); + (const char *) elem); } else if (strcmp(elem2, elem)) { printf("element %s != %s\n", - (const char *)elem, - (const char *)elem2); + (const char *) elem, + (const char *) elem2); errors++; } else + { printf("."); + } + fflush(stdout); n1++; + if (n1 > n2 * 2) break; } + if (n1 != n2) { errors++; printf("number of iterated elements %u != size %u\n", n1, n2); } + printf("\n"); fflush(stdout); } -void test_patricia(void) +void +test_patricia(void) { mowgli_patricia_t *dtree; mowgli_patricia_iteration_state_t state; @@ -119,7 +130,7 @@ void test_patricia(void) MOWGLI_PATRICIA_FOREACH(elem, &state, dtree) { - printf("element -> %s\n", (const char *)elem); + printf("element -> %s\n", (const char *) elem); } printf("End of elements\n"); mowgli_patricia_stats(dtree, statscb, NULL); @@ -147,7 +158,8 @@ void test_patricia(void) mowgli_patricia_destroy(dtree, NULL, NULL); } -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { test_patricia(); diff --git a/src/examples/patriciatest2/patriciatest2.c b/src/examples/patriciatest2/patriciatest2.c index d73b1ee..800c59e 100644 --- a/src/examples/patriciatest2/patriciatest2.c +++ b/src/examples/patriciatest2/patriciatest2.c @@ -37,17 +37,19 @@ int errors = 0; -void str_canon(char *key) +void +str_canon(char *key) { return; } -void statscb(const char *line, void *data) -{ -} +void +statscb(const char *line, void *data) +{ } /* assumes data is key */ -static void check_all_retrievable(mowgli_patricia_t *dtree) +static void +check_all_retrievable(mowgli_patricia_t *dtree) { mowgli_patricia_iteration_state_t state; void *elem, *elem2; @@ -57,24 +59,28 @@ static void check_all_retrievable(mowgli_patricia_t *dtree) n2 = mowgli_patricia_size(dtree); MOWGLI_PATRICIA_FOREACH(elem, &state, dtree) { - elem2 = mowgli_patricia_retrieve(dtree, (const char *)elem); + elem2 = mowgli_patricia_retrieve(dtree, (const char *) elem); + if (elem2 == NULL) { errors++; printf("failed to find element %s\n", - (const char *)elem); + (const char *) elem); } else if (strcmp(elem2, elem)) { printf("element %s != %s\n", - (const char *)elem, - (const char *)elem2); + (const char *) elem, + (const char *) elem2); errors++; } + n1++; + if (n1 > n2 * 2) break; } + if (n1 != n2) { errors++; @@ -82,17 +88,20 @@ static void check_all_retrievable(mowgli_patricia_t *dtree) } } -void test_patricia(void) +void +test_patricia(void) { mowgli_patricia_t *dtree; int i, j; char buf[100], *strings[TESTSIZE]; srandom(12346); + for (i = 0; i < TESTSIZE; i++) { for (j = 0; j < 40; j++) buf[j] = 'a' + random() % 26; + buf[20 + random() % 20] = '\0'; strings[i] = strdup(buf); } @@ -110,12 +119,14 @@ void test_patricia(void) for (i = 0; i < TESTSIZE / 2; i++) { mowgli_patricia_delete(dtree, strings[i]); + if (mowgli_patricia_retrieve(dtree, strings[i])) { printf("still retrievable after delete: %s\n", - strings[i]); + strings[i]); errors++; } + check_all_retrievable(dtree); } @@ -128,12 +139,14 @@ void test_patricia(void) for (i = 0; i < TESTSIZE; i++) { mowgli_patricia_delete(dtree, strings[i]); + if (mowgli_patricia_retrieve(dtree, strings[i])) { printf("still retrievable after delete: %s\n", - strings[i]); + strings[i]); errors++; } + check_all_retrievable(dtree); } @@ -143,7 +156,8 @@ void test_patricia(void) free(strings[i]); } -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { test_patricia(); diff --git a/src/examples/randomtest/randomtest.c b/src/examples/randomtest/randomtest.c index 2c4b2d7..eb7ef05 100644 --- a/src/examples/randomtest/randomtest.c +++ b/src/examples/randomtest/randomtest.c @@ -33,16 +33,20 @@ */ #include -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { mowgli_random_t *r = mowgli_random_create(); int i; printf("1000 iterations:\n"); + for (i = 0; i < 1000; i++) { printf("%10u ", mowgli_random_int(r)); - if (i % 5 == 4) printf("\n"); + + if (i % 5 == 4) + printf("\n"); } mowgli_object_unref(r); diff --git a/src/examples/timertest/timertest.c b/src/examples/timertest/timertest.c index 242b8a9..f99410b 100644 --- a/src/examples/timertest/timertest.c +++ b/src/examples/timertest/timertest.c @@ -25,12 +25,14 @@ mowgli_eventloop_t *eventloop; -void timer_oneshot(void *unused) +void +timer_oneshot(void *unused) { printf("oneshot timer hit\n"); } -void timer_tick(void *unused) +void +timer_tick(void *unused) { static int ticks = 0; @@ -40,7 +42,8 @@ void timer_tick(void *unused) mowgli_eventloop_break(eventloop); } -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { eventloop = mowgli_eventloop_create(); diff --git a/src/examples/vio-udplistener/vio-udplistener.c b/src/examples/vio-udplistener/vio-udplistener.c index 9de4e69..1e1dda1 100644 --- a/src/examples/vio-udplistener/vio-udplistener.c +++ b/src/examples/vio-udplistener/vio-udplistener.c @@ -7,18 +7,19 @@ #define BUFSIZE 2048 -#define PROTO AF_INET6 -#define LISTEN "::ffff:127.0.0.1" /* 6to4 mapping */ -#define PORT 31337 +#define PROTO AF_INET6 +#define LISTEN "::ffff:127.0.0.1" /* 6to4 mapping */ +#define PORT 31337 #define ECHOBACK "Echo: " -int main (void) +int +main(void) { mowgli_vio_t *vio = mowgli_vio_create(NULL); mowgli_vio_sockaddr_t addr; - - mowgli_vio_sockaddr_create(&addr, PROTO, LISTEN, 31337); + + mowgli_vio_sockaddr_create(&addr, PROTO, LISTEN, PORT); if (mowgli_vio_socket(vio, PROTO, SOCK_DGRAM, 0)) return EXIT_FAILURE; @@ -41,5 +42,5 @@ int main (void) mowgli_vio_sendto(vio, buf, strlen(buf), &addr); } - return EXIT_SUCCESS; /* Not reached */ + return EXIT_SUCCESS; /* Not reached */ } diff --git a/src/libmowgli/Makefile b/src/libmowgli/Makefile index 4cf3942..b81552a 100644 --- a/src/libmowgli/Makefile +++ b/src/libmowgli/Makefile @@ -6,7 +6,7 @@ LIB_MINOR = 0 SHARED_LIB = ${LIBMOWGLI_SHARED_LIB} STATIC_LIB = ${LIBMOWGLI_STATIC_LIB} -SUBDIRS = ${LIBMOWGLI_MODULES} platform +SUBDIRS = ${LIBMOWGLI_MODULES} INCLUDES = mowgli.h @@ -15,5 +15,7 @@ OBJS_EXTRA = ${LIBMOWGLI_STATIC_MODULES} include ../../buildsys.mk +$(OBJS_EXTRA) $(LIB_OBJS_EXTRA): subdirs + LIBS += ${PTHREAD_LIBS} CPPFLAGS += -I. -I../.. -DMOWGLI_CORE diff --git a/src/libmowgli/base/argstack.c b/src/libmowgli/base/argstack.c index ea67da2..560c83e 100644 --- a/src/libmowgli/base/argstack.c +++ b/src/libmowgli/base/argstack.c @@ -30,7 +30,8 @@ static mowgli_object_class_t klass; * * \param vptr pointer to mowgli_argstack_t to destroy. */ -static void mowgli_argstack_destroy(void *vptr) +static void +mowgli_argstack_destroy(void *vptr) { mowgli_argstack_t *self = (mowgli_argstack_t *) vptr; mowgli_node_t *n, *tn; @@ -48,17 +49,18 @@ static void mowgli_argstack_destroy(void *vptr) /* * \brief Initialization code for the mowgli.argstack library. - * + * * Side Effects: * - the mowgli_argstack_t object class is registered. */ -void mowgli_argstack_bootstrap(void) +void +mowgli_argstack_bootstrap(void) { mowgli_object_class_init(&klass, "mowgli_argstack_t", mowgli_argstack_destroy, FALSE); } /* - * \brief Creates an argument stack from a va_list and an appropriate + * \brief Creates an argument stack from a va_list and an appropriate * description schema. * * \param descstr a description string which describes the argument stack, where: @@ -70,20 +72,20 @@ void mowgli_argstack_bootstrap(void) * * \return a mowgli_argstack_t (mowgli.argstack) object. */ -mowgli_argstack_t *mowgli_argstack_create_from_va_list(const char *descstr, va_list va) +mowgli_argstack_t * +mowgli_argstack_create_from_va_list(const char *descstr, va_list va) { + return_null_if_fail(descstr != NULL); + const char *cp = descstr; mowgli_argstack_t *out = mowgli_alloc(sizeof(mowgli_argstack_t)); mowgli_object_init(mowgli_object(out), descstr, &klass, NULL); - if (descstr == NULL) - mowgli_throw_exception_val(mowgli.argstack.invalid_description, NULL); - while (*cp) { mowgli_argstack_element_t *e = mowgli_alloc(sizeof(mowgli_argstack_element_t)); - switch(*cp) + switch (*cp) { case 's': e->data.string = va_arg(va, char *); @@ -104,7 +106,8 @@ mowgli_argstack_t *mowgli_argstack_create_from_va_list(const char *descstr, va_l default: va_end(va); mowgli_object_unref(out); - mowgli_throw_exception_val(mowgli.argstack.invalid_description, NULL); + mowgli_log_warning("invalid description"); + return NULL; break; } @@ -127,14 +130,14 @@ mowgli_argstack_t *mowgli_argstack_create_from_va_list(const char *descstr, va_l * * \return a mowgli_argstack_t (mowgli.argstack) object. */ -mowgli_argstack_t *mowgli_argstack_create(const char *descstr, ...) +mowgli_argstack_t * +mowgli_argstack_create(const char *descstr, ...) { + return_null_if_fail(descstr != NULL); + va_list va; mowgli_argstack_t *out; - if (descstr == NULL) - mowgli_throw_exception_val(mowgli.argstack.invalid_description, NULL); - va_start(va, descstr); out = mowgli_argstack_create_from_va_list(descstr, va); va_end(va); @@ -152,14 +155,14 @@ mowgli_argstack_t *mowgli_argstack_create(const char *descstr, ...) * Side Effects: * - the argument is removed from the argstack. */ -const char *mowgli_argstack_pop_string(mowgli_argstack_t *self) +const char * +mowgli_argstack_pop_string(mowgli_argstack_t *self) { + return_null_if_fail(self != NULL); + mowgli_node_t *n; mowgli_argstack_element_t *e; - if (self == NULL) - mowgli_throw_exception_val(mowgli.null_pointer_exception, NULL); - n = self->stack.head; mowgli_node_delete(n, &self->stack); e = n->data; @@ -178,14 +181,14 @@ const char *mowgli_argstack_pop_string(mowgli_argstack_t *self) * Side Effects: * - the argument is removed from the argstack. */ -int mowgli_argstack_pop_numeric(mowgli_argstack_t *self) +int +mowgli_argstack_pop_numeric(mowgli_argstack_t *self) { + return_val_if_fail(self != NULL, 0); + mowgli_node_t *n; mowgli_argstack_element_t *e; - if (self == NULL) - mowgli_throw_exception_val(mowgli.null_pointer_exception, 0); - n = self->stack.head; mowgli_node_delete(n, &self->stack); e = n->data; @@ -204,14 +207,14 @@ int mowgli_argstack_pop_numeric(mowgli_argstack_t *self) * Side Effects: * - the argument is removed from the argstack. */ -mowgli_boolean_t mowgli_argstack_pop_boolean(mowgli_argstack_t *self) +mowgli_boolean_t +mowgli_argstack_pop_boolean(mowgli_argstack_t *self) { + return_val_if_fail(self != NULL, false); + mowgli_node_t *n; mowgli_argstack_element_t *e; - if (self == NULL) - mowgli_throw_exception_val(mowgli.null_pointer_exception, FALSE); - n = self->stack.head; mowgli_node_delete(n, &self->stack); e = n->data; @@ -230,14 +233,14 @@ mowgli_boolean_t mowgli_argstack_pop_boolean(mowgli_argstack_t *self) * Side Effects: * - the argument is removed from the argstack. */ -void *mowgli_argstack_pop_pointer(mowgli_argstack_t *self) +void * +mowgli_argstack_pop_pointer(mowgli_argstack_t *self) { + return_null_if_fail(self != NULL); + mowgli_node_t *n; mowgli_argstack_element_t *e; - if (self == NULL) - mowgli_throw_exception_val(mowgli.null_pointer_exception, NULL); - n = self->stack.head; mowgli_node_delete(n, &self->stack); e = n->data; diff --git a/src/libmowgli/base/argstack.h b/src/libmowgli/base/argstack.h index adf68c2..b3b86f9 100644 --- a/src/libmowgli/base/argstack.h +++ b/src/libmowgli/base/argstack.h @@ -24,29 +24,33 @@ #ifndef __MOWGLI_ARGSTACK_H__ #define __MOWGLI_ARGSTACK_H__ -typedef enum { +typedef enum +{ MOWGLI_ARG_NUMERIC, MOWGLI_ARG_POINTER, MOWGLI_ARG_STRING, MOWGLI_ARG_BOOLEAN } mowgli_argstack_element_type_t; -typedef struct { - union { +typedef struct +{ + union + { int numeric; void *pointer; char *string; mowgli_boolean_t boolean; } data; + mowgli_argstack_element_type_t type; } mowgli_argstack_element_t; -typedef struct { +typedef struct +{ mowgli_object_t parent; mowgli_list_t stack; } mowgli_argstack_t; -extern void mowgli_argstack_bootstrap(void); extern mowgli_argstack_t *mowgli_argstack_create(const char *descstr, ...); extern mowgli_argstack_t *mowgli_argstack_create_from_va_list(const char *descstr, va_list va); extern const char *mowgli_argstack_pop_string(mowgli_argstack_t *); diff --git a/src/libmowgli/base/bitvector.c b/src/libmowgli/base/bitvector.c index b70df55..45fca31 100644 --- a/src/libmowgli/base/bitvector.c +++ b/src/libmowgli/base/bitvector.c @@ -39,7 +39,8 @@ static mowgli_object_class_t klass; * Side Effects: * - the mowgli_bitvector_t object class is registered. */ -void mowgli_bitvector_bootstrap(void) +void +mowgli_bitvector_bootstrap(void) { mowgli_object_class_init(&klass, "mowgli_bitvector_t", mowgli_free, FALSE); } @@ -58,14 +59,16 @@ void mowgli_bitvector_bootstrap(void) * Side Effects: * - none */ -mowgli_bitvector_t *mowgli_bitvector_create(int bits) +mowgli_bitvector_t * +mowgli_bitvector_create(int bits) { mowgli_bitvector_t *bv = (mowgli_bitvector_t *) mowgli_alloc(sizeof(mowgli_bitvector_t)); + mowgli_object_init(mowgli_object(bv), "mowgli_bitvector_t", &klass, NULL); - bv->bits = bits; + bv->bits = bits; bv->divisor = sizeof(int); - bv->vector = (unsigned int *) mowgli_alloc_array(bv->divisor, bv->bits / bv->divisor); + bv->vector = (unsigned int *) mowgli_alloc_array(bv->divisor, bv->bits / bv->divisor); return bv; } @@ -86,19 +89,20 @@ mowgli_bitvector_t *mowgli_bitvector_create(int bits) * Side Effects: * - a bit is either set ON or OFF in the bitvector. */ -void mowgli_bitvector_set(mowgli_bitvector_t *bv, int slot, mowgli_boolean_t val) +void +mowgli_bitvector_set(mowgli_bitvector_t *bv, int slot, mowgli_boolean_t val) { int value = 1 << slot; - switch(val) + switch (val) { - case FALSE: - bv->vector[bv->bits / bv->divisor] &= ~value; - break; - default: - case TRUE: - bv->vector[bv->bits / bv->divisor] |= value; - break; + case FALSE: + bv->vector[bv->bits / bv->divisor] &= ~value; + break; + default: + case TRUE: + bv->vector[bv->bits / bv->divisor] |= value; + break; } } @@ -118,7 +122,8 @@ void mowgli_bitvector_set(mowgli_bitvector_t *bv, int slot, mowgli_boolean_t val * Side Effects: * - none */ -mowgli_boolean_t mowgli_bitvector_get(mowgli_bitvector_t *bv, int slot) +mowgli_boolean_t +mowgli_bitvector_get(mowgli_bitvector_t *bv, int slot) { int mask = 1 << slot; @@ -139,7 +144,8 @@ mowgli_boolean_t mowgli_bitvector_get(mowgli_bitvector_t *bv, int slot) * Side Effects: * - none */ -mowgli_bitvector_t *mowgli_bitvector_combine(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) +mowgli_bitvector_t * +mowgli_bitvector_combine(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) { int bits, iter, bs; mowgli_bitvector_t *out; @@ -179,7 +185,8 @@ mowgli_bitvector_t *mowgli_bitvector_combine(mowgli_bitvector_t *bv1, mowgli_bit * Side Effects: * - none */ -mowgli_bitvector_t *mowgli_bitvector_xor(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) +mowgli_bitvector_t * +mowgli_bitvector_xor(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) { int bits, iter, bs; mowgli_bitvector_t *out; @@ -220,19 +227,18 @@ mowgli_bitvector_t *mowgli_bitvector_xor(mowgli_bitvector_t *bv1, mowgli_bitvect * Side Effects: * - none */ -mowgli_boolean_t mowgli_bitvector_compare(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) +mowgli_boolean_t +mowgli_bitvector_compare(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) { - int iter, bs; + int iter, bs; mowgli_boolean_t ret = TRUE; /* cache the size of the bitvector in memory. */ bs = bv1->bits / bv1->divisor; for (iter = 0; iter < bs; iter++) - { if (!(bv1->vector[iter] & bv2->vector[iter])) ret = FALSE; - } return ret; } diff --git a/src/libmowgli/base/bitvector.h b/src/libmowgli/base/bitvector.h index 592ba59..f96709d 100644 --- a/src/libmowgli/base/bitvector.h +++ b/src/libmowgli/base/bitvector.h @@ -24,13 +24,13 @@ #ifndef __MOWGLI_BITVECTOR_H__ #define __MOWGLI_BITVECTOR_H__ -typedef struct { +typedef struct +{ unsigned int bits; unsigned int divisor; unsigned int *vector; } mowgli_bitvector_t; -extern void mowgli_bitvector_bootstrap(void); extern mowgli_bitvector_t *mowgli_bitvector_create(int bits); extern void mowgli_bitvector_set(mowgli_bitvector_t *bv, int slot, mowgli_boolean_t val); extern mowgli_boolean_t mowgli_bitvector_get(mowgli_bitvector_t *bv, int slot); diff --git a/src/libmowgli/base/formatter.c b/src/libmowgli/base/formatter.c index 21d9e46..db908e7 100644 --- a/src/libmowgli/base/formatter.c +++ b/src/libmowgli/base/formatter.c @@ -23,7 +23,8 @@ #include "mowgli.h" -void mowgli_formatter_format_from_argstack(char *buf, size_t bufstr, const char *fmtstr, const char *descstr, mowgli_argstack_t *stack) +void +mowgli_formatter_format_from_argstack(char *buf, size_t bufstr, const char *fmtstr, const char *descstr, mowgli_argstack_t *stack) { size_t pos = 0; char *i = buf; @@ -42,14 +43,17 @@ void mowgli_formatter_format_from_argstack(char *buf, size_t bufstr, const char pos = strlen(buf); - switch(*fiter) + switch (*fiter) { case '%': fiter++; arg = atoi(fiter); e = mowgli_node_nth_data(&stack->stack, arg - 1); - while (isdigit(*fiter)) fiter++; + while (isdigit(*fiter)) + { + fiter++; + } if (e == NULL) { @@ -58,7 +62,7 @@ void mowgli_formatter_format_from_argstack(char *buf, size_t bufstr, const char continue; } - switch(e->type) + switch (e->type) { case MOWGLI_ARG_STRING: arg = snprintf(i, bufstr - (i - buf), "%s", e->data.string); @@ -77,7 +81,7 @@ void mowgli_formatter_format_from_argstack(char *buf, size_t bufstr, const char i += arg; break; default: - mowgli_throw_exception(mowgli.formatter.unhandled_type_exception); + mowgli_log("unhandled type"); break; } @@ -92,7 +96,8 @@ void mowgli_formatter_format_from_argstack(char *buf, size_t bufstr, const char } } -void mowgli_formatter_format(char *buf, size_t bufstr, const char *fmtstr, const char *descstr, ...) +void +mowgli_formatter_format(char *buf, size_t bufstr, const char *fmtstr, const char *descstr, ...) { va_list va; mowgli_argstack_t *stack; @@ -104,7 +109,8 @@ void mowgli_formatter_format(char *buf, size_t bufstr, const char *fmtstr, const mowgli_formatter_format_from_argstack(buf, bufstr, fmtstr, descstr, stack); } -void mowgli_formatter_print(const char *fmtstr, const char *descstr, ...) +void +mowgli_formatter_print(const char *fmtstr, const char *descstr, ...) { va_list va; char buf[65535]; diff --git a/src/libmowgli/base/hash.c b/src/libmowgli/base/hash.c index 7d70d8c..a2734d0 100644 --- a/src/libmowgli/base/hash.c +++ b/src/libmowgli/base/hash.c @@ -25,12 +25,13 @@ #define HASHINIT 0x811c9dc5 #define HASHBITS 16 -#define HASHSIZE (1 << HASHBITS) /* 2^16 = 65536 */ +#define HASHSIZE (1 << HASHBITS)/* 2^16 = 65536 */ -int mowgli_fnv_hash_string(const char *p) +int +mowgli_fnv_hash_string(const char *p) { static int htoast = 0; - unsigned int hval = HASHINIT; + unsigned int hval = HASHINIT; if (htoast == 0) { @@ -39,21 +40,23 @@ int mowgli_fnv_hash_string(const char *p) mowgli_object_unref(r); } - if (!p) - return (0); - for (; *p != '\0'; ++p) - { - hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); - hval ^= (tolower(*p) ^ htoast); - } + if (!p) + return 0; - return ((hval >> HASHBITS) ^ (hval & ((1 << HASHBITS) - 1)) % HASHSIZE); + for (; *p != '\0'; ++p) + { + hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); + hval ^= (tolower(*p) ^ htoast); + } + + return (hval >> HASHBITS) ^ (hval & ((1 << HASHBITS) - 1)) % HASHSIZE; } -int mowgli_fnv_hash(unsigned int *p) +int +mowgli_fnv_hash(unsigned int *p) { static int htoast = 0; - unsigned int hval = HASHINIT; + unsigned int hval = HASHINIT; if (htoast == 0) { @@ -62,13 +65,14 @@ int mowgli_fnv_hash(unsigned int *p) mowgli_object_unref(r); } - if (!p) - return (0); - for (; *p != '\0'; ++p) - { - hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); - hval ^= (tolower(*p) ^ htoast); - } + if (!p) + return 0; + + for (; *p != '\0'; ++p) + { + hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); + hval ^= (tolower(*p) ^ htoast); + } - return ((hval >> HASHBITS) ^ (hval & ((1 << HASHBITS) - 1)) % HASHSIZE); + return (hval >> HASHBITS) ^ (hval & ((1 << HASHBITS) - 1)) % HASHSIZE; } diff --git a/src/libmowgli/base/hook.c b/src/libmowgli/base/hook.c index 0af9660..315266a 100644 --- a/src/libmowgli/base/hook.c +++ b/src/libmowgli/base/hook.c @@ -27,7 +27,8 @@ static mowgli_patricia_t *mowgli_hooks = NULL; static mowgli_heap_t *mowgli_hook_item_heap; -static void _hook_key_canon(char *str) +static void +_hook_key_canon(char *str) { while (*str) { @@ -116,7 +117,7 @@ mowgli_hook_dissociate(const char *name, mowgli_hook_function_t func) mowgli_heap_free(mowgli_hook_item_heap, hookitem); return 0; - } + } } return -1; diff --git a/src/libmowgli/base/hook.h b/src/libmowgli/base/hook.h index 366e123..5d8d317 100644 --- a/src/libmowgli/base/hook.h +++ b/src/libmowgli/base/hook.h @@ -27,21 +27,22 @@ typedef void (*mowgli_hook_function_t)(void *hook_data, void *user_data); -typedef struct { - mowgli_hook_function_t func; - void *user_data; - mowgli_node_t node; +typedef struct +{ + mowgli_hook_function_t func; + void *user_data; + mowgli_node_t node; } mowgli_hook_item_t; -typedef struct { - const char *name; - mowgli_list_t items; +typedef struct +{ + const char *name; + mowgli_list_t items; } mowgli_hook_t; -extern void mowgli_hook_bootstrap(void); extern void mowgli_hook_register(const char *name); -extern int mowgli_hook_associate(const char *name, mowgli_hook_function_t func, void * user_data); -extern int mowgli_hook_dissociate(const char *name, mowgli_hook_function_t func); -extern void mowgli_hook_call(const char *name, void * hook_data); +extern int mowgli_hook_associate(const char *name, mowgli_hook_function_t func, void *user_data); +extern int mowgli_hook_dissociate(const char *name, mowgli_hook_function_t func); +extern void mowgli_hook_call(const char *name, void *hook_data); #endif diff --git a/src/libmowgli/base/memslice.c b/src/libmowgli/base/memslice.c index a271821..8d8f3a2 100644 --- a/src/libmowgli/base/memslice.c +++ b/src/libmowgli/base/memslice.c @@ -26,7 +26,8 @@ static mowgli_heap_t *allocator_heap; /* * Our slice allocation engine. */ -typedef struct { +typedef struct +{ size_t size; mowgli_heap_t *heap; @@ -36,7 +37,8 @@ typedef struct { /* * Allocation tag. */ -typedef struct { +typedef struct +{ slice_alloc_t *owner; } slice_tag_t; @@ -49,6 +51,7 @@ nexthigher(size_t k) size_t i; k--; + for (i = 1; i < sizeof(k) * 8; i <<= 1) k |= k >> i; @@ -109,7 +112,7 @@ memslice_alloc(size_t i) ptr = mowgli_heap_alloc(alloc->heap); ((slice_tag_t *) ptr)->owner = alloc; - return ptr + sizeof(slice_tag_t); + return (char *) ptr + sizeof(slice_tag_t); } /* @@ -122,7 +125,7 @@ memslice_free(void *ptr) return_if_fail(ptr != NULL); - tag = ptr - sizeof(slice_tag_t); + tag = (void *) ((char *) ptr - sizeof(slice_tag_t)); mowgli_heap_free(tag->owner->heap, tag); } diff --git a/src/libmowgli/base/memslice.h b/src/libmowgli/base/memslice.h index 9d6e842..12ce8f7 100644 --- a/src/libmowgli/base/memslice.h +++ b/src/libmowgli/base/memslice.h @@ -21,7 +21,6 @@ #ifndef __MOWGLI_MEMSLICE_H__ #define __MOWGLI_MEMSLICE_H__ -void mowgli_memslice_bootstrap(void); mowgli_allocation_policy_t *mowgli_memslice_get_policy(void); #endif diff --git a/src/libmowgli/base/mowgli_signal.c b/src/libmowgli/base/mowgli_signal.c index 208ce37..60602b4 100644 --- a/src/libmowgli/base/mowgli_signal.c +++ b/src/libmowgli/base/mowgli_signal.c @@ -26,11 +26,15 @@ #include #include "mowgli.h" +#if defined(__linux__) && defined(__GNUC__) && defined(__STRICT_ANSI__) +# error GCC/Linux in -std=c99 mode will not compile mowgli_signal; use -std=gnu99 instead +#endif + static mowgli_signal_handler_t -mowgli_signal_install_handler_full(int signum, mowgli_signal_handler_t handler, - int *sigtoblock, size_t sigtoblocksize) +mowgli_signal_install_handler_full(int signum, mowgli_signal_handler_t handler, int *sigtoblock, size_t sigtoblocksize) { struct sigaction action, old_action; + size_t i; action.sa_handler = handler; diff --git a/src/libmowgli/base/mowgli_signal.h b/src/libmowgli/base/mowgli_signal.h index b194d8d..1c7f33e 100644 --- a/src/libmowgli/base/mowgli_signal.h +++ b/src/libmowgli/base/mowgli_signal.h @@ -24,7 +24,7 @@ #ifndef __MOWGLI_SIGNAL_H__ #define __MOWGLI_SIGNAL_H__ -typedef void (*mowgli_signal_handler_t) (int); +typedef void (*mowgli_signal_handler_t)(int); extern mowgli_signal_handler_t mowgli_signal_install_handler(int signum, mowgli_signal_handler_t handler); diff --git a/src/libmowgli/base/random.c b/src/libmowgli/base/random.c index b316033..a183057 100644 --- a/src/libmowgli/base/random.c +++ b/src/libmowgli/base/random.c @@ -27,9 +27,9 @@ /* period parameters */ #define N 624 #define M 397 -#define MATRIX_A 0x9908b0dfUL /* constant vector a */ -#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ -#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ /* mowgli_random_t contains state data which is private */ struct mowgli_random_ @@ -42,20 +42,24 @@ struct mowgli_random_ static mowgli_object_class_t klass; /* initialization */ -void mowgli_random_bootstrap(void) +void +mowgli_random_bootstrap(void) { mowgli_object_class_init(&klass, "mowgli_random_t", NULL, FALSE); } /* construction and destruction. */ -mowgli_random_t *mowgli_random_create(void) +mowgli_random_t * +mowgli_random_create(void) { return mowgli_random_create_with_seed(time(NULL)); } -mowgli_random_t *mowgli_random_create_with_seed(unsigned int seed) +mowgli_random_t * +mowgli_random_create_with_seed(unsigned int seed) { mowgli_random_t *out = mowgli_alloc(sizeof(mowgli_random_t)); + mowgli_object_init(mowgli_object(out), NULL, &klass, NULL); mowgli_random_reseed(out, seed); @@ -64,11 +68,13 @@ mowgli_random_t *mowgli_random_create_with_seed(unsigned int seed) } /* reset seed */ -void mowgli_random_reseed(mowgli_random_t *self, unsigned int seed) +void +mowgli_random_reseed(mowgli_random_t *self, unsigned int seed) { return_if_fail(self != NULL); self->mt[0] = seed & 0xffffffffUL; + for (self->mti = 1; self->mti < N; self->mti++) { self->mt[self->mti] = (1812433253UL * (self->mt[self->mti - 1] ^ (self->mt[self->mti - 1] >> 30)) + self->mti); @@ -77,7 +83,8 @@ void mowgli_random_reseed(mowgli_random_t *self, unsigned int seed) } /* number retrieval */ -unsigned int mowgli_random_int(mowgli_random_t *self) +unsigned int +mowgli_random_int(mowgli_random_t *self) { unsigned int y; static unsigned int mag01[2] = { 0x0UL, MATRIX_A }; @@ -97,7 +104,7 @@ unsigned int mowgli_random_int(mowgli_random_t *self) for (; t < N - 1; t++) { y = (self->mt[t] & UPPER_MASK) | (self->mt[t + 1] & LOWER_MASK); - self->mt[t] = self->mt[t + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1U]; + self->mt[t] = self->mt[t + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1U]; } y = (self->mt[N - 1] & UPPER_MASK) | (self->mt[0] & LOWER_MASK); @@ -116,7 +123,8 @@ unsigned int mowgli_random_int(mowgli_random_t *self) return y; } -int mowgli_random_int_ranged(mowgli_random_t *self, int begin, int end) +int +mowgli_random_int_ranged(mowgli_random_t *self, int begin, int end) { unsigned int dist = end - begin; unsigned int max, ret; @@ -129,13 +137,16 @@ int mowgli_random_int_ranged(mowgli_random_t *self, int begin, int end) remain -= dist; max = 0xFFFFFFFFU - remain; - } else + } + else + { max = dist - 1; + } do - { ret = mowgli_random_int(self); - } while (ret > max); + + while (ret > max); ret %= dist; diff --git a/src/libmowgli/base/random.h b/src/libmowgli/base/random.h index ea53dd7..9153478 100644 --- a/src/libmowgli/base/random.h +++ b/src/libmowgli/base/random.h @@ -26,10 +26,8 @@ /* mowgli_random_t contains state data which is private */ struct mowgli_random_; -typedef struct mowgli_random_ mowgli_random_t; -/* object class initialization. */ -extern void mowgli_random_bootstrap(void); +typedef struct mowgli_random_ mowgli_random_t; /* construction and destruction. */ extern mowgli_random_t *mowgli_random_create(void); diff --git a/src/libmowgli/container/dictionary.c b/src/libmowgli/container/dictionary.c index 22445d7..3ffe08e 100644 --- a/src/libmowgli/container/dictionary.c +++ b/src/libmowgli/container/dictionary.c @@ -50,7 +50,8 @@ struct mowgli_dictionary_ * - if services runs out of memory and cannot allocate the object, * the program will abort. */ -mowgli_dictionary_t *mowgli_dictionary_create(mowgli_dictionary_comparator_func_t compare_cb) +mowgli_dictionary_t * +mowgli_dictionary_create(mowgli_dictionary_comparator_func_t compare_cb) { mowgli_dictionary_t *dtree = (mowgli_dictionary_t *) mowgli_alloc(sizeof(mowgli_dictionary_t)); @@ -63,7 +64,7 @@ mowgli_dictionary_t *mowgli_dictionary_create(mowgli_dictionary_comparator_func_ } /* - * mowgli_dictionary_create_named(const char *name, + * mowgli_dictionary_create_named(const char *name, * mowgli_dictionary_comparator_func_t compare_cb) * * Dictionary object factory. @@ -79,8 +80,8 @@ mowgli_dictionary_t *mowgli_dictionary_create(mowgli_dictionary_comparator_func_ * - if services runs out of memory and cannot allocate the object, * the program will abort. */ -mowgli_dictionary_t *mowgli_dictionary_create_named(const char *name, - mowgli_dictionary_comparator_func_t compare_cb) +mowgli_dictionary_t * +mowgli_dictionary_create_named(const char *name, mowgli_dictionary_comparator_func_t compare_cb) { mowgli_dictionary_t *dtree = (mowgli_dictionary_t *) mowgli_alloc(sizeof(mowgli_dictionary_t)); @@ -110,8 +111,8 @@ mowgli_dictionary_t *mowgli_dictionary_create_named(const char *name, * Side Effects: * - the dictionary comparator function is reset. */ -void mowgli_dictionary_set_comparator_func(mowgli_dictionary_t *dict, - mowgli_dictionary_comparator_func_t compare_cb) +void +mowgli_dictionary_set_comparator_func(mowgli_dictionary_t *dict, mowgli_dictionary_comparator_func_t compare_cb) { return_if_fail(dict != NULL); return_if_fail(compare_cb != NULL); @@ -166,11 +167,14 @@ mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, const void *key) return_val_if_fail(key != NULL, 0); elem = mowgli_dictionary_find(dict, key); + if (elem == NULL) return -1; if (!dict->dirty) + { return elem->position; + } else { mowgli_dictionary_elem_t *delem; @@ -248,14 +252,14 @@ mowgli_dictionary_retune(mowgli_dictionary_t *dict, const void *key) * we initialize n with known values, since it's on stack * memory. otherwise the dict would become corrupted. * - * n is used for temporary storage while the tree is retuned. + * n is used for temporary storage while the tree is retuned. * -nenolod */ n.left = n.right = NULL; left = right = &n; /* this for(;;) loop is the main workhorse of the rebalancing */ - for (node = dict->root; ; ) + for (node = dict->root;;) { if ((ret = dict->compare_cb(key, node->key)) == 0) break; @@ -333,8 +337,7 @@ mowgli_dictionary_retune(mowgli_dictionary_t *dict, const void *key) * - a node is linked to the dictionary tree */ void -mowgli_dictionary_link(mowgli_dictionary_t *dict, - mowgli_dictionary_elem_t *delem) +mowgli_dictionary_link(mowgli_dictionary_t *dict, mowgli_dictionary_elem_t *delem) { return_if_fail(dict != NULL); return_if_fail(delem != NULL); @@ -420,19 +423,25 @@ mowgli_dictionary_unlink_root(mowgli_dictionary_t *dict) dict->dirty = true; delem = dict->root; + if (delem == NULL) return; if (dict->root->left == NULL) + { dict->root = dict->root->right; + } else if (dict->root->right == NULL) + { dict->root = dict->root->left; + } else { /* Make the node with the next highest key the new root. * This node has a NULL left pointer. */ nextnode = delem->next; soft_assert(nextnode->left == NULL); + if (nextnode == delem->right) { dict->root = nextnode; @@ -441,8 +450,12 @@ mowgli_dictionary_unlink_root(mowgli_dictionary_t *dict) else { parentofnext = delem->right; + while (parentofnext->left != NULL && parentofnext->left != nextnode) + { parentofnext = parentofnext->left; + } + soft_assert(parentofnext->left == nextnode); parentofnext->left = nextnode->right; dict->root = nextnode; @@ -489,9 +502,8 @@ mowgli_dictionary_unlink_root(mowgli_dictionary_t *dict) * - if this is called without a callback, the objects bound to the * DTree will not be destroyed. */ -void mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, - void (*destroy_cb)(mowgli_dictionary_elem_t *delem, void *privdata), - void *privdata) +void +mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, void (*destroy_cb)(mowgli_dictionary_elem_t *delem, void *privdata), void *privdata) { mowgli_dictionary_elem_t *n, *tn; @@ -526,9 +538,8 @@ void mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, * Side Effects: * - on success, a dtree is iterated */ -void mowgli_dictionary_foreach(mowgli_dictionary_t *dtree, - int (*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), - void *privdata) +void +mowgli_dictionary_foreach(mowgli_dictionary_t *dtree, int (*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), void *privdata) { mowgli_dictionary_elem_t *n, *tn; @@ -563,9 +574,8 @@ void mowgli_dictionary_foreach(mowgli_dictionary_t *dtree, * Side Effects: * - a dtree is iterated until the requested conditions are met */ -void *mowgli_dictionary_search(mowgli_dictionary_t *dtree, - void *(*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), - void *privdata) +void * +mowgli_dictionary_search(mowgli_dictionary_t *dtree, void *(*foreach_cb)(mowgli_dictionary_elem_t * delem, void *privdata), void *privdata) { mowgli_dictionary_elem_t *n, *tn; void *ret = NULL; @@ -603,8 +613,8 @@ void *mowgli_dictionary_search(mowgli_dictionary_t *dtree, * Side Effects: * - the static iterator, &state, is initialized. */ -void mowgli_dictionary_foreach_start(mowgli_dictionary_t *dtree, - mowgli_dictionary_iteration_state_t *state) +void +mowgli_dictionary_foreach_start(mowgli_dictionary_t *dtree, mowgli_dictionary_iteration_state_t *state) { return_if_fail(dtree != NULL); return_if_fail(state != NULL); @@ -641,8 +651,8 @@ void mowgli_dictionary_foreach_start(mowgli_dictionary_t *dtree, * Side Effects: * - none */ -void *mowgli_dictionary_foreach_cur(mowgli_dictionary_t *dtree, - mowgli_dictionary_iteration_state_t *state) +void * +mowgli_dictionary_foreach_cur(mowgli_dictionary_t *dtree, mowgli_dictionary_iteration_state_t *state) { return_val_if_fail(dtree != NULL, NULL); return_val_if_fail(state != NULL, NULL); @@ -666,15 +676,15 @@ void *mowgli_dictionary_foreach_cur(mowgli_dictionary_t *dtree, * Side Effects: * - the static iterator, &state, is advanced to a new DTree node. */ -void mowgli_dictionary_foreach_next(mowgli_dictionary_t *dtree, - mowgli_dictionary_iteration_state_t *state) +void +mowgli_dictionary_foreach_next(mowgli_dictionary_t *dtree, mowgli_dictionary_iteration_state_t *state) { return_if_fail(dtree != NULL); return_if_fail(state != NULL); if (state->cur == NULL) { - mowgli_log("mowgli_dictionary_foreach_next(): called again after iteration finished on dtree<%p>", dtree); + mowgli_log("mowgli_dictionary_foreach_next(): called again after iteration finished on dtree<%p>", (void *) dtree); return; } @@ -702,7 +712,8 @@ void mowgli_dictionary_foreach_next(mowgli_dictionary_t *dtree, * Side Effects: * - none */ -mowgli_dictionary_elem_t *mowgli_dictionary_find(mowgli_dictionary_t *dict, const void *key) +mowgli_dictionary_elem_t * +mowgli_dictionary_find(mowgli_dictionary_t *dict, const void *key) { return_val_if_fail(dict != NULL, NULL); return_val_if_fail(key != NULL, NULL); @@ -733,7 +744,8 @@ mowgli_dictionary_elem_t *mowgli_dictionary_find(mowgli_dictionary_t *dict, cons * Side Effects: * - data is inserted into the DTree. */ -mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dict, const void *key, void *data) +mowgli_dictionary_elem_t * +mowgli_dictionary_add(mowgli_dictionary_t *dict, const void *key, void *data) { mowgli_dictionary_elem_t *delem; @@ -748,7 +760,7 @@ mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dict, const if (delem->key == NULL) { - mowgli_log("major WTF: delem->key is NULL, not adding node.", key); + mowgli_log("major WTF: delem->key<%p> is NULL, not adding node.", (void *) key); mowgli_heap_free(elem_heap, delem); return NULL; } @@ -777,7 +789,8 @@ mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dict, const * Notes: * - the returned data needs to be mowgli_freed/released manually! */ -void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const void *key) +void * +mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const void *key) { mowgli_dictionary_elem_t *delem = mowgli_dictionary_find(dtree, key); void *data; @@ -788,7 +801,7 @@ void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const void *key) data = delem->data; mowgli_dictionary_unlink_root(dtree); - mowgli_heap_free(elem_heap, delem); + mowgli_heap_free(elem_heap, delem); return data; } @@ -809,7 +822,8 @@ void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const void *key) * Side Effects: * - none */ -void *mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const void *key) +void * +mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const void *key) { mowgli_dictionary_elem_t *delem = mowgli_dictionary_find(dtree, key); @@ -833,7 +847,8 @@ void *mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const void *key) * Side Effects: * - none */ -unsigned int mowgli_dictionary_size(mowgli_dictionary_t *dict) +unsigned int +mowgli_dictionary_size(mowgli_dictionary_t *dict) { return_val_if_fail(dict != NULL, 0); @@ -848,11 +863,15 @@ stats_recurse(mowgli_dictionary_elem_t *delem, int depth, int *pmaxdepth) if (depth > *pmaxdepth) *pmaxdepth = depth; + result = depth; + if (delem->left) result += stats_recurse(delem->left, depth + 1, pmaxdepth); + if (delem->right) result += stats_recurse(delem->right, depth + 1, pmaxdepth); + return result; } @@ -872,7 +891,8 @@ stats_recurse(mowgli_dictionary_elem_t *delem, int depth, int *pmaxdepth) * Side Effects: * - callback called with stats text */ -void mowgli_dictionary_stats(mowgli_dictionary_t *dict, void (*cb)(const char *line, void *privdata), void *privdata) +void +mowgli_dictionary_stats(mowgli_dictionary_t *dict, void (*cb)(const char *line, void *privdata), void *privdata) { char str[256]; int sum, maxdepth; @@ -881,19 +901,24 @@ void mowgli_dictionary_stats(mowgli_dictionary_t *dict, void (*cb)(const char *l if (dict->id != NULL) snprintf(str, sizeof str, "Dictionary stats for %s (%d)", - dict->id, dict->count); + dict->id, dict->count); else snprintf(str, sizeof str, "Dictionary stats for <%p> (%d)", - dict, dict->count); + (void *) dict, dict->count); + cb(str, privdata); maxdepth = 0; + if (dict->root != NULL) { sum = stats_recurse(dict->root, 0, &maxdepth); snprintf(str, sizeof str, "Depth sum %d Avg depth %d Max depth %d", sum, sum / dict->count, maxdepth); } else + { snprintf(str, sizeof str, "Depth sum 0 Avg depth 0 Max depth 0"); + } + cb(str, privdata); return; } diff --git a/src/libmowgli/container/dictionary.h b/src/libmowgli/container/dictionary.h index 3c2f4e5..3745a1a 100644 --- a/src/libmowgli/container/dictionary.h +++ b/src/libmowgli/container/dictionary.h @@ -25,7 +25,7 @@ #ifndef __MOWGLI_DICTIONARY_H__ #define __MOWGLI_DICTIONARY_H__ -struct mowgli_dictionary_; /* defined in src/dictionary.c */ +struct mowgli_dictionary_; /* defined in src/dictionary.c */ typedef struct mowgli_dictionary_ mowgli_dictionary_t; @@ -56,7 +56,8 @@ typedef struct mowgli_dictionary_iteration_state_ mowgli_dictionary_iteration_st /* * this is a convenience macro for inlining iteration of dictionaries. */ -#define MOWGLI_DICTIONARY_FOREACH(element, state, dict) for (mowgli_dictionary_foreach_start((dict), (state)); (element = mowgli_dictionary_foreach_cur((dict), (state))); mowgli_dictionary_foreach_next((dict), (state))) +#define MOWGLI_DICTIONARY_FOREACH(element, state, dict) \ + for (mowgli_dictionary_foreach_start((dict), (state)); (element = mowgli_dictionary_foreach_cur((dict), (state))); mowgli_dictionary_foreach_next((dict), (state))) /* * mowgli_dictionary_create() creates a new dictionary tree. @@ -75,8 +76,7 @@ extern mowgli_dictionary_t *mowgli_dictionary_create_named(const char *name, mow * mowgli_dictionary_set_comparator_func() resets the comparator used for lookups and * insertions in the DTree structure. */ -extern void mowgli_dictionary_set_comparator_func(mowgli_dictionary_t *dict, - mowgli_dictionary_comparator_func_t compare_cb); +extern void mowgli_dictionary_set_comparator_func(mowgli_dictionary_t *dict, mowgli_dictionary_comparator_func_t compare_cb); /* * mowgli_dictionary_get_comparator_func() returns the comparator used for lookups and @@ -94,9 +94,7 @@ extern int mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, const v * mowgli_dictionary_destroy() destroys all entries in a dtree, and also optionally calls * a defined callback function to destroy any data attached to it. */ -extern void mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, - void (*destroy_cb)(mowgli_dictionary_elem_t *delem, void *privdata), - void *privdata); +extern void mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, void (*destroy_cb)(mowgli_dictionary_elem_t *delem, void *privdata), void *privdata); /* * mowgli_dictionary_foreach() iterates all entries in a dtree, and also optionally calls @@ -104,9 +102,7 @@ extern void mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, * * To shortcircuit iteration, return non-zero from the callback function. */ -extern void mowgli_dictionary_foreach(mowgli_dictionary_t *dtree, - int (*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), - void *privdata); +extern void mowgli_dictionary_foreach(mowgli_dictionary_t *dtree, int (*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), void *privdata); /* * mowgli_dictionary_search() iterates all entries in a dtree, and also optionally calls @@ -115,9 +111,7 @@ extern void mowgli_dictionary_foreach(mowgli_dictionary_t *dtree, * When the object is found, a non-NULL is returned from the callback, which results * in that object being returned to the user. */ -extern void *mowgli_dictionary_search(mowgli_dictionary_t *dtree, - void *(*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), - void *privdata); +extern void *mowgli_dictionary_search(mowgli_dictionary_t *dtree, void *(*foreach_cb)(mowgli_dictionary_elem_t * delem, void *privdata), void *privdata); /* * mowgli_dictionary_foreach_start() begins an iteration over all items @@ -125,21 +119,18 @@ extern void *mowgli_dictionary_search(mowgli_dictionary_t *dtree, * in progress at a time, it is permitted to remove the current element * of the iteration (but not any other element). */ -extern void mowgli_dictionary_foreach_start(mowgli_dictionary_t *dtree, - mowgli_dictionary_iteration_state_t *state); +extern void mowgli_dictionary_foreach_start(mowgli_dictionary_t *dtree, mowgli_dictionary_iteration_state_t *state); /* * mowgli_dictionary_foreach_cur() returns the current element of the iteration, * or NULL if there are no more elements. */ -extern void *mowgli_dictionary_foreach_cur(mowgli_dictionary_t *dtree, - mowgli_dictionary_iteration_state_t *state); +extern void *mowgli_dictionary_foreach_cur(mowgli_dictionary_t *dtree, mowgli_dictionary_iteration_state_t *state); /* * mowgli_dictionary_foreach_next() moves to the next element. */ -extern void mowgli_dictionary_foreach_next(mowgli_dictionary_t *dtree, - mowgli_dictionary_iteration_state_t *state); +extern void mowgli_dictionary_foreach_next(mowgli_dictionary_t *dtree, mowgli_dictionary_iteration_state_t *state); /* * mowgli_dictionary_add() adds a key->value entry to the dictionary tree. diff --git a/src/libmowgli/container/index.c b/src/libmowgli/container/index.c index 81776f5..aeeaf26 100644 --- a/src/libmowgli/container/index.c +++ b/src/libmowgli/container/index.c @@ -24,164 +24,185 @@ struct mowgli_index_ { - void * * data; - int count, size; - int (* compare) (const void * a, const void * b, void * data); - void * compare_data; + void **data; + int count, size; + int (*compare)(const void *a, const void *b, void *data); + void *compare_data; }; static mowgli_heap_t *index_heap = NULL; -void mowgli_index_init (void) +void +mowgli_index_init(void) { - index_heap = mowgli_heap_create(sizeof(mowgli_index_t), 32, BH_NOW); + index_heap = mowgli_heap_create(sizeof(mowgli_index_t), 32, BH_NOW); } -mowgli_index_t * mowgli_index_create (void) +mowgli_index_t * +mowgli_index_create(void) { - mowgli_index_t * index = mowgli_heap_alloc(index_heap); + mowgli_index_t *index = mowgli_heap_alloc(index_heap); - index->data = NULL; - index->count = 0; - index->size = 0; - index->compare = NULL; - index->compare_data = NULL; + index->data = NULL; + index->count = 0; + index->size = 0; + index->compare = NULL; + index->compare_data = NULL; - return index; + return index; } -void mowgli_index_destroy (mowgli_index_t * index) +void +mowgli_index_destroy(mowgli_index_t *index) { - mowgli_free (index->data); - mowgli_heap_free (index_heap, index); + mowgli_free(index->data); + mowgli_heap_free(index_heap, index); } -int mowgli_index_count (mowgli_index_t * index) +int +mowgli_index_count(mowgli_index_t *index) { - return index->count; + return index->count; } -void mowgli_index_allocate (mowgli_index_t * index, int size) +void +mowgli_index_allocate(mowgli_index_t *index, int size) { - size_t oldsize; - void *new_ptr; + size_t oldsize; + void *new_ptr; - if (size <= index->size) - return; + if (size <= index->size) + return; - if (! index->size) - index->size = 64; + if (!index->size) + index->size = 64; - oldsize = index->size; - while (size > index->size) - index->size <<= 1; + oldsize = index->size; - new_ptr = mowgli_alloc_array(sizeof (void *), index->size); + while (size > index->size) + { + index->size <<= 1; + } - if (index->data != NULL) - { - memcpy(new_ptr, index->data, oldsize); - mowgli_free(index->data); - } + new_ptr = mowgli_alloc_array(sizeof(void *), index->size); - index->data = new_ptr; + if (index->data != NULL) + { + memcpy(new_ptr, index->data, oldsize); + mowgli_free(index->data); + } + + index->data = new_ptr; } -void mowgli_index_set (mowgli_index_t * index, int at, void * value) +void +mowgli_index_set(mowgli_index_t *index, int at, void *value) { - index->data[at] = value; + index->data[at] = value; } -void * mowgli_index_get (mowgli_index_t * index, int at) +void * +mowgli_index_get(mowgli_index_t *index, int at) { - return index->data[at]; + return index->data[at]; } -static void make_room (mowgli_index_t * index, int at, int count) +static void +make_room(mowgli_index_t *index, int at, int count) { - mowgli_index_allocate (index, index->count + count); + mowgli_index_allocate(index, index->count + count); - if (at < index->count) - memmove (index->data + at + count, index->data + at, sizeof (void *) * - (index->count - at)); + if (at < index->count) + memmove(index->data + at + count, index->data + at, sizeof(void *) * + (index->count - at)); - index->count += count; + index->count += count; } -void mowgli_index_insert (mowgli_index_t * index, int at, void * value) +void +mowgli_index_insert(mowgli_index_t *index, int at, void *value) { - make_room (index, at, 1); - index->data[at] = value; + make_room(index, at, 1); + index->data[at] = value; } -void mowgli_index_append (mowgli_index_t * index, void * value) +void +mowgli_index_append(mowgli_index_t *index, void *value) { - mowgli_index_insert (index, index->count, value); + mowgli_index_insert(index, index->count, value); } -void mowgli_index_copy_set (mowgli_index_t * source, int from, mowgli_index_t * target, - int to, int count) +void +mowgli_index_copy_set(mowgli_index_t *source, int from, mowgli_index_t *target, int to, int count) { - memcpy (target->data + to, source->data + from, sizeof (void *) * count); + memcpy(target->data + to, source->data + from, sizeof(void *) * count); } -void mowgli_index_copy_insert (mowgli_index_t * source, int from, mowgli_index_t * target, - int to, int count) +void +mowgli_index_copy_insert(mowgli_index_t *source, int from, mowgli_index_t *target, int to, int count) { - make_room (target, to, count); - memcpy (target->data + to, source->data + from, sizeof (void *) * count); + make_room(target, to, count); + memcpy(target->data + to, source->data + from, sizeof(void *) * count); } -void mowgli_index_copy_append (mowgli_index_t * source, int from, mowgli_index_t * target, - int count) +void +mowgli_index_copy_append(mowgli_index_t *source, int from, mowgli_index_t *target, int count) { - mowgli_index_copy_insert (source, from, target, target->count, count); + mowgli_index_copy_insert(source, from, target, target->count, count); } -void mowgli_index_merge_insert (mowgli_index_t * first, int at, mowgli_index_t * second) +void +mowgli_index_merge_insert(mowgli_index_t *first, int at, mowgli_index_t *second) { - mowgli_index_copy_insert (second, 0, first, at, second->count); + mowgli_index_copy_insert(second, 0, first, at, second->count); } -void mowgli_index_merge_append (mowgli_index_t * first, mowgli_index_t * second) +void +mowgli_index_merge_append(mowgli_index_t *first, mowgli_index_t *second) { - mowgli_index_copy_insert (second, 0, first, first->count, second->count); + mowgli_index_copy_insert(second, 0, first, first->count, second->count); } -void mowgli_index_move (mowgli_index_t * index, int from, int to, int count) +void +mowgli_index_move(mowgli_index_t *index, int from, int to, int count) { - memmove (index->data + to, index->data + from, sizeof (void *) * count); + memmove(index->data + to, index->data + from, sizeof(void *) * count); } -void mowgli_index_delete (mowgli_index_t * index, int at, int count) +void +mowgli_index_delete(mowgli_index_t *index, int at, int count) { - index->count -= count; - memmove (index->data + at, index->data + at + count, sizeof (void *) * - (index->count - at)); + index->count -= count; + memmove(index->data + at, index->data + at + count, sizeof(void *) * + (index->count - at)); } -void mowgli_index_sort (mowgli_index_t * index, int (* compare) (const void *, const void *)) +void +mowgli_index_sort(mowgli_index_t *index, int (*compare)(const void *, const void *)) { - qsort(index->data, index->count, sizeof (void *), compare); + qsort(index->data, index->count, sizeof(void *), compare); } #ifdef NOTYET -static int mowgli_index_compare_with_data (const void * a, const void * b, void * _index) +static int +mowgli_index_compare_with_data(const void *a, const void *b, void *_index) { - mowgli_index_t * index = _index; + mowgli_index_t *index = _index; - return index->compare (* (const void * *) a, * (const void * *) b, - index->compare_data); + return index->compare(*(const void **) a, *(const void **) b, + index->compare_data); } -void mowgli_index_sort_with_data (mowgli_index_t * index, int (* compare) - (const void * a, const void * b, void * data), void * data) +void +mowgli_index_sort_with_data(mowgli_index_t *index, int(*compare) + (const void *a, const void *b, void *data), void *data) { - index->compare = compare; - index->compare_data = data; - g_qsort_with_data (index->data, index->count, sizeof (void *), - mowgli_index_compare_with_data, index); - index->compare = NULL; - index->compare_data = NULL; + index->compare = compare; + index->compare_data = data; + g_qsort_with_data(index->data, index->count, sizeof(void *), + mowgli_index_compare_with_data, index); + index->compare = NULL; + index->compare_data = NULL; } + #endif diff --git a/src/libmowgli/container/index.h b/src/libmowgli/container/index.h index 85e9e72..50341db 100644 --- a/src/libmowgli/container/index.h +++ b/src/libmowgli/container/index.h @@ -25,27 +25,23 @@ struct mowgli_index_; typedef struct mowgli_index_ mowgli_index_t; -mowgli_index_t * mowgli_index_create (void); -void mowgli_index_destroy (mowgli_index_t * index); -int mowgli_index_count (mowgli_index_t * index); -void mowgli_index_allocate (mowgli_index_t * index, int size); -void mowgli_index_set (mowgli_index_t * index, int at, void * value); -void * mowgli_index_get (mowgli_index_t * index, int at); -void mowgli_index_insert (mowgli_index_t * index, int at, void * value); -void mowgli_index_append (mowgli_index_t * index, void * value); -void mowgli_index_copy_set (mowgli_index_t * source, int from, mowgli_index_t * target, - int to, int count); -void mowgli_index_copy_insert (mowgli_index_t * source, int from, mowgli_index_t * target, - int to, int count); -void mowgli_index_copy_append (mowgli_index_t * source, int from, mowgli_index_t * target, - int count); -void mowgli_index_merge_insert (mowgli_index_t * first, int at, mowgli_index_t * second); -void mowgli_index_merge_append (mowgli_index_t * first, mowgli_index_t * second); -void mowgli_index_move (mowgli_index_t * index, int from, int to, int count); -void mowgli_index_delete (mowgli_index_t * index, int at, int count); -void mowgli_index_sort (mowgli_index_t * index, int (* compare) (const void * a, - const void * b)); -void mowgli_index_sort_with_data (mowgli_index_t * index, int (* compare) - (const void * a, const void * b, void * data), void * data); +mowgli_index_t *mowgli_index_create(void); +void mowgli_index_destroy(mowgli_index_t *index); +int mowgli_index_count(mowgli_index_t *index); +void mowgli_index_allocate(mowgli_index_t *index, int size); +void mowgli_index_set(mowgli_index_t *index, int at, void *value); +void *mowgli_index_get(mowgli_index_t *index, int at); +void mowgli_index_insert(mowgli_index_t *index, int at, void *value); +void mowgli_index_append(mowgli_index_t *index, void *value); +void mowgli_index_copy_set(mowgli_index_t *source, int from, mowgli_index_t *target, int to, int count); +void mowgli_index_copy_insert(mowgli_index_t *source, int from, mowgli_index_t *target, int to, int count); +void mowgli_index_copy_append(mowgli_index_t *source, int from, mowgli_index_t *target, int count); +void mowgli_index_merge_insert(mowgli_index_t *first, int at, mowgli_index_t *second); +void mowgli_index_merge_append(mowgli_index_t *first, mowgli_index_t *second); +void mowgli_index_move(mowgli_index_t *index, int from, int to, int count); +void mowgli_index_delete(mowgli_index_t *index, int at, int count); +void mowgli_index_sort(mowgli_index_t *index, int (*compare)(const void *a, const void *b)); +void mowgli_index_sort_with_data(mowgli_index_t *index, int(*compare) + (const void *a, const void *b, void *data), void *data); #endif diff --git a/src/libmowgli/container/list.c b/src/libmowgli/container/list.c index 6283910..695417b 100644 --- a/src/libmowgli/container/list.c +++ b/src/libmowgli/container/list.c @@ -26,12 +26,13 @@ static mowgli_heap_t *mowgli_node_heap; static mowgli_heap_t *mowgli_list_heap; -void mowgli_node_bootstrap(void) +void +mowgli_node_bootstrap(void) { - mowgli_node_heap = mowgli_heap_create(sizeof(mowgli_node_t), 1024, BH_NOW); - mowgli_list_heap = mowgli_heap_create(sizeof(mowgli_list_t), 64, BH_NOW); + mowgli_node_heap = mowgli_heap_create(sizeof(mowgli_node_t), 1024, BH_NOW); + mowgli_list_heap = mowgli_heap_create(sizeof(mowgli_list_t), 64, BH_NOW); - if (mowgli_node_heap == NULL || mowgli_list_heap == NULL) + if ((mowgli_node_heap == NULL) || (mowgli_list_heap == NULL)) { mowgli_log("heap allocator failure."); abort(); @@ -39,31 +40,34 @@ void mowgli_node_bootstrap(void) } /* creates a new node */ -mowgli_node_t *mowgli_node_create(void) +mowgli_node_t * +mowgli_node_create(void) { - mowgli_node_t *n; + mowgli_node_t *n; - /* allocate it */ - n = mowgli_heap_alloc(mowgli_node_heap); + /* allocate it */ + n = mowgli_heap_alloc(mowgli_node_heap); - /* initialize */ - n->next = n->prev = n->data = NULL; + /* initialize */ + n->next = n->prev = n->data = NULL; - /* return a pointer to the new node */ - return n; + /* return a pointer to the new node */ + return n; } /* frees a node */ -void mowgli_node_free(mowgli_node_t *n) +void +mowgli_node_free(mowgli_node_t *n) { return_if_fail(n != NULL); - /* free it */ - mowgli_heap_free(mowgli_node_heap, n); + /* free it */ + mowgli_heap_free(mowgli_node_heap, n); } /* adds a node to the end of a list */ -void mowgli_node_add(void *data, mowgli_node_t *n, mowgli_list_t *l) +void +mowgli_node_add(void *data, mowgli_node_t *n, mowgli_list_t *l) { mowgli_node_t *tn; @@ -78,7 +82,7 @@ void mowgli_node_add(void *data, mowgli_node_t *n, mowgli_list_t *l) { l->head = n; l->tail = n; - l->count++; + l->count = 1; return; } @@ -99,7 +103,8 @@ void mowgli_node_add(void *data, mowgli_node_t *n, mowgli_list_t *l) } /* adds a node to the head of a list */ -void mowgli_node_add_head(void *data, mowgli_node_t *n, mowgli_list_t *l) +void +mowgli_node_add_head(void *data, mowgli_node_t *n, mowgli_list_t *l) { mowgli_node_t *tn; @@ -110,11 +115,11 @@ void mowgli_node_add_head(void *data, mowgli_node_t *n, mowgli_list_t *l) n->data = data; /* first node? */ - if (!l->head) + if (l->head == NULL) { l->head = n; l->tail = n; - l->count++; + l->count = 1; return; } @@ -126,15 +131,20 @@ void mowgli_node_add_head(void *data, mowgli_node_t *n, mowgli_list_t *l) } /* adds a node to a list before another node, or to the end */ -void mowgli_node_add_before(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgli_node_t *before) +void +mowgli_node_add_before(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgli_node_t *before) { return_if_fail(n != NULL); return_if_fail(l != NULL); if (before == NULL) + { mowgli_node_add(data, n, l); + } else if (before == l->head) + { mowgli_node_add_head(data, n, l); + } else { n->data = data; @@ -150,13 +160,16 @@ void mowgli_node_add_before(void *data, mowgli_node_t *n, mowgli_list_t *l, mowg } /* adds a node to a list after another node, or to the end */ -void mowgli_node_add_after(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgli_node_t *before) +void +mowgli_node_add_after(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgli_node_t *before) { return_if_fail(n != NULL); return_if_fail(l != NULL); - if (before == NULL || before->next == NULL) + if ((before == NULL) || (before->next == NULL)) + { mowgli_node_add(data, n, l); + } else { n->data = data; @@ -169,7 +182,8 @@ void mowgli_node_add_after(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgl } /* retrieves a node at `position` position. */ -mowgli_node_t *mowgli_node_nth(mowgli_list_t *l, size_t pos) +mowgli_node_t * +mowgli_node_nth(mowgli_list_t *l, size_t pos) { size_t iter; mowgli_node_t *n; @@ -178,16 +192,20 @@ mowgli_node_t *mowgli_node_nth(mowgli_list_t *l, size_t pos) /* locate the proper position. */ if (pos < MOWGLI_LIST_LENGTH(l) / 2) - for (iter = 0, n = l->head; iter != pos && n != NULL; iter++, n = n->next); + for (iter = 0, n = l->head; iter != pos && n != NULL; iter++, n = n->next) + ; + else for (iter = MOWGLI_LIST_LENGTH(l) - 1, n = l->tail; - iter != pos && n != NULL; iter--, n = n->prev); + iter != pos && n != NULL; iter--, n = n->prev) + ; return n; } /* returns the data from node at `position` position, or NULL. */ -void *mowgli_node_nth_data(mowgli_list_t *l, size_t pos) +void * +mowgli_node_nth_data(mowgli_list_t *l, size_t pos) { mowgli_node_t *n; @@ -202,7 +220,8 @@ void *mowgli_node_nth_data(mowgli_list_t *l, size_t pos) } /* inserts a node at `position` position. */ -void mowgli_node_insert(void *data, mowgli_node_t *n, mowgli_list_t *l, size_t pos) +void +mowgli_node_insert(void *data, mowgli_node_t *n, mowgli_list_t *l, size_t pos) { mowgli_node_t *tn; @@ -216,7 +235,8 @@ void mowgli_node_insert(void *data, mowgli_node_t *n, mowgli_list_t *l, size_t p } /* retrieves the index position of a node in a list. */ -ssize_t mowgli_node_index(mowgli_node_t *n, mowgli_list_t *l) +ssize_t +mowgli_node_index(mowgli_node_t *n, mowgli_list_t *l) { ssize_t iter; mowgli_node_t *tn; @@ -225,82 +245,89 @@ ssize_t mowgli_node_index(mowgli_node_t *n, mowgli_list_t *l) return_val_if_fail(l != NULL, -1); /* locate the proper position. */ - for (iter = 0, tn = l->head; tn != n && tn != NULL; iter++, tn = tn->next); + for (iter = 0, tn = l->head; tn != n && tn != NULL; iter++, tn = tn->next) + ; return iter < (ssize_t) MOWGLI_LIST_LENGTH(l) ? iter : -1; } /* deletes a link between a node and a list. */ -void mowgli_node_delete(mowgli_node_t *n, mowgli_list_t *l) +void +mowgli_node_delete(mowgli_node_t *n, mowgli_list_t *l) { return_if_fail(n != NULL); return_if_fail(l != NULL); - /* are we the head? */ - if (!n->prev) - l->head = n->next; - else - n->prev->next = n->next; + /* are we the head? */ + if (!n->prev) + l->head = n->next; + else + n->prev->next = n->next; - /* are we the tail? */ - if (!n->next) - l->tail = n->prev; - else - n->next->prev = n->prev; + /* are we the tail? */ + if (!n->next) + l->tail = n->prev; + else + n->next->prev = n->prev; - /* down the count */ - l->count--; + /* down the count */ + l->count--; } /* finds a node by `data' */ -mowgli_node_t *mowgli_node_find(void *data, mowgli_list_t *l) +mowgli_node_t * +mowgli_node_find(void *data, mowgli_list_t *l) { mowgli_node_t *n; return_val_if_fail(l != NULL, NULL); - MOWGLI_LIST_FOREACH(n, l->head) if (n->data == data) + MOWGLI_LIST_FOREACH(n, l->head) + + if (n->data == data) return n; return NULL; } /* moves a node from one list to another. */ -void mowgli_node_move(mowgli_node_t *m, mowgli_list_t *oldlist, mowgli_list_t *newlist) +void +mowgli_node_move(mowgli_node_t *m, mowgli_list_t *oldlist, mowgli_list_t *newlist) { return_if_fail(m != NULL); return_if_fail(oldlist != NULL); return_if_fail(newlist != NULL); - /* Assumption: If m->next == NULL, then list->tail == m - * and: If m->prev == NULL, then list->head == m - */ - if (m->next != NULL) - m->next->prev = m->prev; - else - oldlist->tail = m->prev; + /* Assumption: If m->next == NULL, then list->tail == m + * and: If m->prev == NULL, then list->head == m + */ + if (m->next != NULL) + m->next->prev = m->prev; + else + oldlist->tail = m->prev; - if (m->prev != NULL) - m->prev->next = m->next; - else - oldlist->head = m->next; + if (m->prev != NULL) + m->prev->next = m->next; + else + oldlist->head = m->next; - m->prev = NULL; - m->next = newlist->head; + m->prev = NULL; + m->next = newlist->head; - if (newlist->head != NULL) - newlist->head->prev = m; - else if (newlist->tail == NULL) - newlist->tail = m; + if (newlist->head != NULL) + newlist->head->prev = m; + else if (newlist->tail == NULL) + newlist->tail = m; - newlist->head = m; + newlist->head = m; - oldlist->count--; - newlist->count++; + oldlist->count--; + newlist->count++; } /* creates a new list. */ -mowgli_list_t *mowgli_list_create(void) +mowgli_list_t * +mowgli_list_create(void) { mowgli_list_t *out = mowgli_heap_alloc(mowgli_list_heap); @@ -308,13 +335,15 @@ mowgli_list_t *mowgli_list_create(void) } /* frees a created list. */ -void mowgli_list_free(mowgli_list_t *l) +void +mowgli_list_free(mowgli_list_t *l) { mowgli_heap_free(mowgli_list_heap, l); } /* concatenates two lists together. */ -void mowgli_list_concat(mowgli_list_t *l, mowgli_list_t *l2) +void +mowgli_list_concat(mowgli_list_t *l, mowgli_list_t *l2) { return_if_fail(l != NULL); return_if_fail(l2 != NULL); @@ -334,7 +363,8 @@ void mowgli_list_concat(mowgli_list_t *l, mowgli_list_t *l2) } /* reverse a list -- O(n)! */ -void mowgli_list_reverse(mowgli_list_t *l) +void +mowgli_list_reverse(mowgli_list_t *l) { mowgli_node_t *n, *tn; @@ -343,6 +373,7 @@ void mowgli_list_reverse(mowgli_list_t *l) MOWGLI_LIST_FOREACH_SAFE(n, tn, l->head) { mowgli_node_t *tn2 = n->next; + n->next = n->prev; n->prev = tn2; } @@ -353,7 +384,8 @@ void mowgli_list_reverse(mowgli_list_t *l) } /* sorts a list -- O(n ^ 2) most likely, i don't want to think about it. --nenolod */ -void mowgli_list_sort(mowgli_list_t *l, mowgli_list_comparator_t comp, void *opaque) +void +mowgli_list_sort(mowgli_list_t *l, mowgli_list_comparator_t comp, void *opaque) { mowgli_node_t *n, *tn, *n2, *tn2; @@ -374,13 +406,15 @@ void mowgli_list_sort(mowgli_list_t *l, mowgli_list_comparator_t comp, void *opa i2 = mowgli_node_index(n2, l); if ((result = comp(n, n2, opaque)) == 0) + { continue; - else if (result < 0 && i > i2) + } + else if ((result < 0) && (i > i2)) { mowgli_node_delete(n, l); mowgli_node_add_before(n->data, n, l, n2); } - else if (result > 0 && i < i2) + else if ((result > 0) && (i < i2)) { mowgli_node_delete(n, l); mowgli_node_add_after(n->data, n, l, n2); diff --git a/src/libmowgli/container/list.h b/src/libmowgli/container/list.h index 19905b4..338e51c 100644 --- a/src/libmowgli/container/list.h +++ b/src/libmowgli/container/list.h @@ -25,13 +25,17 @@ #define __MOWGLI_LIST_H__ /* macros for linked lists */ -#define MOWGLI_LIST_FOREACH(n, head) for (n = (head); n; n = n->next) -#define MOWGLI_LIST_FOREACH_NEXT(n, head) for (n = (head); n->next; n = n->next) -#define MOWGLI_LIST_FOREACH_PREV(n, tail) for (n = (tail); n; n = n->prev) +#define MOWGLI_LIST_FOREACH(n, head) \ + for (n = (head); n; n = n->next) +#define MOWGLI_LIST_FOREACH_NEXT(n, head) \ + for (n = (head); n->next; n = n->next) +#define MOWGLI_LIST_FOREACH_PREV(n, tail) \ + for (n = (tail); n; n = n->prev) #define MOWGLI_LIST_LENGTH(list) (list)->count -#define MOWGLI_LIST_FOREACH_SAFE(n, tn, head) for (n = (head), tn = n ? n->next : NULL; n != NULL; n = tn, tn = n ? n->next : NULL) +#define MOWGLI_LIST_FOREACH_SAFE(n, tn, head) \ + for (n = (head), tn = n ? n->next : NULL; n != NULL; n = tn, tn = n ? n->next : NULL) /* list node struct */ typedef struct mowgli_node_ mowgli_node_t; @@ -39,18 +43,18 @@ typedef struct mowgli_list_ mowgli_list_t; struct mowgli_node_ { - struct mowgli_node_ *next, *prev; - void *data; /* pointer to real structure */ + struct mowgli_node_ *next, *prev; + + void *data; /* pointer to real structure */ }; /* node list struct */ struct mowgli_list_ { mowgli_node_t *head, *tail; - size_t count; /* how many entries in the list */ + size_t count; /* how many entries in the list */ }; -extern void mowgli_node_bootstrap(void); extern mowgli_node_t *mowgli_node_create(void); extern void mowgli_node_free(mowgli_node_t *n); extern void mowgli_node_add(void *data, mowgli_node_t *n, mowgli_list_t *l); diff --git a/src/libmowgli/container/patricia.c b/src/libmowgli/container/patricia.c index b530d33..5d5ec3d 100644 --- a/src/libmowgli/container/patricia.c +++ b/src/libmowgli/container/patricia.c @@ -57,6 +57,7 @@ struct mowgli_patricia_ { void (*canonize_cb)(char *key); union patricia_elem *root; + unsigned int count; char *id; }; @@ -68,9 +69,12 @@ struct patricia_node { /* nibble to test (nibble NUM%2 of byte NUM/2) */ int nibnum; + /* branches of the tree */ union patricia_elem *down[POINTERS_PER_NODE]; + union patricia_elem *parent; + char parent_val; }; @@ -82,11 +86,14 @@ struct patricia_leaf { /* -1 to indicate this is a leaf, not a node */ int nibnum; + /* data associated with the key */ void *data; + /* key (canonized copy) */ char *key; union patricia_elem *parent; + char parent_val; }; @@ -94,6 +101,7 @@ union patricia_elem { int nibnum; struct patricia_node node; + struct patricia_leaf leaf; }; @@ -117,21 +125,21 @@ union patricia_elem * Side Effects: * - none */ -static union patricia_elem *first_leaf(union patricia_elem *delem) +static union patricia_elem * +first_leaf(union patricia_elem *delem) { int val; while (!IS_LEAF(delem)) { for (val = 0; val < POINTERS_PER_NODE; val++) - { if (delem->node.down[val] != NULL) { delem = delem->node.down[val]; break; } - } } + return delem; } @@ -152,7 +160,8 @@ static union patricia_elem *first_leaf(union patricia_elem *delem) * - if services runs out of memory and cannot allocate the object, * the program will abort. */ -mowgli_patricia_t *mowgli_patricia_create(void (*canonize_cb)(char *key)) +mowgli_patricia_t * +mowgli_patricia_create(void (*canonize_cb)(char *key)) { mowgli_patricia_t *dtree = (mowgli_patricia_t *) mowgli_alloc(sizeof(mowgli_patricia_t)); @@ -160,6 +169,7 @@ mowgli_patricia_t *mowgli_patricia_create(void (*canonize_cb)(char *key)) if (!leaf_heap) leaf_heap = mowgli_heap_create(sizeof(struct patricia_leaf), 1024, BH_NOW); + if (!node_heap) node_heap = mowgli_heap_create(sizeof(struct patricia_node), 128, BH_NOW); @@ -187,8 +197,8 @@ mowgli_patricia_t *mowgli_patricia_create(void (*canonize_cb)(char *key)) * - if services runs out of memory and cannot allocate the object, * the program will abort. */ -mowgli_patricia_t *mowgli_patricia_create_named(const char *name, - void (*canonize_cb)(char *key)) +mowgli_patricia_t * +mowgli_patricia_create_named(const char *name, void (*canonize_cb)(char *key)) { mowgli_patricia_t *dtree = (mowgli_patricia_t *) mowgli_alloc(sizeof(mowgli_patricia_t)); @@ -197,6 +207,7 @@ mowgli_patricia_t *mowgli_patricia_create_named(const char *name, if (!leaf_heap) leaf_heap = mowgli_heap_create(sizeof(struct patricia_leaf), 1024, BH_NOW); + if (!node_heap) node_heap = mowgli_heap_create(sizeof(struct patricia_node), 128, BH_NOW); @@ -220,11 +231,13 @@ mowgli_patricia_t *mowgli_patricia_create_named(const char *name, * Side Effects: * - patricia's internal heaps are destroyed and deallocated */ -void mowgli_patricia_shutdown(void) +void +mowgli_patricia_shutdown(void) { - if(leaf_heap) + if (leaf_heap) mowgli_heap_destroy(leaf_heap); - if(node_heap) + + if (node_heap) mowgli_heap_destroy(node_heap); return; @@ -252,12 +265,12 @@ void mowgli_patricia_shutdown(void) * - if this is called without a callback, the objects bound to the * DTree will not be destroyed. */ -void mowgli_patricia_destroy(mowgli_patricia_t *dtree, - void (*destroy_cb)(const char *key, void *data, void *privdata), - void *privdata) +void +mowgli_patricia_destroy(mowgli_patricia_t *dtree, void (*destroy_cb)(const char *key, void *data, void *privdata), void *privdata) { mowgli_patricia_iteration_state_t state; union patricia_elem *delem; + void *entry; return_if_fail(dtree != NULL); @@ -265,9 +278,11 @@ void mowgli_patricia_destroy(mowgli_patricia_t *dtree, MOWGLI_PATRICIA_FOREACH(entry, &state, dtree) { delem = STATE_CUR(&state); + if (destroy_cb != NULL) (*destroy_cb)(delem->leaf.key, delem->leaf.data, - privdata); + privdata); + mowgli_patricia_delete(dtree, delem->leaf.key); } @@ -292,31 +307,37 @@ void mowgli_patricia_destroy(mowgli_patricia_t *dtree, * Side Effects: * - on success, a dtree is iterated */ -void mowgli_patricia_foreach(mowgli_patricia_t *dtree, - int (*foreach_cb)(const char *key, void *data, void *privdata), - void *privdata) +void +mowgli_patricia_foreach(mowgli_patricia_t *dtree, int (*foreach_cb)(const char *key, void *data, void *privdata), void *privdata) { union patricia_elem *delem, *next; + int val; return_if_fail(dtree != NULL); delem = dtree->root; + if (delem == NULL) return; + /* Only one element in the tree */ if (IS_LEAF(delem)) { if (foreach_cb != NULL) (*foreach_cb)(delem->leaf.key, delem->leaf.data, privdata); + return; } + val = 0; + do { do next = delem->node.down[val++]; while (next == NULL && val < POINTERS_PER_NODE); + if (next != NULL) { if (IS_LEAF(next)) @@ -330,12 +351,15 @@ void mowgli_patricia_foreach(mowgli_patricia_t *dtree, val = 0; } } + while (val >= POINTERS_PER_NODE) { val = delem->node.parent_val; delem = delem->node.parent; + if (delem == NULL) break; + val++; } } while (delem != NULL); @@ -360,38 +384,45 @@ void mowgli_patricia_foreach(mowgli_patricia_t *dtree, * Side Effects: * - a dtree is iterated until the requested conditions are met */ -void *mowgli_patricia_search(mowgli_patricia_t *dtree, - void *(*foreach_cb)(const char *key, void *data, void *privdata), - void *privdata) +void * +mowgli_patricia_search(mowgli_patricia_t *dtree, void *(*foreach_cb)(const char *key, void *data, void *privdata), void *privdata) { union patricia_elem *delem, *next; + int val; void *ret = NULL; return_val_if_fail(dtree != NULL, NULL); delem = dtree->root; + if (delem == NULL) return NULL; + /* Only one element in the tree */ if (IS_LEAF(delem)) { if (foreach_cb != NULL) return (*foreach_cb)(delem->leaf.key, delem->leaf.data, privdata); + return NULL; } + val = 0; + for (;;) { do next = delem->node.down[val++]; while (next == NULL && val < POINTERS_PER_NODE); + if (next != NULL) { if (IS_LEAF(next)) { if (foreach_cb != NULL) ret = (*foreach_cb)(next->leaf.key, next->leaf.data, privdata); + if (ret != NULL) break; } @@ -401,15 +432,19 @@ void *mowgli_patricia_search(mowgli_patricia_t *dtree, val = 0; } } + while (val >= POINTERS_PER_NODE) { val = delem->node.parent_val; delem = delem->node.parent; + if (delem == NULL) break; + val++; } } + return ret; } @@ -429,8 +464,8 @@ void *mowgli_patricia_search(mowgli_patricia_t *dtree, * Side Effects: * - the static iterator, &state, is initialized. */ -void mowgli_patricia_foreach_start(mowgli_patricia_t *dtree, - mowgli_patricia_iteration_state_t *state) +void +mowgli_patricia_foreach_start(mowgli_patricia_t *dtree, mowgli_patricia_iteration_state_t *state) { if (dtree == NULL) return; @@ -441,6 +476,7 @@ void mowgli_patricia_foreach_start(mowgli_patricia_t *dtree, STATE_NEXT(state) = first_leaf(dtree->root); else STATE_NEXT(state) = NULL; + STATE_CUR(state) = STATE_NEXT(state); if (STATE_NEXT(state) == NULL) @@ -468,8 +504,8 @@ void mowgli_patricia_foreach_start(mowgli_patricia_t *dtree, * Side Effects: * - none */ -void *mowgli_patricia_foreach_cur(mowgli_patricia_t *dtree, - mowgli_patricia_iteration_state_t *state) +void * +mowgli_patricia_foreach_cur(mowgli_patricia_t *dtree, mowgli_patricia_iteration_state_t *state) { if (dtree == NULL) return NULL; @@ -477,7 +513,7 @@ void *mowgli_patricia_foreach_cur(mowgli_patricia_t *dtree, return_val_if_fail(state != NULL, NULL); return STATE_CUR(state) != NULL ? - ((struct patricia_leaf *)STATE_CUR(state))->data : NULL; + ((struct patricia_leaf *) STATE_CUR(state))->data : NULL; } /* @@ -496,11 +532,13 @@ void *mowgli_patricia_foreach_cur(mowgli_patricia_t *dtree, * Side Effects: * - the static iterator, &state, is advanced to a new DTree node. */ -void mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, - mowgli_patricia_iteration_state_t *state) +void +mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, mowgli_patricia_iteration_state_t *state) { struct patricia_leaf *leaf; + union patricia_elem *delem, *next; + int val; if (dtree == NULL) @@ -510,7 +548,7 @@ void mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, if (STATE_CUR(state) == NULL) { - mowgli_log("mowgli_patricia_foreach_next(): called again after iteration finished on dtree<%p>", dtree); + mowgli_log("mowgli_patricia_foreach_next(): called again after iteration finished on dtree<%p>", (void *) dtree); return; } @@ -528,6 +566,7 @@ void mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, do next = delem->node.down[val++]; while (next == NULL && val < POINTERS_PER_NODE); + if (next != NULL) { if (IS_LEAF(next)) @@ -537,10 +576,11 @@ void mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, { if (strcmp(next->leaf.key, leaf->key) < 0) { - mowgli_log("mowgli_patricia_foreach_next(): iteration went backwards (libmowgli bug) on dtree<%p>", dtree); + mowgli_log("mowgli_patricia_foreach_next(): iteration went backwards (libmowgli bug) on dtree<%p>", (void *) dtree); STATE_NEXT(state) = NULL; return; } + STATE_NEXT(state) = next; return; } @@ -551,15 +591,19 @@ void mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, val = 0; } } + while (val >= POINTERS_PER_NODE) { val = delem->node.parent_val; delem = delem->node.parent; + if (delem == NULL) break; + val++; } } + STATE_NEXT(state) = NULL; } @@ -579,12 +623,15 @@ void mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, * Side Effects: * - none */ -struct patricia_leaf *mowgli_patricia_elem_find(mowgli_patricia_t *dict, const char *key) +struct patricia_leaf * +mowgli_patricia_elem_find(mowgli_patricia_t *dict, const char *key) { char ckey_store[256]; + char *ckey_buf = NULL; const char *ckey; union patricia_elem *delem; + int val, keylen; return_val_if_fail(dict != NULL, NULL); @@ -593,7 +640,9 @@ struct patricia_leaf *mowgli_patricia_elem_find(mowgli_patricia_t *dict, const c keylen = strlen(key); if (dict->canonize_cb == NULL) + { ckey = key; + } else { if (keylen >= (int) sizeof(ckey_store)) @@ -611,16 +660,19 @@ struct patricia_leaf *mowgli_patricia_elem_find(mowgli_patricia_t *dict, const c } delem = dict->root; + while (delem != NULL && !IS_LEAF(delem)) { if (delem->nibnum / 2 < keylen) val = NIBBLE_VAL(ckey, delem->nibnum); else val = 0; + delem = delem->node.down[val]; } + /* Now, if the key is in the tree, delem contains it. */ - if (delem != NULL && strcmp(delem->leaf.key, ckey)) + if ((delem != NULL) && strcmp(delem->leaf.key, ckey)) delem = NULL; if (ckey_buf != NULL) @@ -646,11 +698,15 @@ struct patricia_leaf *mowgli_patricia_elem_find(mowgli_patricia_t *dict, const c * Side Effects: * - data is inserted into the DTree. */ -struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const char *key, void *data) +struct patricia_leaf * +mowgli_patricia_elem_add(mowgli_patricia_t *dict, const char *key, void *data) { char *ckey; + union patricia_elem *delem, *prev, *newnode; + union patricia_elem **place1; + int val, keylen; int i, j; @@ -660,39 +716,43 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch keylen = strlen(key); ckey = mowgli_strdup(key); + if (ckey == NULL) { mowgli_log("major WTF: ckey is NULL, not adding node."); return NULL; } + if (dict->canonize_cb != NULL) dict->canonize_cb(ckey); prev = NULL; - val = POINTERS_PER_NODE + 2; /* trap value */ + val = POINTERS_PER_NODE + 2; /* trap value */ delem = dict->root; + while (delem != NULL && !IS_LEAF(delem)) { prev = delem; + if (delem->nibnum / 2 < keylen) val = NIBBLE_VAL(ckey, delem->nibnum); else val = 0; + delem = delem->node.down[val]; } + /* Now, if the key is in the tree, delem contains it. */ - if (delem != NULL && !strcmp(delem->leaf.key, ckey)) + if ((delem != NULL) && !strcmp(delem->leaf.key, ckey)) { mowgli_log("Key is already in dict, ignoring duplicate"); mowgli_free(ckey); return NULL; } - if (delem == NULL && prev != NULL) - { + if ((delem == NULL) && (prev != NULL)) /* Get a leaf to compare with. */ delem = first_leaf(prev); - } if (delem == NULL) { @@ -713,13 +773,15 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch /* Find the first nibble where they differ. */ for (i = 0; NIBBLE_VAL(ckey, i) == NIBBLE_VAL(delem->leaf.key, i); i++) ; + /* Find where to insert the new node. */ while (prev != NULL && prev->nibnum > i) { val = prev->node.parent_val; prev = prev->node.parent; } - if (prev == NULL || prev->nibnum < i) + + if ((prev == NULL) || (prev->nibnum < i)) { /* Insert new node below prev */ newnode = mowgli_heap_alloc(node_heap); @@ -727,11 +789,14 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch newnode->nibnum = i; newnode->node.parent = prev; newnode->node.parent_val = val; + for (j = 0; j < POINTERS_PER_NODE; j++) newnode->node.down[j] = NULL; + if (prev == NULL) { newnode->node.down[NIBBLE_VAL(delem->leaf.key, i)] = dict->root; + if (IS_LEAF(dict->root)) { dict->root->leaf.parent = newnode; @@ -743,11 +808,13 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch dict->root->node.parent = newnode; dict->root->node.parent_val = NIBBLE_VAL(delem->leaf.key, i); } + dict->root = newnode; } else { newnode->node.down[NIBBLE_VAL(delem->leaf.key, i)] = prev->node.down[val]; + if (IS_LEAF(prev->node.down[val])) { prev->node.down[val]->leaf.parent = newnode; @@ -758,6 +825,7 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch prev->node.down[val]->node.parent = newnode; prev->node.down[val]->node.parent_val = NIBBLE_VAL(delem->leaf.key, i); } + prev->node.down[val] = newnode; } } @@ -767,6 +835,7 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch soft_assert(prev->nibnum == i); newnode = prev; } + val = NIBBLE_VAL(ckey, i); place1 = &newnode->node.down[val]; soft_assert(*place1 == NULL); @@ -781,7 +850,8 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch return &(*place1)->leaf; } -mowgli_boolean_t mowgli_patricia_add(mowgli_patricia_t *dict, const char *key, void *data) +mowgli_boolean_t +mowgli_patricia_add(mowgli_patricia_t *dict, const char *key, void *data) { return (mowgli_patricia_elem_add(dict, key, data) != NULL) ? TRUE : FALSE; } @@ -805,12 +875,14 @@ mowgli_boolean_t mowgli_patricia_add(mowgli_patricia_t *dict, const char *key, v * Notes: * - the returned data needs to be mowgli_freed/released manually! */ -void *mowgli_patricia_delete(mowgli_patricia_t *dict, const char *key) +void * +mowgli_patricia_delete(mowgli_patricia_t *dict, const char *key) { void *data; struct patricia_leaf *leaf; leaf = mowgli_patricia_elem_find(dict, key); + if (leaf == NULL) return NULL; @@ -819,15 +891,17 @@ void *mowgli_patricia_delete(mowgli_patricia_t *dict, const char *key) return data; } -void mowgli_patricia_elem_delete(mowgli_patricia_t *dict, struct patricia_leaf *leaf) +void +mowgli_patricia_elem_delete(mowgli_patricia_t *dict, struct patricia_leaf *leaf) { union patricia_elem *delem, *prev, *next; + int val, i, used; return_if_fail(dict != NULL); return_if_fail(leaf != NULL); - delem = (union patricia_elem *)leaf; + delem = (union patricia_elem *) leaf; val = delem->leaf.parent_val; prev = delem->leaf.parent; @@ -843,10 +917,13 @@ void mowgli_patricia_elem_delete(mowgli_patricia_t *dict, struct patricia_leaf * delem = prev; used = -1; + for (i = 0; i < POINTERS_PER_NODE; i++) if (delem->node.down[i] != NULL) used = used == -1 ? i : -2; + soft_assert(used == -2 || used >= 0); + if (used >= 0) { /* Only one pointer in this node, remove it. @@ -856,14 +933,17 @@ void mowgli_patricia_elem_delete(mowgli_patricia_t *dict, struct patricia_leaf * next = delem->node.down[used]; val = delem->node.parent_val; prev = delem->node.parent; + if (prev != NULL) prev->node.down[val] = next; else dict->root = next; + if (IS_LEAF(next)) next->leaf.parent = prev, next->leaf.parent_val = val; else next->node.parent = prev, next->node.parent_val = val; + mowgli_heap_free(node_heap, delem); } } @@ -874,6 +954,7 @@ void mowgli_patricia_elem_delete(mowgli_patricia_t *dict, struct patricia_leaf * } dict->count--; + if (dict->count == 0) { soft_assert(dict->root == NULL); @@ -897,7 +978,8 @@ void mowgli_patricia_elem_delete(mowgli_patricia_t *dict, struct patricia_leaf * * Side Effects: * - none */ -void *mowgli_patricia_retrieve(mowgli_patricia_t *dtree, const char *key) +void * +mowgli_patricia_retrieve(mowgli_patricia_t *dtree, const char *key) { struct patricia_leaf *delem = mowgli_patricia_elem_find(dtree, key); @@ -907,21 +989,24 @@ void *mowgli_patricia_retrieve(mowgli_patricia_t *dtree, const char *key) return NULL; } -const char *mowgli_patricia_elem_get_key(struct patricia_leaf *leaf) +const char * +mowgli_patricia_elem_get_key(struct patricia_leaf *leaf) { return_val_if_fail(leaf != NULL, NULL); return leaf->key; } -void mowgli_patricia_elem_set_data(struct patricia_leaf *leaf, void *data) +void +mowgli_patricia_elem_set_data(struct patricia_leaf *leaf, void *data) { return_if_fail(leaf != NULL); leaf->data = data; } -void *mowgli_patricia_elem_get_data(struct patricia_leaf *leaf) +void * +mowgli_patricia_elem_get_data(struct patricia_leaf *leaf) { return_val_if_fail(leaf != NULL, NULL); @@ -942,7 +1027,8 @@ void *mowgli_patricia_elem_get_data(struct patricia_leaf *leaf) * Side Effects: * - none */ -unsigned int mowgli_patricia_size(mowgli_patricia_t *dict) +unsigned int +mowgli_patricia_size(mowgli_patricia_t *dict) { return_val_if_fail(dict != NULL, 0); @@ -960,25 +1046,28 @@ stats_recurse(union patricia_elem *delem, int depth, int *pmaxdepth) if (depth > *pmaxdepth) *pmaxdepth = depth; + if (depth == 0) { if (IS_LEAF(delem)) - { soft_assert(delem->leaf.parent == NULL); - } + else - { soft_assert(delem->node.parent == NULL); - } } + if (IS_LEAF(delem)) return depth; + for (val = 0; val < POINTERS_PER_NODE; val++) { next = delem->node.down[val]; + if (next == NULL) continue; + result += stats_recurse(next, depth + 1, pmaxdepth); + if (IS_LEAF(next)) { soft_assert(next->leaf.parent == delem); @@ -991,6 +1080,7 @@ stats_recurse(union patricia_elem *delem, int depth, int *pmaxdepth) soft_assert(next->node.nibnum > delem->node.nibnum); } } + return result; } @@ -1010,7 +1100,8 @@ stats_recurse(union patricia_elem *delem, int depth, int *pmaxdepth) * Side Effects: * - callback called with stats text */ -void mowgli_patricia_stats(mowgli_patricia_t *dict, void (*cb)(const char *line, void *privdata), void *privdata) +void +mowgli_patricia_stats(mowgli_patricia_t *dict, void (*cb)(const char *line, void *privdata), void *privdata) { char str[256]; int sum, maxdepth; @@ -1019,19 +1110,24 @@ void mowgli_patricia_stats(mowgli_patricia_t *dict, void (*cb)(const char *line, if (dict->id != NULL) snprintf(str, sizeof str, "Dictionary stats for %s (%d)", - dict->id, dict->count); + dict->id, dict->count); else snprintf(str, sizeof str, "Dictionary stats for <%p> (%d)", - dict, dict->count); + (void *) dict, dict->count); + cb(str, privdata); maxdepth = 0; + if (dict->count > 0) { sum = stats_recurse(dict->root, 0, &maxdepth); snprintf(str, sizeof str, "Depth sum %d Avg depth %d Max depth %d", sum, sum / dict->count, maxdepth); } else + { snprintf(str, sizeof str, "Depth sum 0 Avg depth 0 Max depth 0"); + } + cb(str, privdata); return; } diff --git a/src/libmowgli/container/patricia.h b/src/libmowgli/container/patricia.h index 417ba62..a0ab515 100644 --- a/src/libmowgli/container/patricia.h +++ b/src/libmowgli/container/patricia.h @@ -35,8 +35,9 @@ #ifndef __MOWGLI_PATRICIA_H__ #define __MOWGLI_PATRICIA_H__ -struct mowgli_patricia_; /* defined in src/patricia.c */ -struct mowgli_patricia_elem_; /* defined in src/patricia.c */ +struct mowgli_patricia_;/* defined in src/patricia.c */ + +struct mowgli_patricia_elem_; /* defined in src/patricia.c */ typedef struct mowgli_patricia_ mowgli_patricia_t; typedef struct mowgli_patricia_elem_ mowgli_patricia_elem_t; @@ -56,7 +57,8 @@ typedef struct mowgli_patricia_iteration_state_ mowgli_patricia_iteration_state_ /* * this is a convenience macro for inlining iteration of dictionaries. */ -#define MOWGLI_PATRICIA_FOREACH(element, state, dict) for (mowgli_patricia_foreach_start((dict), (state)); (element = mowgli_patricia_foreach_cur((dict), (state))); mowgli_patricia_foreach_next((dict), (state))) +#define MOWGLI_PATRICIA_FOREACH(element, state, dict) \ + for (mowgli_patricia_foreach_start((dict), (state)); (element = mowgli_patricia_foreach_cur((dict), (state))); mowgli_patricia_foreach_next((dict), (state))) /* * mowgli_patricia_create() creates a new patricia tree of the defined resolution. @@ -79,9 +81,7 @@ extern void mowgli_patricia_shutdown(void); * mowgli_patricia_destroy() destroys all entries in a dtree, and also optionally calls * a defined callback function to destroy any data attached to it. */ -extern void mowgli_patricia_destroy(mowgli_patricia_t *dtree, - void (*destroy_cb)(const char *key, void *data, void *privdata), - void *privdata); +extern void mowgli_patricia_destroy(mowgli_patricia_t *dtree, void (*destroy_cb)(const char *key, void *data, void *privdata), void *privdata); /* * mowgli_patricia_foreach() iterates all entries in a dtree, and also optionally calls @@ -89,9 +89,7 @@ extern void mowgli_patricia_destroy(mowgli_patricia_t *dtree, * * To shortcircuit iteration, return non-zero from the callback function. */ -extern void mowgli_patricia_foreach(mowgli_patricia_t *dtree, - int (*foreach_cb)(const char *key, void *data, void *privdata), - void *privdata); +extern void mowgli_patricia_foreach(mowgli_patricia_t *dtree, int (*foreach_cb)(const char *key, void *data, void *privdata), void *privdata); /* * mowgli_patricia_search() iterates all entries in a dtree, and also optionally calls @@ -100,9 +98,7 @@ extern void mowgli_patricia_foreach(mowgli_patricia_t *dtree, * When the object is found, a non-NULL is returned from the callback, which results * in that object being returned to the user. */ -extern void *mowgli_patricia_search(mowgli_patricia_t *dtree, - void *(*foreach_cb)(const char *key, void *data, void *privdata), - void *privdata); +extern void *mowgli_patricia_search(mowgli_patricia_t *dtree, void *(*foreach_cb)(const char *key, void *data, void *privdata), void *privdata); /* * mowgli_patricia_foreach_start() begins an iteration over all items @@ -110,21 +106,18 @@ extern void *mowgli_patricia_search(mowgli_patricia_t *dtree, * in progress at a time, it is permitted to remove the current element * of the iteration (but not any other element). */ -extern void mowgli_patricia_foreach_start(mowgli_patricia_t *dtree, - mowgli_patricia_iteration_state_t *state); +extern void mowgli_patricia_foreach_start(mowgli_patricia_t *dtree, mowgli_patricia_iteration_state_t *state); /* * mowgli_patricia_foreach_cur() returns the current element of the iteration, * or NULL if there are no more elements. */ -extern void *mowgli_patricia_foreach_cur(mowgli_patricia_t *dtree, - mowgli_patricia_iteration_state_t *state); +extern void *mowgli_patricia_foreach_cur(mowgli_patricia_t *dtree, mowgli_patricia_iteration_state_t *state); /* * mowgli_patricia_foreach_next() moves to the next element. */ -extern void mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, - mowgli_patricia_iteration_state_t *state); +extern void mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, mowgli_patricia_iteration_state_t *state); /* * mowgli_patricia_add() adds a key->value entry to the patricia tree. diff --git a/src/libmowgli/container/queue.c b/src/libmowgli/container/queue.c index 39150d3..a321d6b 100644 --- a/src/libmowgli/container/queue.c +++ b/src/libmowgli/container/queue.c @@ -139,7 +139,8 @@ mowgli_queue_skip(mowgli_queue_t *head, int nodes) return_val_if_fail(head != NULL, NULL); - for (iter = 0, n = head; n != NULL && iter < nodes; n = n->next, iter++); + for (iter = 0, n = head; n != NULL && iter < nodes; n = n->next, iter++) + ; return n; } @@ -152,7 +153,8 @@ mowgli_queue_rewind(mowgli_queue_t *head, int nodes) return_val_if_fail(head != NULL, NULL); - for (iter = 0, n = head; n != NULL && iter < nodes; n = n->prev, iter++); + for (iter = 0, n = head; n != NULL && iter < nodes; n = n->prev, iter++) + ; return n; } @@ -164,7 +166,8 @@ mowgli_queue_head(mowgli_queue_t *n) return_val_if_fail(n != NULL, NULL); - for (tn = n; tn != NULL && tn->prev != NULL; tn = tn->prev); + for (tn = n; tn != NULL && tn->prev != NULL; tn = tn->prev) + ; return tn; } @@ -176,7 +179,8 @@ mowgli_queue_tail(mowgli_queue_t *n) return_val_if_fail(n != NULL, NULL); - for (tn = n; tn != NULL && tn->next != NULL; tn = tn->next); + for (tn = n; tn != NULL && tn->next != NULL; tn = tn->next) + ; return tn; } @@ -225,7 +229,8 @@ mowgli_queue_length(mowgli_queue_t *head) return_val_if_fail(head != NULL, -1); - for (n = head, iter = 0; n != NULL; n = n->next, iter++); + for (n = head, iter = 0; n != NULL; n = n->next, iter++) + ; return iter; } diff --git a/src/libmowgli/container/queue.h b/src/libmowgli/container/queue.h index 7f8d995..f16a789 100644 --- a/src/libmowgli/container/queue.h +++ b/src/libmowgli/container/queue.h @@ -26,7 +26,6 @@ typedef mowgli_iterator_t mowgli_queue_t; -extern void mowgli_queue_bootstrap(void); extern mowgli_queue_t *mowgli_queue_push(mowgli_queue_t *head, void *data); extern mowgli_queue_t *mowgli_queue_shift(mowgli_queue_t *head, void *data); extern mowgli_queue_t *mowgli_queue_remove(mowgli_queue_t *head); diff --git a/src/libmowgli/dns/Makefile b/src/libmowgli/dns/Makefile index 06fb36c..5a1c8ba 100644 --- a/src/libmowgli/dns/Makefile +++ b/src/libmowgli/dns/Makefile @@ -4,13 +4,13 @@ STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_DNS} STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_DNS} SRCS = dns.c \ - dns_evloop_res.c \ - dns_evloop_reslib.c \ - dns_evloop_reslist_win32.c + evloop_res.c \ + evloop_reslib.c \ + evloop_reslist_win32.c INCLUDES = dns.h \ - dns_evloop_res.h \ - dns_evloop_reslib.h + evloop_res.h \ + evloop_reslib.h include ../../../buildsys.mk diff --git a/src/libmowgli/dns/dns.c b/src/libmowgli/dns/dns.c index eff5080..f12eea1 100644 --- a/src/libmowgli/dns/dns.c +++ b/src/libmowgli/dns/dns.c @@ -18,9 +18,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "dns.h" +#include "mowgli.h" -mowgli_dns_t * mowgli_dns_create(mowgli_eventloop_t *eventloop, int implementation) +mowgli_dns_t * +mowgli_dns_create(mowgli_eventloop_t *eventloop, int implementation) { mowgli_dns_t *dns = mowgli_alloc(sizeof(mowgli_dns_t)); const mowgli_dns_ops_t *ops; @@ -44,7 +45,8 @@ mowgli_dns_t * mowgli_dns_create(mowgli_eventloop_t *eventloop, int implementati return dns; } -int mowgli_dns_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop, const mowgli_dns_ops_t *ops) +int +mowgli_dns_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop, const mowgli_dns_ops_t *ops) { return_val_if_fail(dns != NULL, -1); @@ -53,30 +55,34 @@ int mowgli_dns_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop, const mowg return dns->dns_ops->mowgli_dns_init_func_t(dns, eventloop); } -void mowgli_dns_destroy(mowgli_dns_t *dns) +void +mowgli_dns_destroy(mowgli_dns_t *dns) { dns->dns_ops->mowgli_dns_fini_func_t(dns); mowgli_free(dns); } -int mowgli_dns_restart(mowgli_dns_t *dns) +int +mowgli_dns_restart(mowgli_dns_t *dns) { return dns->dns_ops->mowgli_dns_restart_func_t(dns); } -void mowgli_dns_delete_query(mowgli_dns_t *dns, const mowgli_dns_query_t *query) +void +mowgli_dns_delete_query(mowgli_dns_t *dns, const mowgli_dns_query_t *query) { dns->dns_ops->mowgli_dns_delete_query_func_t(dns, query); } -void mowgli_dns_gethost_byname(mowgli_dns_t *dns, const char *name, mowgli_dns_query_t *query, int type) +void +mowgli_dns_gethost_byname(mowgli_dns_t *dns, const char *name, mowgli_dns_query_t *query, int type) { dns->dns_ops->mowgli_dns_gethost_byname_func_t(dns, name, query, type); } -void mowgli_dns_gethost_byaddr(mowgli_dns_t *dns, const struct sockaddr_storage *addr, mowgli_dns_query_t *query) +void +mowgli_dns_gethost_byaddr(mowgli_dns_t *dns, const struct sockaddr_storage *addr, mowgli_dns_query_t *query) { dns->dns_ops->mowgli_dns_gethost_byaddr_func_t(dns, addr, query); } - diff --git a/src/libmowgli/dns/dns.h b/src/libmowgli/dns/dns.h index 9cbb6ee..9e097dd 100644 --- a/src/libmowgli/dns/dns.h +++ b/src/libmowgli/dns/dns.h @@ -21,15 +21,13 @@ #ifndef __MOWGLI_DNS_DNS_H__ #define __MOWGLI_DNS_DNS_H__ -#include "mowgli.h" - /* Longest hostname we're willing to work with */ #define MOWGLI_DNS_RES_HOSTLEN 512 /* Resolver types */ -#define MOWGLI_DNS_TYPE_CUSTOM 0 -#define MOWGLI_DNS_TYPE_ASYNC 1 -#define MOWGLI_DNS_TYPE_HELPER 2 +#define MOWGLI_DNS_TYPE_CUSTOM 0 +#define MOWGLI_DNS_TYPE_ASYNC 1 +#define MOWGLI_DNS_TYPE_HELPER 2 /* Lookup types */ #define MOWGLI_DNS_T_A 1 @@ -76,11 +74,11 @@ struct _mowgli_dns_t struct _mowgli_dns_query_t { - void *ptr; /* pointer used by callback to identify request */ - void (*callback) (mowgli_dns_reply_t * reply, int result, void *vptr); /* callback to call */ + void *ptr; /* pointer used by callback to identify request */ + void (*callback)(mowgli_dns_reply_t *reply, int result, void *vptr); /* callback to call */ }; -extern mowgli_dns_t * mowgli_dns_create(mowgli_eventloop_t *eventloop, int implementation); +extern mowgli_dns_t *mowgli_dns_create(mowgli_eventloop_t *eventloop, int implementation); extern int mowgli_dns_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop, const mowgli_dns_ops_t *ops); extern void mowgli_dns_destroy(mowgli_dns_t *dns); extern int mowgli_dns_restart(mowgli_dns_t *dns); @@ -89,8 +87,7 @@ extern void mowgli_dns_gethost_byname(mowgli_dns_t *dns, const char *name, mowgl extern void mowgli_dns_gethost_byaddr(mowgli_dns_t *dns, const struct sockaddr_storage *addr, mowgli_dns_query_t *query); /* Pull in headers that depend on these types */ -#include "dns_evloop_res.h" -#include "dns_evloop_reslib.h" +#include "evloop_res.h" +#include "evloop_reslib.h" #endif - diff --git a/src/libmowgli/dns/dns_evloop_res.c b/src/libmowgli/dns/dns_evloop_res.c deleted file mode 100644 index a97daf5..0000000 --- a/src/libmowgli/dns/dns_evloop_res.c +++ /dev/null @@ -1,1017 +0,0 @@ -/* - * A rewrite of Darren Reeds original res.c As there is nothing - * left of Darrens original code, this is now licensed by the hybrid group. - * (Well, some of the function names are the same, and bits of the structs..) - * You can use it where it is useful, free even. Buy us a beer and stuff. - * - * The authors takes no responsibility for any damage or loss - * of property which results from the use of this software. - * - * $Id: res.c 3301 2007-03-28 15:04:06Z jilles $ - * from Hybrid Id: res.c 459 2006-02-12 22:21:37Z db $ - * - * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code, - * added callbacks and reference counting of returned hostents. - * --Bleep (Thomas Helvey ) - * - * This was all needlessly complicated for irc. Simplified. No more hostent - * All we really care about is the IP -> hostname mappings. Thats all. - * - * Apr 28, 2003 --cryogen and Dianora - * - * DNS server flooding lessened, AAAA-or-A lookup removed, ip6.int support - * removed, various robustness fixes - * - * 2006 --jilles and nenolod - * - * Clean up various crap, remove global state. Reindent because two space indent - * is hideous. Also remove ancient assumptions that don't make sense anymore (e.g., - * libmowgli targets C99, which specifies an 8-bit char). Pack all this stuff into - * its own namespace. Also gutted a lot of needless/one-use/few-line functions. - * Jesus, what were they thinking... - * - * 2012 --Elizacat - */ - -#include "mowgli.h" -#include "dns.h" - -#define MOWGLI_DNS_MAXPACKET 1024 /* rfc sez 512 but we expand names so ... */ -#define MOWGLI_DNS_RES_MAXALIASES 35 /* maximum aliases allowed */ -#define MOWGLI_DNS_RES_MAXADDRS 35 /* maximum addresses allowed */ -#define MOWGLI_DNS_AR_TTL 600 /* TTL in seconds for dns cache entries */ - -/* RFC 1104/1105 wasn't very helpful about what these fields should be named, so for now, we'll - just name them this way. we probably should look at what named calls them or something. */ -#define MOWGLI_DNS_TYPE_SIZE (size_t)2 -#define MOWGLI_DNS_CLASS_SIZE (size_t)2 -#define MOWGLI_DNS_TTL_SIZE (size_t)4 -#define MOWGLI_DNS_RDLENGTH_SIZE (size_t)2 -#define MOWGLI_DNS_ANSWER_FIXED_SIZE (MOWGLI_DNS_TYPE_SIZE + MOWGLI_DNS_CLASS_SIZE + MOWGLI_DNS_TTL_SIZE + MOWGLI_DNS_RDLENGTH_SIZE) - -#define MOWGLI_DNS_MAXLINE 128 - -typedef struct -{ - mowgli_node_t node; - int id; - time_t ttl; - char type; - char queryname[MOWGLI_DNS_RES_HOSTLEN + 1]; /* name currently being queried */ - char retries; /* retry counter */ - char sends; /* number of sends (>1 means resent) */ - time_t sentat; - time_t timeout; - unsigned int lastns; /* index of last server sent to */ - struct sockaddr_storage addr; - char *name; - mowgli_dns_query_t *query; /* query callback for this request */ -} mowgli_dns_reslist_t; - -static mowgli_heap_t *reslist_heap = NULL; - -#ifndef _WIN32 -static int parse_resvconf(mowgli_dns_t *dns); -#else -static void parse_windows_resolvers(mowgli_dns_t *dns); -#endif - -static void timeout_resolver(void *arg); -static void add_nameserver(mowgli_dns_t *dns, const char *arg); -static int res_ourserver(mowgli_dns_t *dns, const struct sockaddr_storage *inp); -static void rem_request(mowgli_dns_t *dns, mowgli_dns_reslist_t *request); -static mowgli_dns_reslist_t *make_request(mowgli_dns_t *dns, mowgli_dns_query_t * query); -static void do_query_name(mowgli_dns_t *dns, mowgli_dns_query_t * query, const char *name, mowgli_dns_reslist_t *request, int); -static void do_query_number(mowgli_dns_t *dns, mowgli_dns_query_t * query, const struct sockaddr_storage *, mowgli_dns_reslist_t *request); -static void query_name(mowgli_dns_t *dns, mowgli_dns_reslist_t *request); -static int send_res_msg(mowgli_dns_t *dns, const char *buf, int len, int count); -static void resend_query(mowgli_dns_t *dns, mowgli_dns_reslist_t *request); -static int check_question(mowgli_dns_t *dns, mowgli_dns_reslist_t *request, mowgli_dns_resheader_t * header, char *buf, char *eob); -static int proc_answer(mowgli_dns_t *dns, mowgli_dns_reslist_t *request, mowgli_dns_resheader_t * header, char *, char *); -static mowgli_dns_reslist_t *find_id(mowgli_dns_t *dns, int id); -static mowgli_dns_reply_t *make_dnsreply(mowgli_dns_reslist_t *request); -static void res_readreply(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata); - -/* - * mowgli_dns_evloop_init - do everything we need to read the resolv.conf file - * and initialize the resolver file descriptor if needed - */ -int mowgli_dns_evloop_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop) -{ - int i; - mowgli_dns_evloop_t *state; - - if (dns->dns_state == NULL) - dns->dns_state = mowgli_alloc(sizeof(mowgli_dns_evloop_t)); - - dns->dns_type = MOWGLI_DNS_TYPE_ASYNC; - - if (!reslist_heap) - reslist_heap = mowgli_heap_create(sizeof(mowgli_dns_reslist_t), 512, BH_LAZY); - - state = dns->dns_state; - - state->rand = mowgli_random_create(); - - state->nscount = 0; - -#ifndef _WIN32 - parse_resvconf(dns); -#else - parse_windows_resolvers(dns); -#endif - - if (state->nscount == 0) - { - mowgli_log("couldn't get resolv.conf entries, falling back to localhost resolver"); - add_nameserver(dns, "127.0.0.1"); - } - - for (i = 0; i < state->nscount; i++) - state->timeout_count[i] = 0; - - if (state->vio == NULL) - { - state->vio = mowgli_vio_create(dns); - if (mowgli_vio_socket(state->vio, state->nsaddr_list[0].addr.ss_family, SOCK_DGRAM, 0) != 0) - { - mowgli_log("start_resolver(): unable to open UDP resolver socket: %s", - state->vio->error.string); - return -1; - } - - state->eventloop = eventloop; - mowgli_vio_eventloop_attach(state->vio, state->eventloop); - mowgli_pollable_setselect(state->eventloop, state->vio->io, MOWGLI_EVENTLOOP_IO_READ, res_readreply); - state->timeout_resolver_timer = mowgli_timer_add(state->eventloop, "timeout_resolver", timeout_resolver, dns, 1); - } - - return 0; -} - -/* - * mowgli_dns_evloop_restart - reread resolv.conf, reopen socket - */ -int mowgli_dns_evloop_restart(mowgli_dns_t *dns) -{ - mowgli_dns_evloop_t *state = dns->dns_state; - - mowgli_dns_evloop_destroy(dns); - return mowgli_dns_evloop_init(dns, state->eventloop); -} - -/* mowgli_dns_evloop_destroy - finish us off */ -void mowgli_dns_evloop_destroy(mowgli_dns_t *dns) -{ - mowgli_dns_evloop_t *state = dns->dns_state; - - mowgli_vio_close(state->vio); - mowgli_vio_destroy(state->vio); - - mowgli_timer_destroy(state->eventloop, state->timeout_resolver_timer); - - mowgli_free(state); - dns->dns_state = NULL; -} - -#ifndef _WIN32 - -/* parse_resvconf() inputs - NONE output - -1 if failure 0 if success side effects - fills in - * state->nsaddr_list */ -static int parse_resvconf(mowgli_dns_t *dns) -{ - char *p; - char *opt; - char *arg; - char input[MOWGLI_DNS_MAXLINE]; - FILE *file; - mowgli_dns_evloop_t *state = dns->dns_state; - - /* XXX "/etc/resolv.conf" should be from a define in setup.h perhaps for cygwin support etc. - * this hardcodes it to unix for now -db */ - if ((file = fopen("/etc/resolv.conf", "r")) == NULL) - return -1; - - while (fgets(input, sizeof(input), file) != NULL) - { - /* blow away any newline */ - if ((p = strpbrk(input, "\r\n")) != NULL) - *p = '\0'; - - p = input; - /* skip until something thats not a space is seen */ - while (isspace(*p)) - p++; - /* if at this point, have a '\0' then continue */ - if (*p == '\0') - continue; - - /* Ignore comment lines immediately */ - if (*p == '#' || *p == ';') - continue; - - /* skip until a space is found */ - opt = p; - while (!isspace(*p) && *p != '\0') - p++; - if (*p == '\0') - continue; /* no arguments?.. ignore this line */ - /* blow away the space character */ - *p++ = '\0'; - - /* skip these spaces that are before the argument */ - while (isspace(*p)) - p++; - /* Now arg should be right where p is pointing */ - arg = p; - if ((p = strpbrk(arg, " \t")) != NULL) - *p = '\0'; /* take the first word */ - - if (strcmp(opt, "domain") == 0) - mowgli_strlcpy(state->domain, arg, sizeof(state->domain)); - else if (strcmp(opt, "nameserver") == 0) - add_nameserver(dns, arg); - } - - fclose(file); - return 0; -} - -#else - -extern int mowgli_dns_get_windows_nameservers(char *ret_buf, size_t ret_size); - -static void -parse_windows_resolvers(mowgli_dns_t *dns) -{ - char ns_buf[4096]; - char *server; - - mowgli_dns_get_windows_nameservers(ns_buf, sizeof ns_buf); - - for(server = strtok(ns_buf, ","); server != NULL; server = strtok(NULL, ",")) - add_nameserver(dns, server); -} - -#endif - - -/* add_nameserver() input - either an IPV4 address in dotted quad or an IPV6 address in : format - * output - NONE side effects - entry in state->nsaddr_list is filled in as needed */ -static void add_nameserver(mowgli_dns_t *dns, const char *arg) -{ - struct addrinfo hints, *res; - mowgli_dns_evloop_t *state = dns->dns_state; - -#ifdef DEBUG - mowgli_log("add_nameserver(): %s", arg); -#endif - - /* Done max number of nameservers? */ - if (state->nscount >= MOWGLI_DNS_MAXNS) - { - mowgli_log("Too many nameservers, ignoring %s", arg); - return; - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; - - if (getaddrinfo(arg, "domain", &hints, &res)) - return; - - if (res == NULL) - return; - - memcpy(&state->nsaddr_list[state->nscount].addr, res->ai_addr, res->ai_addrlen); - state->nsaddr_list[state->nscount].addrlen = res->ai_addrlen; - state->nscount++; - freeaddrinfo(res); -} - -/* - * int - * res_ourserver(dns, inp) - * looks up "inp" in state->nsaddr_list[] - * returns: - * 0 : not found - * >0 : found - * author: - * paul vixie, 29may94 - * revised for ircd, cryogen(stu) may03 - * rewritten by Elizacat 25mar12 - */ -static int res_ourserver(mowgli_dns_t *dns, const struct sockaddr_storage * inp) -{ - int ns; - mowgli_dns_evloop_t *state = dns->dns_state; - - for (ns = 0; ns < state->nscount; ns++) - { - const struct sockaddr_storage *srv = &state->nsaddr_list[ns].addr; - - /* could probably just memcmp(srv, inp, srv.ss_len) here but we'll air on the side of - caution - stu */ - switch (srv->ss_family) - { - case AF_INET6: - { - const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)srv; - const struct sockaddr_in6 *v6in = (const struct sockaddr_in6 *)inp; - - if (srv->ss_family == inp->ss_family && v6->sin6_port == v6in->sin6_port) - { - if ((memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr, - sizeof(struct in6_addr)) == 0) || - (memcmp(&v6->sin6_addr.s6_addr, &in6addr_any, - sizeof(struct in6_addr)) == 0)) - { - state->timeout_count[ns] = 0; - return 1; - } - } - break; - } - case AF_INET: - { - const struct sockaddr_in *v4 = (const struct sockaddr_in *)srv; - const struct sockaddr_in *v4in = (const struct sockaddr_in *)inp; - - if (srv->ss_family == inp->ss_family && v4->sin_port == v4in->sin_port) - { - if ((v4->sin_addr.s_addr == INADDR_ANY) - || (v4->sin_addr.s_addr == v4in->sin_addr.s_addr)) - { - state->timeout_count[ns] = 0; - return 1; - } - } - break; - } - default: - break; - } - } - - return 0; -} - -/* - * timeout_query_list - Remove queries from the list which have been - * there too long without being resolved. - */ -static time_t timeout_query_list(mowgli_dns_t *dns, time_t now) -{ - mowgli_node_t *ptr; - mowgli_node_t *next_ptr; - mowgli_dns_reslist_t *request; - time_t next_time = 0; - time_t timeout = 0; - mowgli_dns_evloop_t *state = dns->dns_state; - - MOWGLI_ITER_FOREACH_SAFE(ptr, next_ptr, state->request_list.head) - { - request = ptr->data; - timeout = request->sentat + request->timeout; - - if (now >= timeout) - { - if (--request->retries <= 0) - { - (*request->query->callback) (NULL, MOWGLI_DNS_RES_TIMEOUT, request->query->ptr); - rem_request(dns, request); - continue; - } - else - { - state->timeout_count[request->lastns]++; - request->sentat = now; - request->timeout += request->timeout; - resend_query(dns, request); - } - } - - if ((next_time == 0) || timeout < next_time) - next_time = timeout; - } - - return (next_time > now) ? next_time : (now + MOWGLI_DNS_AR_TTL); -} - -/* - * timeout_resolver - check request list - */ -static void timeout_resolver(void *arg) -{ - mowgli_dns_t *dns = arg; - mowgli_dns_evloop_t *state = dns->dns_state; - time_t next; - - next = timeout_query_list(dns, mowgli_eventloop_get_time(state->eventloop)); - - /* Reschedule */ - mowgli_timer_destroy(state->eventloop, state->timeout_resolver_timer); - mowgli_timer_add(state->eventloop, "timeout_resolver", timeout_resolver, dns, next); -} - - -/* - * mowgli_dns_evloop_add_local_domain - Add the domain to hostname, if it is missing - * (as suggested by eps@TOASTER.SFSU.EDU) - */ -void mowgli_dns_evloop_add_local_domain(mowgli_dns_t *dns, char *hname, size_t size) -{ - mowgli_dns_evloop_t *state = dns->dns_state; - - /* try to fix up unqualified names */ - if (strchr(hname, '.') == NULL) - { - if (state->domain[0]) - { - size_t len = strlen(hname); - - if ((strlen(state->domain) + len + 2) < size) - { - hname[len++] = '.'; - strcpy(hname + len, state->domain); - } - } - } -} - -/* - * rem_request - remove a request from the list. - * This must also free any memory that has been allocated for - * temporary storage of DNS results. - */ -static void rem_request(mowgli_dns_t *dns, mowgli_dns_reslist_t *request) -{ - mowgli_dns_evloop_t *state = dns->dns_state; - - return_if_fail(request != NULL); - - mowgli_node_delete(&request->node, &state->request_list); - mowgli_free(request->name); - mowgli_heap_free(reslist_heap, request); -} - -/* - * make_request - Create a DNS request record for the server. - */ -static mowgli_dns_reslist_t *make_request(mowgli_dns_t *dns, mowgli_dns_query_t * query) -{ - mowgli_dns_reslist_t *request = mowgli_heap_alloc(reslist_heap); - mowgli_dns_evloop_t *state = dns->dns_state; - - request->sentat = mowgli_eventloop_get_time(state->eventloop); - request->retries = 3; - request->timeout = 4; /* start at 4 and exponential inc. */ - request->query = query; - - mowgli_node_add(request, &request->node, &state->request_list); - - return request; -} - -/* - * mowgli_dns_evloop_delete_queries - cleanup outstanding queries - * for which there no longer exist clients or conf lines. - */ -void mowgli_dns_evloop_delete_queries(mowgli_dns_t *dns, const mowgli_dns_query_t * query) -{ - mowgli_node_t *ptr; - mowgli_node_t *next_ptr; - mowgli_dns_reslist_t *request; - mowgli_dns_evloop_t *state = dns->dns_state; - - MOWGLI_ITER_FOREACH_SAFE(ptr, next_ptr, state->request_list.head) - { - if ((request = ptr->data) != NULL) - { - if (query == request->query) - rem_request(dns, request); - } - } -} - -/* - * retryfreq - determine how many queries to wait before resending - * if there have been that many consecutive timeouts - */ -static inline int retryfreq(int timeouts) -{ - int i; - int counter = 1; - const int max_retries = 5; - - for (i = 0; i < (timeouts < max_retries ? timeouts : max_retries); i++) - counter *= 3; - - return counter; -} - -/* - * send_res_msg - sends msg to a nameserver. - * This should reflect /etc/resolv.conf. - * Returns number of nameserver successfully sent to - * or -1 if no successful sends. - */ -static int send_res_msg(mowgli_dns_t *dns, const char *rmsg, int len, int rcount) -{ - int i; - int ns; - mowgli_dns_evloop_t *state = dns->dns_state; - - state->retrycnt++; - /* First try a nameserver that seems to work. Every once in a while, try a possibly broken one - * to check if it is working again. */ - for (i = 0; i < state->nscount; i++) - { - ns = (i + rcount - 1) % state->nscount; - - if (state->timeout_count[ns] && state->retrycnt % retryfreq(state->timeout_count[ns])) - continue; - - if (mowgli_vio_sendto(state->vio, rmsg, len, &state->nsaddr_list[ns]) == len) - return ns; - } - - /* No known working nameservers, try some broken one. */ - for (i = 0; i < state->nscount; i++) - { - ns = (i + rcount - 1) % state->nscount; - if (!state->timeout_count[ns]) - continue; - - if (mowgli_vio_sendto(state->vio, rmsg, len, &state->nsaddr_list[ns]) == len) - return ns; - } - - return -1; -} - -/* - * find_id - find a dns request id (id is determined by dn_mkquery) - */ -static mowgli_dns_reslist_t *find_id(mowgli_dns_t *dns, int id) -{ - mowgli_node_t *ptr; - mowgli_dns_reslist_t *request; - mowgli_dns_evloop_t *state = dns->dns_state; - - MOWGLI_ITER_FOREACH(ptr, state->request_list.head) - { - request = ptr->data; - - if (request->id == id) - return request; - } - - return NULL; -} - -/* - * mowgli_dns_evloop_gethost_byname - get host address from name - * - */ -void mowgli_dns_evloop_gethost_byname(mowgli_dns_t *dns, const char *name, mowgli_dns_query_t * query, int type) -{ - return_if_fail(name != NULL); - - do_query_name(dns, query, name, NULL, type); -} - -/* - * mowgli_dns_evloop_gethost_byaddr - get host name from address - */ -void mowgli_dns_evloop_gethost_byaddr(mowgli_dns_t *dns, const struct sockaddr_storage * addr, mowgli_dns_query_t * query) -{ - return_if_fail(addr != NULL); - - do_query_number(dns, query, addr, NULL); -} - -/* - * do_query_name - nameserver lookup name - */ -static void do_query_name(mowgli_dns_t *dns, mowgli_dns_query_t * query, const char *name, mowgli_dns_reslist_t *request, int type) -{ - char host_name[MOWGLI_DNS_RES_HOSTLEN + 1]; - - mowgli_strlcpy(host_name, name, MOWGLI_DNS_RES_HOSTLEN + 1); - mowgli_dns_evloop_add_local_domain(dns, host_name, MOWGLI_DNS_RES_HOSTLEN); - - if (request == NULL) - { - request = make_request(dns, query); - request->name = mowgli_strdup(host_name); - } - - mowgli_strlcpy(request->queryname, host_name, sizeof(request->queryname)); - request->type = type; - query_name(dns, request); -} - -/* - * do_query_number - Use this to do reverse IP# lookups. - */ -static void do_query_number(mowgli_dns_t *dns, mowgli_dns_query_t * query, const struct sockaddr_storage * addr, - mowgli_dns_reslist_t *request) -{ - const unsigned char *cp; - const size_t size = addr->ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - - if (request == NULL) - { - request = make_request(dns, query); - memcpy(&request->addr, addr, size); - request->name = (char *)mowgli_alloc(MOWGLI_DNS_RES_HOSTLEN + 1); - } - - if (addr->ss_family == AF_INET) - { - const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr; - cp = (const unsigned char *)&v4->sin_addr.s_addr; - - sprintf(request->queryname, "%u.%u.%u.%u.in-addr.arpa", (unsigned int)(cp[3]), - (unsigned int)(cp[2]), (unsigned int)(cp[1]), (unsigned int)(cp[0])); - } - else if (addr->ss_family == AF_INET6) - { - int i; - char *rqptr = request->queryname; - const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr; - cp = (const unsigned char *)&v6->sin6_addr.s6_addr; - - for(i = 15; i >= 0; i--, rqptr += 4) - { - sprintf(rqptr, "%1x.%1x.", - (unsigned int)(cp[i] & 0xf), - (unsigned int)(cp[i] >> 4)); - } - - strcpy(rqptr, ".ip6.arpa"); - } - else - { - mowgli_log("do_query_number() called with invalid sockaddr_storage %d", addr->ss_family); - return; - } - - - request->type = MOWGLI_DNS_T_PTR; - query_name(dns, request); -} - -/* - * query_name - generate a query based on class, type and name. - */ -static void query_name(mowgli_dns_t *dns, mowgli_dns_reslist_t *request) -{ - char buf[MOWGLI_DNS_MAXPACKET]; - int request_len = 0; - int ns; - mowgli_dns_evloop_t *state = dns->dns_state; - - memset(buf, 0, sizeof(buf)); - - if ((request_len = - mowgli_dns_res_mkquery(request->queryname, MOWGLI_DNS_C_IN, request->type, (unsigned char *)buf, - sizeof(buf))) > 0) - { - mowgli_dns_resheader_t *header = (mowgli_dns_resheader_t *) buf; - /* - * generate an unique id - * NOTE: we don't have to worry about converting this to and from - * network byte order, the nameserver does not interpret this value - * and returns it unchanged - */ - do - { - header->id = (header->id + mowgli_random_int(state->rand)) & 0xffff; - } - while (find_id(dns, header->id)); - - request->id = header->id; - ++request->sends; - - ns = send_res_msg(dns, buf, request_len, request->sends); - if (ns != -1) - request->lastns = ns; - } -} - -static void resend_query(mowgli_dns_t *dns, mowgli_dns_reslist_t *request) -{ - switch (request->type) - { - case MOWGLI_DNS_T_PTR: - do_query_number(dns, NULL, &request->addr, request); - break; - case MOWGLI_DNS_T_A: - case MOWGLI_DNS_T_AAAA: - do_query_name(dns, NULL, request->name, request, request->type); - break; - default: - break; - } -} - -/* - * check_question - check if the reply really belongs to the - * name we queried (to guard against late replies from previous - * queries with the same id). - */ -static int check_question(mowgli_dns_t *dns, mowgli_dns_reslist_t *request, mowgli_dns_resheader_t * header, char *buf, char *eob) -{ - char hostbuf[MOWGLI_DNS_RES_HOSTLEN + 1]; /* working buffer */ - unsigned char *current; /* current position in buf */ - int n; /* temp count */ - - current = (unsigned char *)buf + sizeof(mowgli_dns_resheader_t); - - if (header->qdcount != 1) - return 0; - - n = mowgli_dns_dn_expand((unsigned char *)buf, (unsigned char *)eob, current, hostbuf, sizeof(hostbuf)); - - if (n <= 0) - return 0; - - if (strcasecmp(hostbuf, request->queryname)) - return 0; - - return 1; -} - -/* - * proc_answer - process name server reply - */ -static int proc_answer(mowgli_dns_t *dns, mowgli_dns_reslist_t *request, mowgli_dns_resheader_t * header, char *buf, char *eob) -{ - char hostbuf[MOWGLI_DNS_RES_HOSTLEN + 100]; /* working buffer */ - unsigned char *current; /* current position in buf */ - int query_class; /* answer class */ - int type; /* answer type */ - int n; /* temp count */ - int rd_length; - - current = (unsigned char *)buf + sizeof(mowgli_dns_resheader_t); - - for (; header->qdcount > 0; --header->qdcount) - { - if ((n = mowgli_dns_dn_skipname(current, (unsigned char *)eob)) < 0) - return 0; - - current += (size_t) n + MOWGLI_DNS_QFIXEDSIZE; - } - - /* process each answer sent to us. */ - while (header->ancount > 0 && (char *)current < eob) - { - header->ancount--; - - n = mowgli_dns_dn_expand((unsigned char *)buf, (unsigned char *)eob, current, hostbuf, - sizeof(hostbuf)); - - /* Broken message (< 0) or no more answers left (== 0) */ - if (n <= 0) - return 0; - - hostbuf[MOWGLI_DNS_RES_HOSTLEN] = '\0'; - - /* With Address arithmetic you have to be very anal -- this code was not working on alpha due - * to that (spotted by rodder/jailbird/dianora) */ - current += (size_t) n; - - if (!(((char *)current + MOWGLI_DNS_ANSWER_FIXED_SIZE) < eob)) - break; - - type = mowgli_dns_ns_get16(current); - current += MOWGLI_DNS_TYPE_SIZE; - - query_class = mowgli_dns_ns_get16(current); - current += MOWGLI_DNS_CLASS_SIZE; - - /* We may use this later at some point so... eliminate bogus GCC warning */ - (void)query_class; - - request->ttl = mowgli_dns_ns_get32(current); - current += MOWGLI_DNS_TTL_SIZE; - - rd_length = mowgli_dns_ns_get16(current); - current += MOWGLI_DNS_RDLENGTH_SIZE; - - /* Wait to set request->type until we verify this structure */ - switch (type) - { - case MOWGLI_DNS_T_A: - { - struct sockaddr_in *v4; - - if (request->type != MOWGLI_DNS_T_A) - return 0; - - /* check for invalid rd_length or too many addresses */ - if (rd_length != sizeof(struct in_addr)) - return 0; - - v4 = (struct sockaddr_in *)&request->addr; - v4->sin_family = AF_INET; - memcpy(&v4->sin_addr, current, sizeof(struct in_addr)); - - return 1; - } - case MOWGLI_DNS_T_AAAA: - { - struct sockaddr_in6 *v6; - - if (request->type != MOWGLI_DNS_T_AAAA) - return 0; - - if (rd_length != sizeof(struct in6_addr)) - return 0; - - v6 = (struct sockaddr_in6 *)&request->addr; - v6->sin6_family = AF_INET6; - memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr)); - - return 1; - } - case MOWGLI_DNS_T_PTR: - if (request->type != MOWGLI_DNS_T_PTR) - return 0; - - n = mowgli_dns_dn_expand((unsigned char *)buf, (unsigned char *)eob, current, - hostbuf, sizeof(hostbuf)); - - /* Broken message or no more answers left */ - if (n <= 0) - return 0; - - mowgli_strlcpy(request->name, hostbuf, MOWGLI_DNS_RES_HOSTLEN + 1); - - return 1; - case MOWGLI_DNS_T_CNAME: - /* real answer will follow */ - current += rd_length; - break; - default: - /* XXX I'd rather just throw away the entire bogus thing but its possible its just a - * broken nameserver with still valid answers. But lets do some rudimentary logging for - * now... */ - mowgli_log("proc_answer(): bogus type %d", type); - break; - } - } - - return 1; -} - -/* - * res_read_single_reply - read a dns reply from the nameserver and process it. - * Return value: 1 if a packet was read, 0 otherwise - */ -static int res_read_single_reply(mowgli_dns_t *dns) -{ - char buf[sizeof(mowgli_dns_resheader_t) + MOWGLI_DNS_MAXPACKET] - /* Sparc and alpha need 16bit-alignment for accessing header->id (which is uint16_t). - Because of the header = (mowgli_dns_resheader_t*) buf; later on, this is neeeded. --FaUl */ -#if defined(__sparc__) || defined(__alpha__) - __attribute__ ((aligned(16))) -#endif - ; - mowgli_dns_resheader_t *header; - mowgli_dns_reslist_t *request = NULL; - mowgli_dns_reply_t *reply = NULL; - int rc; - int answer_count; - mowgli_vio_sockaddr_t lsin; - mowgli_dns_evloop_t *state = dns->dns_state; - - rc = mowgli_vio_recvfrom(state->vio, buf, sizeof(buf), &lsin); - - /* No packet */ - if (rc == 0 || rc == -1) - return 0; - - /* Too small */ - if (rc <= (int)(sizeof(mowgli_dns_resheader_t))) - return 1; - - /* - * convert DNS reply reader from Network byte order to CPU byte order. - */ - header = (mowgli_dns_resheader_t *) buf; - header->ancount = ntohs(header->ancount); - header->qdcount = ntohs(header->qdcount); - header->nscount = ntohs(header->nscount); - header->arcount = ntohs(header->arcount); - - /* response for an id which we have already received an answer for - * just ignore this response. */ - if ((request = find_id(dns, header->id)) == 0) - return 1; - - /* check against possibly fake replies */ - if (!res_ourserver(dns, &lsin.addr)) - return 1; - - if (!check_question(dns, request, header, buf, buf + rc)) - return 1; - - if ((header->rcode != MOWGLI_DNS_NO_ERRORS) || (header->ancount == 0)) - { - if (header->rcode == MOWGLI_DNS_NXDOMAIN) - { - (*request->query->callback) (NULL, MOWGLI_DNS_RES_NXDOMAIN, request->query->ptr); - rem_request(dns, request); - } - else - { - /* - * If a bad error was returned, we stop here and dont send - * send any more (no retries granted). - */ - (*request->query->callback) (NULL, MOWGLI_DNS_RES_INVALID, request->query->ptr); - rem_request(dns, request); - } - return 1; - } - - /* If this fails there was an error decoding the received packet, - * give up. -- jilles - */ - answer_count = proc_answer(dns, request, header, buf, buf + rc); - - if (answer_count) - { - if (request->type == MOWGLI_DNS_T_PTR) - { - if (request->name == NULL) - { - /* got a PTR response with no name, something bogus is happening - * don't bother trying again, the client address doesn't resolve - */ - (*request->query->callback) (reply, MOWGLI_DNS_RES_INVALID, request->query->ptr); - rem_request(dns, request); - return 1; - } - - /* Lookup the 'authoritative' name that we were given for the - * ip#. */ - if (request->addr.ss_family == AF_INET6) - mowgli_dns_evloop_gethost_byname(dns, request->name, request->query, MOWGLI_DNS_T_AAAA); - else - mowgli_dns_evloop_gethost_byname(dns, request->name, request->query, MOWGLI_DNS_T_A); - rem_request(dns, request); - } - else - { - /* got a name and address response, client resolved */ - reply = make_dnsreply(request); - (*request->query->callback) (reply, MOWGLI_DNS_RES_SUCCESS, request->query->ptr); - mowgli_free(reply); - rem_request(dns, request); - } - } - else - { - /* couldn't decode, give up -- jilles */ - (*request->query->callback) (NULL, MOWGLI_DNS_RES_INVALID, request->query->ptr); - rem_request(dns, request); - } - - return 1; -} - -static mowgli_dns_reply_t *make_dnsreply(mowgli_dns_reslist_t *request) -{ - mowgli_dns_reply_t *cp; - return_val_if_fail(request != 0, NULL); - - cp = (mowgli_dns_reply_t *) mowgli_alloc(sizeof(mowgli_dns_reply_t)); - - cp->h_name = request->name; - memcpy(&cp->addr, &request->addr, sizeof(cp->addr)); - return cp; -} - -static void res_readreply(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) -{ - mowgli_dns_t *dns = userdata; - while (res_read_single_reply(dns)); -} - -/* DNS ops for this resolver */ -const mowgli_dns_ops_t mowgli_dns_evloop_resolver = { - .mowgli_dns_init_func_t = mowgli_dns_evloop_init, - .mowgli_dns_fini_func_t = mowgli_dns_evloop_destroy, - .mowgli_dns_restart_func_t = mowgli_dns_evloop_restart, - .mowgli_dns_delete_query_func_t = mowgli_dns_evloop_delete_queries, - .mowgli_dns_gethost_byname_func_t = mowgli_dns_evloop_gethost_byname, - .mowgli_dns_gethost_byaddr_func_t = mowgli_dns_evloop_gethost_byaddr, -}; - diff --git a/src/libmowgli/dns/dns_evloop_res.h b/src/libmowgli/dns/dns_evloop_res.h deleted file mode 100644 index 3973533..0000000 --- a/src/libmowgli/dns/dns_evloop_res.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * res.h for referencing functions in res.c, reslib.c - * - * Originally from Charybdis (before that, hybrid), but very little of the - * original remains, so... - */ - -#ifndef __MOWGLI_DNS_RES_H__ -#define __MOWGLI_DNS_RES_H__ - -/* Maximum number of nameservers we track */ -#define MOWGLI_DNS_MAXNS 10 - -typedef struct -{ - mowgli_vio_sockaddr_t nsaddr_list[MOWGLI_DNS_MAXNS]; - int nscount; - - int retrycnt; - - int timeout_count[MOWGLI_DNS_MAXNS]; - - mowgli_vio_t *vio; - mowgli_eventloop_t *eventloop; - mowgli_eventloop_timer_t *timeout_resolver_timer; - - mowgli_list_t request_list; - - mowgli_random_t *rand; - - char domain[MOWGLI_DNS_RES_HOSTLEN]; -} mowgli_dns_evloop_t; - -extern int mowgli_dns_evloop_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop); -extern int mowgli_dns_evloop_restart(mowgli_dns_t *dns); -extern void mowgli_dns_evloop_destroy(mowgli_dns_t *dns); -extern void mowgli_dns_evloop_delete_queries(mowgli_dns_t *dns, const mowgli_dns_query_t *); -extern void mowgli_dns_evloop_gethost_byname(mowgli_dns_t *dns, const char *, mowgli_dns_query_t *, int); -extern void mowgli_dns_evloop_gethost_byaddr(mowgli_dns_t *dns, const struct sockaddr_storage *, mowgli_dns_query_t *); -extern void mowgli_dns_evloop_add_local_domain(mowgli_dns_t *dns, char *, size_t); - -extern const mowgli_dns_ops_t mowgli_dns_evloop_resolver; - -#endif diff --git a/src/libmowgli/dns/dns_evloop_reslib.c b/src/libmowgli/dns/dns_evloop_reslib.c deleted file mode 100644 index edefbe7..0000000 --- a/src/libmowgli/dns/dns_evloop_reslib.c +++ /dev/null @@ -1,1102 +0,0 @@ -/* - * Copyright (c) 1985, 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. - */ - -/* - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * - * 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, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION 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. - */ - -/* - * Portions Copyright (c) 1996-1999 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* Original copyright ISC as above. Code modified specifically for ircd use from the following - * orginal files in bind ... res_comp.c ns_name.c ns_netint.c res_init.c - Dianora */ - -#include "dns.h" - -#ifdef _WIN32 -#define EMSGSIZE WSAEMSGSIZE -#endif - -#define MOWGLI_DNS_NS_TYPE_ELT 0x40 /* EDNS0 extended label type */ -#define MOWGLI_DNS_LABELTYPE_BITSTRING 0x41 - -/* from Hybrid Id: reslib.c 177 2005-10-22 09:05:05Z michael $ */ - -static const char digitvalue[256] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 16 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 32 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 48 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 64 */ - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 96 */ - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 112 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 128 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 256 */ -}; - -static const char digits[] = "0123456789"; - -static int labellen(const unsigned char *lp); -static bool mowgli_dns_is_special(int ch); -static bool mowgli_dns_is_printable(int ch); -static int mowgli_dns_decode_bitstring(const char **cpp, char *dn, const char *eom); -static int mowgli_dns_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz, unsigned char **dnptrs, unsigned char **lastdnptr); -static int mowgli_dns_dn_find(const unsigned char *, const unsigned char *, const unsigned char *const *, const unsigned char *const *); -static int mowgli_dns_encode_bitsring(const char **, const char *, unsigned char **, unsigned char **, const char *); -static int mowgli_dns_ns_name_uncompress(const unsigned char *, const unsigned char *, const unsigned char *, char *, size_t); -static int mowgli_dns_ns_name_unpack(const unsigned char *, const unsigned char *, const unsigned char *, unsigned char *, size_t); -static int mowgli_dns_ns_name_ntop(const char *, char *, size_t); -static int mowgli_dns_ns_name_skip(const unsigned char **, const unsigned char *); -static int mowgli_dns_mklower(int ch); - -/* - * Expand compressed domain name 'comp_dn' to full domain name. - * 'rmsg' is a pointer to the begining of the message, - * 'eomorig' points to the first location after the message, - * 'exp_dn' is a pointer to a buffer of size 'length' for the result. - * Return size of compressed name or -1 if there was an error. - */ -int -mowgli_dns_dn_expand(const unsigned char *rmsg, const unsigned char *eom, - const unsigned char *src, char *dst, int dstsiz) -{ - int n = mowgli_dns_ns_name_uncompress(rmsg, eom, src, dst, (size_t) dstsiz); - - if (n > 0 && dst[0] == '.') - dst[0] = '\0'; - return n; -} - -/* - * mowgli_dns_ns_name_uncompress(rmsg, eom, src, dst, dstsiz) - * Expand compressed domain name to presentation format. - * return: - * Number of bytes read out of `src', or -1 (with errno set). - * note: - * Root domain returns as "." not "". - */ -static int -mowgli_dns_ns_name_uncompress(const unsigned char *rmsg, const unsigned char *eom, - const unsigned char *src, char *dst, size_t dstsiz) -{ - unsigned char tmp[MOWGLI_DNS_NS_MAXCDNAME]; - int n; - - if ((n = mowgli_dns_ns_name_unpack(rmsg, eom, src, tmp, sizeof tmp)) == -1) - return -1; - if (mowgli_dns_ns_name_ntop((char *)tmp, dst, dstsiz) == -1) - return -1; - return n; -} - -/* - * mowgli_dns_ns_name_unpack(rmsg, eom, src, dst, dstsiz) - * Unpack a domain name from a message, source may be compressed. - * return: - * -1 if it fails, or consumed octets if it succeeds. - */ -static int -mowgli_dns_ns_name_unpack(const unsigned char *rmsg, const unsigned char *eom, const unsigned char *src, unsigned char *dst, size_t dstsiz) -{ - const unsigned char *srcp, *dstlim; - unsigned char *dstp; - int n, len, checked, l; - - len = -1; - checked = 0; - dstp = dst; - srcp = src; - dstlim = dst + dstsiz; - if (srcp < rmsg || srcp >= eom) - { - errno = EMSGSIZE; - return -1; - } - /* Fetch next label in domain name. */ - while ((n = *srcp++) != 0) - { - /* Check for indirection. */ - switch (n & MOWGLI_DNS_NS_CMPRSFLAGS) - { - case 0: - case MOWGLI_DNS_NS_TYPE_ELT: - /* Limit checks. */ - if ((l = labellen(srcp - 1)) < 0) - { - errno = EMSGSIZE; - return -1; - } - if (dstp + l + 1 >= dstlim || srcp + l >= eom) - { - errno = EMSGSIZE; - return -1; - } - checked += l + 1; - *dstp++ = n; - memcpy(dstp, srcp, l); - dstp += l; - srcp += l; - break; - - case MOWGLI_DNS_NS_CMPRSFLAGS: - if (srcp >= eom) - { - errno = EMSGSIZE; - return -1; - } - if (len < 0) - len = srcp - src + 1; - srcp = rmsg + (((n & 0x3f) << 8) | (*srcp & 0xff)); - if (srcp < rmsg || srcp >= eom) - { /* Out of range. */ - errno = EMSGSIZE; - return -1; - } - checked += 2; - /* - * Check for loops in the compressed name; - * if we've looked at the whole message, - * there must be a loop. - */ - if (checked >= eom - rmsg) - { - errno = EMSGSIZE; - return -1; - } - break; - - default: - errno = EMSGSIZE; - return -1; /* flag error */ - } - } - *dstp = '\0'; - if (len < 0) - len = srcp - src; - return len; -} - -/* - * mowgli_dns_ns_name_ntop(src, dst, dstsiz) - * Convert an encoded domain name to mowgli_dns_is_printable ascii as per RFC1035. - * return: - * Number of bytes written to buffer, or -1 (with errno set) - * notes: - * The root is returned as "." - * All other domains are returned in non absolute form - */ -static int mowgli_dns_ns_name_ntop(const char *src, char *dst, size_t dstsiz) -{ - const char *cp; - char *dn, *eom; - unsigned char c; - unsigned int n; - int l; - - cp = src; - dn = dst; - eom = dst + dstsiz; - - while ((n = *cp++) != 0) - { - if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) - { - /* Some kind of compression pointer. */ - errno = EMSGSIZE; - return -1; - } - if (dn != dst) - { - if (dn >= eom) - { - errno = EMSGSIZE; - return -1; - } - *dn++ = '.'; - } - if ((l = labellen((const unsigned char *)(cp - 1))) < 0) - { - errno = EMSGSIZE; /* XXX */ - return -1; - } - if (dn + l >= eom) - { - errno = EMSGSIZE; - return -1; - } - if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_TYPE_ELT) - { - int m; - - if (n != MOWGLI_DNS_LABELTYPE_BITSTRING) - { - /* XXX: labellen should reject this case */ - errno = EINVAL; - return -1; - } - if ((m = mowgli_dns_decode_bitstring(&cp, dn, eom)) < 0) - { - errno = EMSGSIZE; - return -1; - } - dn += m; - continue; - } - for ((void)NULL; l > 0; l--) - { - c = *cp++; - if (mowgli_dns_is_special(c)) - { - if (dn + 1 >= eom) - { - errno = EMSGSIZE; - return -1; - } - *dn++ = '\\'; - *dn++ = (char)c; - } - else if (!mowgli_dns_is_printable(c)) - { - if (dn + 3 >= eom) - { - errno = EMSGSIZE; - return -1; - } - *dn++ = '\\'; - *dn++ = digits[c / 100]; - *dn++ = digits[(c % 100) / 10]; - *dn++ = digits[c % 10]; - } - else - { - if (dn >= eom) - { - errno = EMSGSIZE; - return -1; - } - *dn++ = (char)c; - } - } - } - if (dn == dst) - { - if (dn >= eom) - { - errno = EMSGSIZE; - return -1; - } - *dn++ = '.'; - } - if (dn >= eom) - { - errno = EMSGSIZE; - return -1; - } - *dn++ = '\0'; - return dn - dst; -} - -/* - * Pack domain name 'exp_dn' in presentation form into 'comp_dn'. - * Return the size of the compressed name or -1. - * 'length' is the size of the array pointed to by 'comp_dn'. - */ -static int -mowgli_dns_dn_comp(const char *src, unsigned char *dst, int dstsiz, - unsigned char **dnptrs, unsigned char **lastdnptr) -{ - return mowgli_dns_ns_name_compress(src, dst, (size_t) dstsiz, dnptrs, lastdnptr); -} - -/* - * Skip over a compressed domain name. Return the size or -1. - */ -int mowgli_dns_dn_skipname(const unsigned char *ptr, const unsigned char *eom) -{ - const unsigned char *saveptr = ptr; - - if (mowgli_dns_ns_name_skip(&ptr, eom) == -1) - return -1; - return ptr - saveptr; -} - -/* - * ns_name_skip(ptrptr, eom) - * Advance *ptrptr to skip over the compressed name it points at. - * return: - * 0 on success, -1 (with errno set) on failure. - */ -static int mowgli_dns_ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom) -{ - const unsigned char *cp; - unsigned int n; - int l; - - cp = *ptrptr; - - while (cp < eom && (n = *cp++) != 0) - { - /* Check for indirection. */ - switch (n & MOWGLI_DNS_NS_CMPRSFLAGS) - { - case 0: /* normal case, n == len */ - cp += n; - continue; - case MOWGLI_DNS_NS_TYPE_ELT: /* EDNS0 extended label */ - if ((l = labellen(cp - 1)) < 0) - { - errno = EMSGSIZE; /* XXX */ - return -1; - } - - cp += l; - continue; - case MOWGLI_DNS_NS_CMPRSFLAGS: /* indirection */ - cp++; - break; - default: /* illegal type */ - errno = EMSGSIZE; - return -1; - } - - break; - } - - if (cp > eom) - { - errno = EMSGSIZE; - return -1; - } - - *ptrptr = cp; - return 0; -} - -unsigned int mowgli_dns_ns_get16(const unsigned char *src) -{ - unsigned int dst; - - MOWGLI_DNS_NS_GET16(dst, src); - return dst; -} - -unsigned long mowgli_dns_ns_get32(const unsigned char *src) -{ - unsigned long dst; - - MOWGLI_DNS_NS_GET32(dst, src); - return dst; -} - -void mowgli_dns_ns_put16(unsigned int src, unsigned char *dst) -{ - MOWGLI_DNS_NS_PUT16(src, dst); -} - -void mowgli_dns_ns_put32(unsigned long src, unsigned char *dst) -{ - MOWGLI_DNS_NS_PUT32(src, dst); -} - -/* From ns_name.c */ - -/* - * mowgli_dns_is_special(ch) - * Thinking in noninternationalized USASCII (per the DNS spec), - * is this characted mowgli_dns_is_special ("in need of quoting") ? - * return: - * boolean. - */ -static bool mowgli_dns_is_special(int ch) -{ - switch (ch) - { - case 0x22: /* '"' */ - case 0x2E: /* '.' */ - case 0x3B: /* ';' */ - case 0x5C: /* '\\' */ - case 0x28: /* '(' */ - case 0x29: /* ')' */ - /* Special modifiers in zone files. */ - case 0x40: /* '@' */ - case 0x24: /* '$' */ - return true; - default: - return false; - } -} - -static int labellen(const unsigned char *lp) -{ - int bitlen; - unsigned char l = *lp; - - if ((l & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) - /* should be avoided by the caller */ - return -1; - - if ((l & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_TYPE_ELT) - { - if (l == MOWGLI_DNS_LABELTYPE_BITSTRING) - { - if ((bitlen = *(lp + 1)) == 0) - bitlen = 256; - - return (bitlen + 7) / 8 + 1; - } - - return -1; /* unknwon ELT */ - } - - return l; -} - - -/* - * mowgli_dns_is_printable(ch) - * Thinking in noninternationalized USASCII (per the DNS spec), - * is this character visible and not a space when printed ? - * return: - * boolean. - */ -static bool mowgli_dns_is_printable(int ch) -{ - return (ch > 0x20 && ch < 0x7f) ? true : false; -} - -static int mowgli_dns_decode_bitstring(const char **cpp, char *dn, const char *eom) -{ - const char *cp = *cpp; - char *beg = dn, tc; - int b, blen, plen; - - if ((blen = (*cp & 0xff)) == 0) - blen = 256; - plen = (blen + 3) / 4; - plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); - if (dn + plen >= eom) - return -1; - - cp++; - dn += sprintf(dn, "\\[x"); - for (b = blen; b > 7; b -= 8, cp++) - dn += sprintf(dn, "%02x", *cp & 0xff); - if (b > 4) - { - tc = *cp++; - dn += sprintf(dn, "%02x", tc & (0xff << (8 - b))); - } - else if (b > 0) - { - tc = *cp++; - dn += sprintf(dn, "%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b))); - } - dn += sprintf(dn, "/%d]", blen); - - *cpp = cp; - return (dn - beg); -} - -/* - * mowgli_dns_ns_name_pton(src, dst, dstsiz) - * Convert a ascii string into an encoded domain name as per RFC1035. - * return: - * -1 if it fails - * 1 if string was fully qualified - * 0 is string was not fully qualified - * notes: - * Enforces label and domain length limits. - */ -static int mowgli_dns_ns_name_pton(const char *src, unsigned char *dst, size_t dstsiz) -{ - unsigned char *label, *bp, *eom; - char *cp; - int c, n, escaped, e = 0; - - escaped = 0; - bp = dst; - eom = dst + dstsiz; - label = bp++; - - - while ((c = *src++) != 0) - { - if (escaped) - { - if (c == '[') - { /* start a bit string label */ - if ((cp = strchr(src, ']')) == NULL) - { - errno = EINVAL; /* ??? */ - return -1; - } - if ((e = mowgli_dns_encode_bitsring(&src, cp + 2, &label, &bp, (const char *)eom)) != 0) - { - errno = e; - return -1; - } - escaped = 0; - label = bp++; - if ((c = *src++) == 0) - goto done; - else if (c != '.') - { - errno = EINVAL; - return -1; - } - continue; - } - else if ((cp = strchr(digits, c)) != NULL) - { - n = (cp - digits) * 100; - if ((c = *src++) == 0 || (cp = strchr(digits, c)) == NULL) - { - errno = EMSGSIZE; - return -1; - } - n += (cp - digits) * 10; - if ((c = *src++) == 0 || (cp = strchr(digits, c)) == NULL) - { - errno = EMSGSIZE; - return -1; - } - n += (cp - digits); - if (n > 255) - { - errno = EMSGSIZE; - return -1; - } - c = n; - } - escaped = 0; - } - else if (c == '\\') - { - escaped = 1; - continue; - } - else if (c == '.') - { - c = (bp - label - 1); - if ((c & MOWGLI_DNS_NS_CMPRSFLAGS) != 0) - { /* Label too big. */ - errno = EMSGSIZE; - return -1; - } - if (label >= eom) - { - errno = EMSGSIZE; - return -1; - } - *label = c; - /* Fully qualified ? */ - if (*src == '\0') - { - if (c != 0) - { - if (bp >= eom) - { - errno = EMSGSIZE; - return -1; - } - *bp++ = '\0'; - } - if ((bp - dst) > MOWGLI_DNS_NS_MAXCDNAME) - { - errno = EMSGSIZE; - return -1; - } - return (1); - } - if (c == 0 || *src == '.') - { - errno = EMSGSIZE; - return -1; - } - label = bp++; - continue; - } - if (bp >= eom) - { - errno = EMSGSIZE; - return -1; - } - *bp++ = (unsigned char)c; - } - c = (bp - label - 1); - if ((c & MOWGLI_DNS_NS_CMPRSFLAGS) != 0) - { /* Label too big. */ - errno = EMSGSIZE; - return -1; - } - done: - if (label >= eom) - { - errno = EMSGSIZE; - return -1; - } - *label = c; - if (c != 0) - { - if (bp >= eom) - { - errno = EMSGSIZE; - return -1; - } - *bp++ = 0; - } - - if ((bp - dst) > MOWGLI_DNS_NS_MAXCDNAME) - { /* src too big */ - errno = EMSGSIZE; - return -1; - } - - return 0; -} - -/* - * mowgli_dns_ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) - * Pack domain name 'domain' into 'comp_dn'. - * return: - * Size of the compressed name, or -1. - * notes: - * 'dnptrs' is an array of pointers to previous compressed names. - * dnptrs[0] is a pointer to the beginning of the message. The array - * ends with NULL. - * 'lastdnptr' is a pointer to the end of the array pointed to - * by 'dnptrs'. - * Side effects: - * The list of pointers in dnptrs is updated for labels inserted into - * the message as we compress the name. If 'dnptr' is NULL, we don't - * try to compress names. If 'lastdnptr' is NULL, we don't update the - * list. - */ -static int -mowgli_dns_ns_name_pack(const unsigned char *src, unsigned char *dst, int dstsiz, - unsigned char **dnptrs, unsigned char **lastdnptr) -{ - unsigned char *dstp; - unsigned char **cpp, **lpp; - const unsigned char *eob, *rmsg; - const unsigned char *srcp; - int n, l, first = 1; - - srcp = src; - dstp = dst; - eob = dstp + dstsiz; - lpp = cpp = NULL; - if (dnptrs != NULL) - { - if ((rmsg = *dnptrs++) != NULL) - { - for (cpp = dnptrs; *cpp != NULL; cpp++) - (void)NULL; - lpp = cpp; /* end of list to search */ - } - } - else - rmsg = NULL; - - /* make sure the domain we are about to add is legal */ - l = 0; - do - { - int l0; - - n = *srcp; - if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) - { - errno = EMSGSIZE; - return -1; - } - if ((l0 = labellen(srcp)) < 0) - { - errno = EINVAL; - return -1; - } - l += l0 + 1; - if (l > MOWGLI_DNS_NS_MAXCDNAME) - { - errno = EMSGSIZE; - return -1; - } - srcp += l0 + 1; - } - while (n != 0); - - /* from here on we need to reset compression pointer array on error */ - srcp = src; - do - { - /* Look to see if we can use pointers. */ - n = *srcp; - if (n != 0 && rmsg != NULL) - { - l = mowgli_dns_dn_find(srcp, rmsg, (const unsigned char *const *)dnptrs, - (const unsigned char *const *)lpp); - if (l >= 0) - { - if (dstp + 1 >= eob) - { - goto cleanup; - } - *dstp++ = (l >> 8) | MOWGLI_DNS_NS_CMPRSFLAGS; - *dstp++ = l % 256; - return (dstp - dst); - } - /* Not found, save it. */ - if (lastdnptr != NULL && cpp < lastdnptr - 1 && (dstp - rmsg) < 0x4000 && first) - { - *cpp++ = dstp; - *cpp = NULL; - first = 0; - } - } - /* copy label to buffer */ - if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) - { - /* Should not happen. */ - goto cleanup; - } - n = labellen(srcp); - if (dstp + 1 + n >= eob) - { - goto cleanup; - } - memcpy(dstp, srcp, n + 1); - srcp += n + 1; - dstp += n + 1; - } - while (n != 0); - - if (dstp > eob) - { - cleanup: - if (rmsg != NULL) - *lpp = NULL; - errno = EMSGSIZE; - return -1; - } - return (dstp - dst); -} - -static int -mowgli_dns_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz, - unsigned char **dnptrs, unsigned char **lastdnptr) -{ - unsigned char tmp[MOWGLI_DNS_NS_MAXCDNAME]; - - if (mowgli_dns_ns_name_pton(src, tmp, sizeof tmp) == -1) - return -1; - return (mowgli_dns_ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); -} - -static int -mowgli_dns_encode_bitsring(const char **bp, const char *end, unsigned char **labelp, - unsigned char **dst, const char *eom) -{ - int afterslash = 0; - const char *cp = *bp; - char *tp, c; - const char *beg_blen; - char *end_blen = NULL; - int value = 0, count = 0, tbcount = 0, blen = 0; - - beg_blen = end_blen = NULL; - - /* a bitstring must contain at least 2 characters */ - if (end - cp < 2) - return EINVAL; - - /* XXX: currently, only hex strings are supported */ - if (*cp++ != 'x') - return EINVAL; - if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */ - return EINVAL; - - for (tp = (char *)(dst + 1); cp < end && tp < eom; cp++) - { - switch ((c = *cp)) - { - case ']': /* end of the bitstring */ - if (afterslash) - { - if (beg_blen == NULL) - return EINVAL; - blen = (int)strtol(beg_blen, &end_blen, 10); - if (*end_blen != ']') - return EINVAL; - } - if (count) - *tp++ = ((value << 4) & 0xff); - cp++; /* skip ']' */ - goto done; - case '/': - afterslash = 1; - break; - default: - if (afterslash) - { - if (!isdigit(c & 0xff)) - return EINVAL; - if (beg_blen == NULL) - { - - if (c == '0') - { - /* blen never begings with 0 */ - return EINVAL; - } - beg_blen = cp; - } - } - else - { - if (!isxdigit(c & 0xff)) - return EINVAL; - value <<= 4; - value += digitvalue[(int)c]; - count += 4; - tbcount += 4; - if (tbcount > 256) - return EINVAL; - if (count == 8) - { - *tp++ = value; - count = 0; - } - } - break; - } - } - done: - if (cp >= end || tp >= eom) - return (EMSGSIZE); - - /* - * bit length validation: - * If a is present, the number of digits in the - * MUST be just sufficient to contain the number of bits specified - * by the . If there are insignificant bits in a final - * hexadecimal or octal digit, they MUST be zero. - * RFC 2673, Section 3.2. - */ - if (blen > 0) - { - int traillen; - - if (((blen + 3) & ~3) != tbcount) - return EINVAL; - traillen = tbcount - blen; /* between 0 and 3 */ - if (((value << (8 - traillen)) & 0xff) != 0) - return EINVAL; - } - else - blen = tbcount; - if (blen == 256) - blen = 0; - - /* encode the type and the significant bit fields */ - **labelp = MOWGLI_DNS_LABELTYPE_BITSTRING; - **dst = blen; - - *bp = cp; - *dst = (unsigned char *)tp; - - return 0; -} - -/* - * dn_find(domain, rmsg, dnptrs, lastdnptr) - * Search for the counted-label name in an array of compressed names. - * return: - * offset from rmsg if found, or -1. - * notes: - * dnptrs is the pointer to the first name on the list, - * not the pointer to the start of the message. - */ -static int -mowgli_dns_dn_find(const unsigned char *domain, const unsigned char *rmsg, - const unsigned char *const *dnptrs, const unsigned char *const *lastdnptr) -{ - const unsigned char *dn, *cp, *sp; - const unsigned char *const *cpp; - unsigned int n; - - for (cpp = dnptrs; cpp < lastdnptr; cpp++) - { - sp = *cpp; - /* - * terminate search on: - * root label - * compression pointer - * unusable offset - */ - while (*sp != 0 && (*sp & MOWGLI_DNS_NS_CMPRSFLAGS) == 0 && (sp - rmsg) < 0x4000) - { - dn = domain; - cp = sp; - while ((n = *cp++) != 0) - { - /* - * check for indirection - */ - switch (n & MOWGLI_DNS_NS_CMPRSFLAGS) - { - case 0: /* normal case, n == len */ - n = labellen(cp - 1); /* XXX */ - - if (n != *dn++) - goto next; - - for ( ; n > 0; n--) - if (mowgli_dns_mklower(*dn++) != mowgli_dns_mklower(*cp++)) - goto next; - - /* Is next root for both ? */ - if (*dn == '\0' && *cp == '\0') - return sp - rmsg; - if (*dn) - continue; - goto next; - case MOWGLI_DNS_NS_CMPRSFLAGS: /* indirection */ - cp = rmsg + (((n & 0x3f) << 8) | *cp); - break; - - default: /* illegal type */ - errno = EMSGSIZE; - return -1; - } - } - next:; - sp += *sp + 1; - } - } - errno = ENOENT; - return -1; -} - -/* - * Thinking in noninternationalized USASCII (per the DNS spec), - * convert this character to lower case if it's upper case. - */ -static int mowgli_dns_mklower(int ch) -{ - if (ch >= 0x41 && ch <= 0x5A) - return ch + 0x20; - - return ch; -} - -/* From resolv/mkquery.c */ - -/* - * Form all types of queries. - * Returns the size of the result or -1. - */ -int mowgli_dns_res_mkquery(const char *dname, /* domain name */ - int query_class, int type, /* class and type of query */ - unsigned char *buf, /* buffer to put query */ - int buflen) /* size of buffer */ -{ - mowgli_dns_resheader_t *hp; - unsigned char *cp; - int n; - unsigned char *dnptrs[20], **dpp, **lastdnptr; - - /* - * Initialize header fields. - */ - if ((buf == NULL) || (buflen < MOWGLI_DNS_HFIXEDSIZE)) - return -1; - memset(buf, 0, MOWGLI_DNS_HFIXEDSIZE); - hp = (mowgli_dns_resheader_t *) buf; - - hp->id = 0; - hp->opcode = MOWGLI_DNS_QUERY; - hp->rd = 1; /* recurse */ - hp->rcode = MOWGLI_DNS_NO_ERRORS; - cp = buf + MOWGLI_DNS_HFIXEDSIZE; - buflen -= MOWGLI_DNS_HFIXEDSIZE; - dpp = dnptrs; - *dpp++ = buf; - *dpp++ = NULL; - lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; - - if ((buflen -= MOWGLI_DNS_QFIXEDSIZE) < 0) - return -1; - if ((n = mowgli_dns_dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) - return -1; - - cp += n; - buflen -= n; - MOWGLI_DNS_NS_PUT16(type, cp); - MOWGLI_DNS_NS_PUT16(query_class, cp); - hp->qdcount = htons(1); - - return cp - buf; -} diff --git a/src/libmowgli/dns/dns_evloop_reslib.h b/src/libmowgli/dns/dns_evloop_reslib.h deleted file mode 100644 index b6fcf03..0000000 --- a/src/libmowgli/dns/dns_evloop_reslib.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * dns/reslib.h - * - * $Id: reslib.h 446 2006-02-12 02:46:54Z db $ - */ - -#ifndef __MOWGLI_DNS_RESLIB_H__ -#define __MOWGLI_DNS_RESLIB_H__ - -/* Here we define some values lifted from nameser.h */ -#define MOWGLI_DNS_NS_NOTIFY_OP 4 -#define MOWGLI_DNS_NS_INT16SIZE 2 -#define MOWGLI_DNS_NS_IN6ADDRSIZE 16 -#define MOWGLI_DNS_NS_INADDRSIZE 4 -#define MOWGLI_DNS_NS_INT32SIZE 4 -#define MOWGLI_DNS_NS_CMPRSFLAGS 0xc0 -#define MOWGLI_DNS_NS_MAXCDNAME 255 -#define MOWGLI_DNS_QUERY 0 -#define MOWGLI_DNS_IQUERY 1 -#define MOWGLI_DNS_NO_ERRORS 0 -#define MOWGLI_DNS_SERVFAIL 2 -#define MOWGLI_DNS_NXDOMAIN 3 -#define MOWGLI_DNS_C_IN 1 -#define MOWGLI_DNS_QFIXEDSIZE 4 -#define MOWGLI_DNS_RRFIXEDSIZE 10 -#define MOWGLI_DNS_HFIXEDSIZE 12 - -typedef struct -{ - unsigned id:16; /* query identification number */ -#ifdef WORDS_BIGENDIAN - /* fields in third byte */ - unsigned qr:1; /* response flag */ - unsigned opcode:4; /* purpose of message */ - unsigned aa:1; /* authoritive answer */ - unsigned tc:1; /* truncated message */ - unsigned rd:1; /* recursion desired */ - /* fields in fourth byte */ - unsigned ra:1; /* recursion available */ - unsigned unused:1; /* unused bits (MBZ as of 4.9.3a3) */ - unsigned ad:1; /* authentic data from named */ - unsigned cd:1; /* checking disabled by resolver */ - unsigned rcode:4; /* response code */ -#else - /* fields in third byte */ - unsigned rd:1; /* recursion desired */ - unsigned tc:1; /* truncated message */ - unsigned aa:1; /* authoritive answer */ - unsigned opcode:4; /* purpose of message */ - unsigned qr:1; /* response flag */ - /* fields in fourth byte */ - unsigned rcode:4; /* response code */ - unsigned cd:1; /* checking disabled by resolver */ - unsigned ad:1; /* authentic data from named */ - unsigned unused:1; /* unused bits (MBZ as of 4.9.3a3) */ - unsigned ra:1; /* recursion available */ -#endif - /* remaining bytes */ - unsigned qdcount:16; /* number of question entries */ - unsigned ancount:16; /* number of answer entries */ - unsigned nscount:16; /* number of authority entries */ - unsigned arcount:16; /* number of resource entries */ -} mowgli_dns_resheader_t; - -/* - * Inline versions of get/put short/long. Pointer is advanced. - */ -#define MOWGLI_DNS_NS_GET16(s, cp) { \ - const unsigned char *t_cp = (const unsigned char *)(cp); \ - (s) = ((uint16_t)t_cp[0] << 8) \ - | ((uint16_t)t_cp[1]) \ - ; \ - (cp) += MOWGLI_DNS_NS_INT16SIZE; \ -} - -#define MOWGLI_DNS_NS_GET32(l, cp) { \ - const unsigned char *t_cp = (const unsigned char *)(cp); \ - (l) = ((uint32_t)t_cp[0] << 24) \ - | ((uint32_t)t_cp[1] << 16) \ - | ((uint32_t)t_cp[2] << 8) \ - | ((uint32_t)t_cp[3]) \ - ; \ - (cp) += MOWGLI_DNS_NS_INT32SIZE; \ -} - -#define MOWGLI_DNS_NS_PUT16(s, cp) { \ - uint16_t t_s = (uint16_t)(s); \ - unsigned char *t_cp = (unsigned char *)(cp); \ - *t_cp++ = t_s >> 8; \ - *t_cp = t_s; \ - (cp) += MOWGLI_DNS_NS_INT16SIZE; \ -} - -#define MOWGLI_DNS_NS_PUT32(l, cp) { \ - uint32_t t_l = (uint32_t)(l); \ - unsigned char *t_cp = (unsigned char *)(cp); \ - *t_cp++ = t_l >> 24; \ - *t_cp++ = t_l >> 16; \ - *t_cp++ = t_l >> 8; \ - *t_cp = t_l; \ - (cp) += MOWGLI_DNS_NS_INT32SIZE; \ -} - -extern int mowgli_dns_dn_expand(const unsigned char *msg, const unsigned char *eom, const unsigned char *src, char *dst, int dstsiz); -extern int mowgli_dns_dn_skipname(const unsigned char *ptr, const unsigned char *eom); -extern unsigned int mowgli_dns_ns_get16(const unsigned char *src); -extern unsigned long mowgli_dns_ns_get32(const unsigned char *src); -extern void mowgli_dns_ns_put16(unsigned int src, unsigned char *dst); -extern void mowgli_dns_ns_put32(unsigned long src, unsigned char *dst); -extern int mowgli_dns_res_mkquery(const char *dname, int query_class, int type, unsigned char *buf, int buflen); - -#endif diff --git a/src/libmowgli/dns/dns_evloop_reslist_win32.c b/src/libmowgli/dns/dns_evloop_reslist_win32.c deleted file mode 100644 index eb45ce8..0000000 --- a/src/libmowgli/dns/dns_evloop_reslist_win32.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * reslist.c - get nameservers from windows * - * - * Copyright 1998 by the Massachusetts Institute of Technology. - * Copyright (C) 2007-2008 by Daniel Stenberg - * - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting - * documentation, and that the name of M.I.T. not be used in - * advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" - * without express or implied warranty. - */ - -#ifdef _WIN32 -#include "mowgli.h" -#include -#include - -int -mowgli_dns_get_windows_nameservers(char *ret_buf, size_t ret_size) -{ - FIXED_INFO *fixedinfo, tfixedinfo; - DWORD size = sizeof(*fixedinfo); - typedef DWORD(WINAPI * get_net_param_func) (FIXED_INFO *, DWORD *); - get_net_param_func get_network_params; - HMODULE handle; - IP_ADDR_STRING *ip_addr; - int i, count = 0; - size_t ip_size = sizeof("255.255.255.255"); - size_t left = ret_size; - char *ret = ret_buf; - HRESULT res; - - if (!(handle = LoadLibrary("iphlpapi.dll"))) - return 0; - - if (!(get_network_params = (get_net_param_func)GetProcAddress(handle, "GetNetworkParams"))) - goto quit; - - res = (*get_network_params)(&tfixedinfo, &size); - if((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS)) - goto quit; - - fixedinfo = mowgli_alloc(size); - if(!fixedinfo || (*get_network_params)(fixedinfo, &size) != ERROR_SUCCESS) - goto quit; - -#ifdef DEBUG - mowgli_log("Host Name: %s\n", fixedinfo->HostName); - mowgli_log("Domain Name: %s\n", fixedinfo->DomainName); - mowgli_log("DNS Servers:\n\t%s (primary)\n", fixedinfo->DnsServerList.IpAddress.String); -#endif - - if(strlen(fixedinfo->DnsServerList.IpAddress.String) > 0 && - inet_addr(fixedinfo->DnsServerList.IpAddress.String) != INADDR_NONE && left > ip_size) - { - ret += sprintf(ret, "%s,", fixedinfo->DnsServerList.IpAddress.String); - left -= ret - ret_buf; - count++; - } - - for(i = 0, ip_addr = fixedinfo->DnsServerList.Next; ip_addr && left > ip_size; ip_addr = ip_addr->Next, i++) - { - if(inet_addr(ip_addr->IpAddress.String) != INADDR_NONE) - { - ret += sprintf(ret, "%s,", ip_addr->IpAddress.String); - left -= ret - ret_buf; - count++; - } -#ifdef DEBUG - mowgli_log("\t%s (secondary %d)\n", ip_addr->IpAddress.String, i + 1); -#endif - } - - mowgli_free(fixedinfo); - -quit: - if(handle) - FreeLibrary(handle); - - if(left <= ip_size) - mowgli_log("Too many nameservers. Truncating to %d addressess", count); - - if(ret > ret_buf) - ret[-1] = '\0'; - - return count; -} - -#endif - diff --git a/src/libmowgli/dns/evloop_res.c b/src/libmowgli/dns/evloop_res.c new file mode 100644 index 0000000..f3292dc --- /dev/null +++ b/src/libmowgli/dns/evloop_res.c @@ -0,0 +1,1094 @@ +/* + * A rewrite of Darren Reeds original res.c As there is nothing + * left of Darrens original code, this is now licensed by the hybrid group. + * (Well, some of the function names are the same, and bits of the structs..) + * You can use it where it is useful, free even. Buy us a beer and stuff. + * + * The authors takes no responsibility for any damage or loss + * of property which results from the use of this software. + * + * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code, + * added callbacks and reference counting of returned hostents. + * --Bleep (Thomas Helvey ) + * + * This was all needlessly complicated for irc. Simplified. No more hostent + * All we really care about is the IP -> hostname mappings. Thats all. + * + * Apr 28, 2003 --cryogen and Dianora + * + * DNS server flooding lessened, AAAA-or-A lookup removed, ip6.int support + * removed, various robustness fixes + * + * 2006 --jilles and nenolod + * + * Clean up various crap, remove global state. Reindent because two space indent + * is hideous. Also remove ancient assumptions that don't make sense anymore (e.g., + * libmowgli targets C99, which specifies an 8-bit char). Pack all this stuff into + * its own namespace. Also gutted a lot of needless/one-use/few-line functions. + * Jesus, what were they thinking... + * + * 2012 --Elizacat + */ + +#include "mowgli.h" +#include "dns.h" + +#define MOWGLI_DNS_MAXPACKET 1024 /* rfc sez 512 but we expand names so ... */ +#define MOWGLI_DNS_RES_MAXALIASES 35 /* maximum aliases allowed */ +#define MOWGLI_DNS_RES_MAXADDRS 35 /* maximum addresses allowed */ +#define MOWGLI_DNS_AR_TTL 600 /* TTL in seconds for dns cache entries */ + +/* RFC 1104/1105 wasn't very helpful about what these fields should be named, so for now, we'll + just name them this way. we probably should look at what named calls them or something. */ +#define MOWGLI_DNS_TYPE_SIZE ((size_t) 2) +#define MOWGLI_DNS_CLASS_SIZE ((size_t) 2) +#define MOWGLI_DNS_TTL_SIZE ((size_t) 4) +#define MOWGLI_DNS_RDLENGTH_SIZE ((size_t) 2) +#define MOWGLI_DNS_ANSWER_FIXED_SIZE (MOWGLI_DNS_TYPE_SIZE + MOWGLI_DNS_CLASS_SIZE + MOWGLI_DNS_TTL_SIZE + MOWGLI_DNS_RDLENGTH_SIZE) + +#define MOWGLI_DNS_MAXLINE 128 + +typedef struct +{ + mowgli_node_t node; + int id; + time_t ttl; + char type; + char queryname[MOWGLI_DNS_RES_HOSTLEN + 1]; /* name currently being queried */ + char retries; /* retry counter */ + char sends; /* number of sends (>1 means resent) */ + time_t sentat; + time_t timeout; + unsigned int lastns; /* index of last server sent to */ + struct sockaddr_storage addr; + + char *name; + mowgli_dns_query_t *query; /* query callback for this request */ +} mowgli_dns_reslist_t; + +static mowgli_heap_t *reslist_heap = NULL; + +#ifndef _WIN32 +static int parse_resvconf(mowgli_dns_t *dns); + +#else +static void parse_windows_resolvers(mowgli_dns_t *dns); + +#endif + +static void timeout_resolver(void *arg); +static void add_nameserver(mowgli_dns_t *dns, const char *arg); +static int res_ourserver(mowgli_dns_t *dns, const struct sockaddr_storage *inp); +static void rem_request(mowgli_dns_t *dns, mowgli_dns_reslist_t *request); +static mowgli_dns_reslist_t *make_request(mowgli_dns_t *dns, mowgli_dns_query_t *query); +static void do_query_name(mowgli_dns_t *dns, mowgli_dns_query_t *query, const char *name, mowgli_dns_reslist_t *request, int); +static void do_query_number(mowgli_dns_t *dns, mowgli_dns_query_t *query, const struct sockaddr_storage *, mowgli_dns_reslist_t *request); +static void query_name(mowgli_dns_t *dns, mowgli_dns_reslist_t *request); +static int send_res_msg(mowgli_dns_t *dns, const char *buf, int len, int count); +static void resend_query(mowgli_dns_t *dns, mowgli_dns_reslist_t *request); +static int check_question(mowgli_dns_reslist_t *request, mowgli_dns_resheader_t *header, char *buf, char *eob); +static int proc_answer(mowgli_dns_reslist_t *request, mowgli_dns_resheader_t *header, char *, char *); +static mowgli_dns_reslist_t *find_id(mowgli_dns_t *dns, int id); +static mowgli_dns_reply_t *make_dnsreply(mowgli_dns_reslist_t *request); +static void res_readreply(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata); + +/* + * mowgli_dns_evloop_init - do everything we need to read the resolv.conf file + * and initialize the resolver file descriptor if needed + */ +int +mowgli_dns_evloop_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop) +{ + int i; + mowgli_dns_evloop_t *state; + + if (dns->dns_state == NULL) + dns->dns_state = mowgli_alloc(sizeof(mowgli_dns_evloop_t)); + + dns->dns_type = MOWGLI_DNS_TYPE_ASYNC; + + if (!reslist_heap) + reslist_heap = mowgli_heap_create(sizeof(mowgli_dns_reslist_t), 512, BH_LAZY); + + state = dns->dns_state; + + state->rand = mowgli_random_create(); + + state->nscount = 0; + +#ifndef _WIN32 + parse_resvconf(dns); +#else + parse_windows_resolvers(dns); +#endif + + if (state->nscount == 0) + { + mowgli_log("couldn't get resolv.conf entries, falling back to localhost resolver"); + add_nameserver(dns, "127.0.0.1"); + } + + for (i = 0; i < state->nscount; i++) + state->timeout_count[i] = 0; + + if (state->vio == NULL) + { + state->vio = mowgli_vio_create(dns); + + if (mowgli_vio_socket(state->vio, state->nsaddr_list[0].addr.ss_family, SOCK_DGRAM, 0) != 0) + { + mowgli_log("start_resolver(): unable to open UDP resolver socket: %s", + state->vio->error.string); + return -1; + } + + state->eventloop = eventloop; + mowgli_vio_eventloop_attach(state->vio, state->eventloop, NULL); + mowgli_pollable_setselect(state->eventloop, state->vio->io.e, MOWGLI_EVENTLOOP_IO_READ, res_readreply); + mowgli_pollable_set_cloexec(state->vio->io.e, true); + state->timeout_resolver_timer = mowgli_timer_add(state->eventloop, "timeout_resolver", timeout_resolver, dns, 1); + } + + return 0; +} + +int +mowgli_dns_evloop_set_resolvconf(mowgli_dns_t *dns, const char *respath) +{ +#ifndef _WIN32 + mowgli_dns_evloop_t *state = dns->dns_state; + + return_val_if_fail(dns, -1); + + state->resolvconf = respath; + + if (!state->dns_init) + return mowgli_dns_evloop_restart(dns); + + return 0; +#else + mowgli_log("Unimplemented on Windows. :("); +#endif +} + +/* + * mowgli_dns_evloop_restart - reread resolv.conf, reopen socket + */ +int +mowgli_dns_evloop_restart(mowgli_dns_t *dns) +{ + mowgli_dns_evloop_t *state = dns->dns_state; + + mowgli_dns_evloop_destroy(dns); + return mowgli_dns_evloop_init(dns, state->eventloop); +} + +/* mowgli_dns_evloop_destroy - finish us off */ +void +mowgli_dns_evloop_destroy(mowgli_dns_t *dns) +{ + mowgli_dns_evloop_t *state = dns->dns_state; + + mowgli_vio_close(state->vio); + mowgli_vio_destroy(state->vio); + + mowgli_timer_destroy(state->eventloop, state->timeout_resolver_timer); + + mowgli_free(state); + dns->dns_state = NULL; +} + +#ifndef _WIN32 + +/* parse_resvconf() + * inputs - NONE + * output - -1 if failure, 0 if success + * side effects - fills in state->nsaddr_list + */ +static int +parse_resvconf(mowgli_dns_t *dns) +{ + char *p; + char *opt; + char *arg; + const char *respath; + char input[MOWGLI_DNS_MAXLINE]; + FILE *file; + mowgli_dns_evloop_t *state = dns->dns_state; + + if (state->resolvconf) + respath = state->resolvconf; + else + respath = "/etc/resolv.conf"; + + if ((file = fopen(respath, "r")) == NULL) + { + mowgli_log("Failed to open %s: %s", respath, strerror(errno)); + return -1; + } + + while (fgets(input, sizeof(input), file) != NULL) + { + /* blow away any newline */ + if ((p = strpbrk(input, "\r\n")) != NULL) + *p = '\0'; + + p = input; + + /* skip until something thats not a space is seen */ + while (isspace(*p)) + { + p++; + } + + /* if at this point, have a '\0' then continue */ + if (*p == '\0') + continue; + + /* Ignore comment lines immediately */ + if ((*p == '#') || (*p == ';')) + continue; + + /* skip until a space is found */ + opt = p; + + while (!isspace(*p) && *p != '\0') + { + p++; + } + + if (*p == '\0') + continue; /* no arguments?.. ignore this line */ + + /* blow away the space character */ + *p++ = '\0'; + + /* skip these spaces that are before the argument */ + while (isspace(*p)) + { + p++; + } + + /* Now arg should be right where p is pointing */ + arg = p; + + if ((p = strpbrk(arg, " \t")) != NULL) + *p = '\0'; /* take the first word */ + + if (strcmp(opt, "domain") == 0) + mowgli_strlcpy(state->domain, arg, sizeof(state->domain)); + else if (strcmp(opt, "nameserver") == 0) + add_nameserver(dns, arg); + } + + fclose(file); + + state->dns_init = true; + + return 0; +} + +#else + +extern int mowgli_dns_get_windows_nameservers(char *ret_buf, size_t ret_size); + +static void +parse_windows_resolvers(mowgli_dns_t *dns) +{ + char ns_buf[4096]; + char *server; + + mowgli_dns_get_windows_nameservers(ns_buf, sizeof ns_buf); + + for (server = strtok(ns_buf, ","); server != NULL; server = strtok(NULL, ",")) + add_nameserver(dns, server); +} + +#endif + +/* add_nameserver() + * input - either an IPV4 address in dotted quad or an IPV6 address in : format + * output - NONE + * side effects - entry in state->nsaddr_list is filled in as needed */ +static void +add_nameserver(mowgli_dns_t *dns, const char *arg) +{ + struct addrinfo hints, *res; + + mowgli_dns_evloop_t *state = dns->dns_state; + +#ifdef DEBUG + mowgli_log("add_nameserver(): %s", arg); +#endif + + /* Done max number of nameservers? */ + if (state->nscount >= MOWGLI_DNS_MAXNS) + { + mowgli_log("Too many nameservers, ignoring %s", arg); + return; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + if (getaddrinfo(arg, "domain", &hints, &res)) + return; + + if (res == NULL) + return; + + memcpy(&state->nsaddr_list[state->nscount].addr, res->ai_addr, res->ai_addrlen); + state->nsaddr_list[state->nscount].addrlen = res->ai_addrlen; + state->nscount++; + freeaddrinfo(res); +} + +/* + * int + * res_ourserver(dns, inp) + * looks up "inp" in state->nsaddr_list[] + * returns: + * 0 : not found + * >0 : found + * author: + * paul vixie, 29may94 + * revised for ircd, cryogen(stu) may03 + * rewritten by Elizacat 25mar12 + */ +static int +res_ourserver(mowgli_dns_t *dns, const struct sockaddr_storage *inp) +{ + int ns; + mowgli_dns_evloop_t *state = dns->dns_state; + + for (ns = 0; ns < state->nscount; ns++) + { + const struct sockaddr_storage *srv = &state->nsaddr_list[ns].addr; + + /* could probably just memcmp(srv, inp, srv.ss_len) here but we'll air on the side of + caution - stu */ + switch (srv->ss_family) + { + case AF_INET6: + { + const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *) srv; + const struct sockaddr_in6 *v6in = (const struct sockaddr_in6 *) inp; + + if ((srv->ss_family == inp->ss_family) && (v6->sin6_port == v6in->sin6_port)) + if ((memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr, + sizeof(struct in6_addr)) == 0) || + (memcmp(&v6->sin6_addr.s6_addr, &in6addr_any, + sizeof(struct in6_addr)) == 0)) + { + state->timeout_count[ns] = 0; + return 1; + } + + break; + } + case AF_INET: + { + const struct sockaddr_in *v4 = (const struct sockaddr_in *) srv; + const struct sockaddr_in *v4in = (const struct sockaddr_in *) inp; + + if ((srv->ss_family == inp->ss_family) && (v4->sin_port == v4in->sin_port)) + if ((v4->sin_addr.s_addr == INADDR_ANY) + || (v4->sin_addr.s_addr == v4in->sin_addr.s_addr)) + { + state->timeout_count[ns] = 0; + return 1; + } + + break; + } + default: + break; + } + } + + return 0; +} + +/* + * timeout_query_list - Remove queries from the list which have been + * there too long without being resolved. + */ +static time_t +timeout_query_list(mowgli_dns_t *dns, time_t now) +{ + mowgli_node_t *ptr; + mowgli_node_t *next_ptr; + mowgli_dns_reslist_t *request; + time_t next_time = 0; + time_t timeout = 0; + mowgli_dns_evloop_t *state = dns->dns_state; + + MOWGLI_ITER_FOREACH_SAFE(ptr, next_ptr, state->request_list.head) + { + request = ptr->data; + timeout = request->sentat + request->timeout; + + if (now >= timeout) + { + if (--request->retries <= 0) + { + (*request->query->callback)(NULL, MOWGLI_DNS_RES_TIMEOUT, request->query->ptr); + rem_request(dns, request); + continue; + } + else + { + state->timeout_count[request->lastns]++; + request->sentat = now; + request->timeout += request->timeout; + resend_query(dns, request); + } + } + + if ((next_time == 0) || (timeout < next_time)) + next_time = timeout; + } + + return (next_time > now) ? next_time : (now + MOWGLI_DNS_AR_TTL); +} + +/* + * timeout_resolver - check request list + */ +static void +timeout_resolver(void *arg) +{ + mowgli_dns_t *dns = arg; + mowgli_dns_evloop_t *state = dns->dns_state; + time_t now, next; + + now = mowgli_eventloop_get_time(state->eventloop); + next = timeout_query_list(dns, now); + + /* Reschedule */ + mowgli_timer_destroy(state->eventloop, state->timeout_resolver_timer); + mowgli_timer_add(state->eventloop, "timeout_resolver", timeout_resolver, dns, next - now); +} + +/* + * mowgli_dns_evloop_add_local_domain - Add the domain to hostname, if it is missing + * (as suggested by eps@TOASTER.SFSU.EDU) + */ +void +mowgli_dns_evloop_add_local_domain(mowgli_dns_t *dns, char *hname, size_t size) +{ + mowgli_dns_evloop_t *state = dns->dns_state; + + /* try to fix up unqualified names */ + if (strchr(hname, '.') == NULL) + if (state->domain[0]) + { + size_t len = strlen(hname); + + if ((strlen(state->domain) + len + 2) < size) + { + hname[len++] = '.'; + strcpy(hname + len, state->domain); + } + } +} + +/* + * rem_request - remove a request from the list. + * This must also free any memory that has been allocated for + * temporary storage of DNS results. + */ +static void +rem_request(mowgli_dns_t *dns, mowgli_dns_reslist_t *request) +{ + mowgli_dns_evloop_t *state = dns->dns_state; + + return_if_fail(request != NULL); + + mowgli_node_delete(&request->node, &state->request_list); + mowgli_free(request->name); + mowgli_heap_free(reslist_heap, request); +} + +/* + * make_request - Create a DNS request record for the server. + */ +static mowgli_dns_reslist_t * +make_request(mowgli_dns_t *dns, mowgli_dns_query_t *query) +{ + mowgli_dns_reslist_t *request = mowgli_heap_alloc(reslist_heap); + mowgli_dns_evloop_t *state = dns->dns_state; + + request->sentat = mowgli_eventloop_get_time(state->eventloop); + request->retries = 3; + request->timeout = 4; /* start at 4 and exponential inc. */ + request->query = query; + + mowgli_node_add(request, &request->node, &state->request_list); + + return request; +} + +/* + * mowgli_dns_evloop_delete_queries - cleanup outstanding queries + * for which there no longer exist clients or conf lines. + */ +void +mowgli_dns_evloop_delete_queries(mowgli_dns_t *dns, const mowgli_dns_query_t *query) +{ + mowgli_node_t *ptr; + mowgli_node_t *next_ptr; + mowgli_dns_reslist_t *request; + mowgli_dns_evloop_t *state = dns->dns_state; + + MOWGLI_ITER_FOREACH_SAFE(ptr, next_ptr, state->request_list.head) + { + if ((request = ptr->data) != NULL) + if (query == request->query) + rem_request(dns, request); + } +} + +/* + * retryfreq - determine how many queries to wait before resending + * if there have been that many consecutive timeouts + */ +static inline int +retryfreq(int timeouts) +{ + int i; + int counter = 1; + const int max_retries = 5; + + for (i = 0; i < (timeouts < max_retries ? timeouts : max_retries); i++) + counter *= 3; + + return counter; +} + +/* + * send_res_msg - sends msg to a nameserver. + * This should reflect /etc/resolv.conf. + * Returns number of nameserver successfully sent to + * or -1 if no successful sends. + */ +static int +send_res_msg(mowgli_dns_t *dns, const char *rmsg, int len, int rcount) +{ + int i; + int ns; + mowgli_dns_evloop_t *state = dns->dns_state; + + state->retrycnt++; + + /* First try a nameserver that seems to work. Every once in a while, try a possibly broken one + * to check if it is working again. */ + for (i = 0; i < state->nscount; i++) + { + ns = (i + rcount - 1) % state->nscount; + + if (state->timeout_count[ns] && state->retrycnt % retryfreq(state->timeout_count[ns])) + continue; + + if (mowgli_vio_sendto(state->vio, rmsg, len, &state->nsaddr_list[ns]) == len) + return ns; + } + + /* No known working nameservers, try some broken one. */ + for (i = 0; i < state->nscount; i++) + { + ns = (i + rcount - 1) % state->nscount; + + if (!state->timeout_count[ns]) + continue; + + if (mowgli_vio_sendto(state->vio, rmsg, len, &state->nsaddr_list[ns]) == len) + return ns; + } + + return -1; +} + +/* + * find_id - find a dns request id (id is determined by dn_mkquery) + */ +static mowgli_dns_reslist_t * +find_id(mowgli_dns_t *dns, int id) +{ + mowgli_node_t *ptr; + mowgli_dns_reslist_t *request; + mowgli_dns_evloop_t *state = dns->dns_state; + + MOWGLI_ITER_FOREACH(ptr, state->request_list.head) + { + request = ptr->data; + + if (request->id == id) + return request; + } + + return NULL; +} + +/* + * mowgli_dns_evloop_gethost_byname - get host address from name + * + */ +void +mowgli_dns_evloop_gethost_byname(mowgli_dns_t *dns, const char *name, mowgli_dns_query_t *query, int type) +{ + return_if_fail(name != NULL); + + do_query_name(dns, query, name, NULL, type); +} + +/* + * mowgli_dns_evloop_gethost_byaddr - get host name from address + */ +void +mowgli_dns_evloop_gethost_byaddr(mowgli_dns_t *dns, const struct sockaddr_storage *addr, mowgli_dns_query_t *query) +{ + return_if_fail(addr != NULL); + + do_query_number(dns, query, addr, NULL); +} + +/* + * do_query_name - nameserver lookup name + */ +static void +do_query_name(mowgli_dns_t *dns, mowgli_dns_query_t *query, const char *name, mowgli_dns_reslist_t *request, int type) +{ + char host_name[MOWGLI_DNS_RES_HOSTLEN + 1]; + + mowgli_strlcpy(host_name, name, MOWGLI_DNS_RES_HOSTLEN + 1); + mowgli_dns_evloop_add_local_domain(dns, host_name, MOWGLI_DNS_RES_HOSTLEN); + + if (request == NULL) + { + request = make_request(dns, query); + request->name = mowgli_strdup(host_name); + } + + mowgli_strlcpy(request->queryname, host_name, sizeof(request->queryname)); + request->type = type; + query_name(dns, request); +} + +/* + * do_query_number - Use this to do reverse IP# lookups. + */ +static void +do_query_number(mowgli_dns_t *dns, mowgli_dns_query_t *query, const struct sockaddr_storage *addr, mowgli_dns_reslist_t *request) +{ + const unsigned char *cp; + const size_t size = addr->ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); + + if (request == NULL) + { + request = make_request(dns, query); + memcpy(&request->addr, addr, size); + request->name = (char *) mowgli_alloc(MOWGLI_DNS_RES_HOSTLEN + 1); + } + + if (addr->ss_family == AF_INET) + { + const struct sockaddr_in *v4 = (const struct sockaddr_in *) addr; + cp = (const unsigned char *) &v4->sin_addr.s_addr; + + sprintf(request->queryname, "%u.%u.%u.%u.in-addr.arpa", (unsigned int) (cp[3]), + (unsigned int) (cp[2]), (unsigned int) (cp[1]), (unsigned int) (cp[0])); + } + else if (addr->ss_family == AF_INET6) + { + int i; + char *rqptr = request->queryname; + const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *) addr; + cp = (const unsigned char *) &v6->sin6_addr.s6_addr; + + for (i = 15; i >= 0; i--, rqptr += 4) + sprintf(rqptr, "%1x.%1x.", + (unsigned int) (cp[i] & 0xf), + (unsigned int) (cp[i] >> 4)); + + strcpy(rqptr, ".ip6.arpa"); + } + else + { + mowgli_log("do_query_number() called with invalid sockaddr_storage %d", addr->ss_family); + return; + } + + request->type = MOWGLI_DNS_T_PTR; + query_name(dns, request); +} + +/* + * query_name - generate a query based on class, type and name. + */ +static void +query_name(mowgli_dns_t *dns, mowgli_dns_reslist_t *request) +{ + char buf[MOWGLI_DNS_MAXPACKET]; + int request_len = 0; + int ns; + mowgli_dns_evloop_t *state = dns->dns_state; + + memset(buf, 0, sizeof(buf)); + + if ((request_len = + mowgli_dns_res_mkquery(request->queryname, MOWGLI_DNS_C_IN, request->type, (unsigned char *) buf, + sizeof(buf))) > 0) + { + mowgli_dns_resheader_t *header = (mowgli_dns_resheader_t *) buf; + + /* + * generate an unique id + * NOTE: we don't have to worry about converting this to and from + * network byte order, the nameserver does not interpret this value + * and returns it unchanged + */ + do + header->id = (header->id + mowgli_random_int(state->rand)) & 0xffff; + + while (find_id(dns, header->id)); + + request->id = header->id; + ++request->sends; + + ns = send_res_msg(dns, buf, request_len, request->sends); + + if (ns != -1) + request->lastns = ns; + } +} + +static void +resend_query(mowgli_dns_t *dns, mowgli_dns_reslist_t *request) +{ + switch (request->type) + { + case MOWGLI_DNS_T_PTR: + do_query_number(dns, NULL, &request->addr, request); + break; + case MOWGLI_DNS_T_A: + case MOWGLI_DNS_T_AAAA: + do_query_name(dns, NULL, request->name, request, request->type); + break; + default: + break; + } +} + +/* + * check_question - check if the reply really belongs to the + * name we queried (to guard against late replies from previous + * queries with the same id). + */ +static int +check_question(mowgli_dns_reslist_t *request, mowgli_dns_resheader_t *header, char *buf, char *eob) +{ + char hostbuf[MOWGLI_DNS_RES_HOSTLEN + 1]; /* working buffer */ + unsigned char *current; /* current position in buf */ + int n; /* temp count */ + + current = (unsigned char *) buf + sizeof(mowgli_dns_resheader_t); + + if (header->qdcount != 1) + return 0; + + n = mowgli_dns_dn_expand((unsigned char *) buf, (unsigned char *) eob, current, hostbuf, sizeof(hostbuf)); + + if (n <= 0) + return 0; + + if (strcasecmp(hostbuf, request->queryname)) + return 0; + + return 1; +} + +/* + * proc_answer - process name server reply + */ +static int +proc_answer(mowgli_dns_reslist_t *request, mowgli_dns_resheader_t *header, char *buf, char *eob) +{ + char hostbuf[MOWGLI_DNS_RES_HOSTLEN + 100]; /* working buffer */ + unsigned char *current; /* current position in buf */ + int query_class;/* answer class */ + int type; /* answer type */ + int n; /* temp count */ + int rd_length; + + current = (unsigned char *) buf + sizeof(mowgli_dns_resheader_t); + + for (; header->qdcount > 0; --header->qdcount) + { + if ((n = mowgli_dns_dn_skipname(current, (unsigned char *) eob)) < 0) + return 0; + + current += (size_t) n + MOWGLI_DNS_QFIXEDSIZE; + } + + /* process each answer sent to us. */ + while (header->ancount > 0 && (char *) current < eob) + { + header->ancount--; + + n = mowgli_dns_dn_expand((unsigned char *) buf, (unsigned char *) eob, current, hostbuf, + sizeof(hostbuf)); + + /* Broken message (< 0) or no more answers left (== 0) */ + if (n <= 0) + return 0; + + hostbuf[MOWGLI_DNS_RES_HOSTLEN] = '\0'; + + /* With Address arithmetic you have to be very anal -- this code was not working on alpha due + * to that (spotted by rodder/jailbird/dianora) */ + current += (size_t) n; + + if (!(((char *) current + MOWGLI_DNS_ANSWER_FIXED_SIZE) < eob)) + break; + + type = mowgli_dns_ns_get16(current); + current += MOWGLI_DNS_TYPE_SIZE; + + query_class = mowgli_dns_ns_get16(current); + current += MOWGLI_DNS_CLASS_SIZE; + + /* We may use this later at some point so... eliminate bogus GCC warning */ + (void) query_class; + + request->ttl = mowgli_dns_ns_get32(current); + current += MOWGLI_DNS_TTL_SIZE; + + rd_length = mowgli_dns_ns_get16(current); + current += MOWGLI_DNS_RDLENGTH_SIZE; + + /* Wait to set request->type until we verify this structure */ + switch (type) + { + case MOWGLI_DNS_T_A: + { + struct sockaddr_in *v4; + + if (request->type != MOWGLI_DNS_T_A) + return 0; + + /* check for invalid rd_length or too many addresses */ + if (rd_length != sizeof(struct in_addr)) + return 0; + + v4 = (struct sockaddr_in *) &request->addr; + v4->sin_family = AF_INET; + memcpy(&v4->sin_addr, current, sizeof(struct in_addr)); + + return 1; + } + case MOWGLI_DNS_T_AAAA: + { + struct sockaddr_in6 *v6; + + if (request->type != MOWGLI_DNS_T_AAAA) + return 0; + + if (rd_length != sizeof(struct in6_addr)) + return 0; + + v6 = (struct sockaddr_in6 *) &request->addr; + v6->sin6_family = AF_INET6; + memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr)); + + return 1; + } + case MOWGLI_DNS_T_PTR: + + if (request->type != MOWGLI_DNS_T_PTR) + return 0; + + n = mowgli_dns_dn_expand((unsigned char *) buf, (unsigned char *) eob, current, + hostbuf, sizeof(hostbuf)); + + /* Broken message or no more answers left */ + if (n <= 0) + return 0; + + mowgli_strlcpy(request->name, hostbuf, MOWGLI_DNS_RES_HOSTLEN + 1); + + return 1; + case MOWGLI_DNS_T_CNAME: + + /* real answer will follow */ + current += rd_length; + break; + default: + + /* XXX I'd rather just throw away the entire bogus thing but its possible its just a + * broken nameserver with still valid answers. But lets do some rudimentary logging for + * now... */ + mowgli_log("proc_answer(): bogus type %d", type); + break; + } + } + + return 1; +} + +/* + * res_read_single_reply - read a dns reply from the nameserver and process it. + * Return value: 1 if a packet was read, 0 otherwise + */ +static int +res_read_single_reply(mowgli_dns_t *dns) +{ + char buf[sizeof(mowgli_dns_resheader_t) + MOWGLI_DNS_MAXPACKET] + + /* Sparc and alpha need 16bit-alignment for accessing header->id (which is uint16_t). + Because of the header = (mowgli_dns_resheader_t*) buf; later on, this is neeeded. --FaUl */ +#if defined(__sparc__) || defined(__alpha__) + __attribute__((aligned(16))) +#endif + ; + mowgli_dns_resheader_t *header; + mowgli_dns_reslist_t *request = NULL; + mowgli_dns_reply_t *reply = NULL; + int rc; + int answer_count; + mowgli_vio_sockaddr_t lsin = { .addrlen = sizeof(lsin.addr) }; + mowgli_dns_evloop_t *state = dns->dns_state; + + rc = mowgli_vio_recvfrom(state->vio, buf, sizeof(buf), &lsin); + + /* No packet */ + if ((rc == 0) || (rc == -1)) + return 0; + + /* Too small */ + if (rc <= (int) (sizeof(mowgli_dns_resheader_t))) + return 1; + + /* + * convert DNS reply reader from Network byte order to CPU byte order. + */ + header = (mowgli_dns_resheader_t *) buf; + header->ancount = ntohs(header->ancount); + header->qdcount = ntohs(header->qdcount); + header->nscount = ntohs(header->nscount); + header->arcount = ntohs(header->arcount); + + /* response for an id which we have already received an answer for + * just ignore this response. */ + if ((request = find_id(dns, header->id)) == 0) + return 1; + + /* check against possibly fake replies */ + if (!res_ourserver(dns, &lsin.addr)) + return 1; + + if (!check_question(request, header, buf, buf + rc)) + return 1; + + if ((header->rcode != MOWGLI_DNS_NO_ERRORS) || (header->ancount == 0)) + { + if (header->rcode == MOWGLI_DNS_NXDOMAIN) + { + (*request->query->callback)(NULL, MOWGLI_DNS_RES_NXDOMAIN, request->query->ptr); + rem_request(dns, request); + } + else + { + /* + * If a bad error was returned, we stop here and dont send + * send any more (no retries granted). + */ + (*request->query->callback)(NULL, MOWGLI_DNS_RES_INVALID, request->query->ptr); + rem_request(dns, request); + } + + return 1; + } + + /* If this fails there was an error decoding the received packet, + * give up. -- jilles + */ + answer_count = proc_answer(request, header, buf, buf + rc); + + if (answer_count) + { + if (request->type == MOWGLI_DNS_T_PTR) + { + if (request->name == NULL) + { + /* got a PTR response with no name, something bogus is happening + * don't bother trying again, the client address doesn't resolve + */ + (*request->query->callback)(reply, MOWGLI_DNS_RES_INVALID, request->query->ptr); + rem_request(dns, request); + return 1; + } + + /* Lookup the 'authoritative' name that we were given for the + * ip#. */ + if (request->addr.ss_family == AF_INET6) + mowgli_dns_evloop_gethost_byname(dns, request->name, request->query, MOWGLI_DNS_T_AAAA); + else + mowgli_dns_evloop_gethost_byname(dns, request->name, request->query, MOWGLI_DNS_T_A); + + rem_request(dns, request); + } + else + { + /* got a name and address response, client resolved */ + reply = make_dnsreply(request); + (*request->query->callback)(reply, MOWGLI_DNS_RES_SUCCESS, request->query->ptr); + mowgli_free(reply); + rem_request(dns, request); + } + } + else + { + /* couldn't decode, give up -- jilles */ + (*request->query->callback)(NULL, MOWGLI_DNS_RES_INVALID, request->query->ptr); + rem_request(dns, request); + } + + return 1; +} + +static mowgli_dns_reply_t * +make_dnsreply(mowgli_dns_reslist_t *request) +{ + mowgli_dns_reply_t *cp; + + return_val_if_fail(request != 0, NULL); + + cp = (mowgli_dns_reply_t *) mowgli_alloc(sizeof(mowgli_dns_reply_t)); + + cp->h_name = request->name; + memcpy(&cp->addr, &request->addr, sizeof(cp->addr)); + return cp; +} + +static void +res_readreply(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +{ + mowgli_dns_t *dns = userdata; + + while (res_read_single_reply(dns)) + { } +} + +/* DNS ops for this resolver */ +const mowgli_dns_ops_t mowgli_dns_evloop_resolver = +{ + .mowgli_dns_init_func_t = mowgli_dns_evloop_init, + .mowgli_dns_fini_func_t = mowgli_dns_evloop_destroy, + .mowgli_dns_restart_func_t = mowgli_dns_evloop_restart, + .mowgli_dns_delete_query_func_t = mowgli_dns_evloop_delete_queries, + .mowgli_dns_gethost_byname_func_t = mowgli_dns_evloop_gethost_byname, + .mowgli_dns_gethost_byaddr_func_t = mowgli_dns_evloop_gethost_byaddr, +}; diff --git a/src/libmowgli/dns/evloop_res.h b/src/libmowgli/dns/evloop_res.h new file mode 100644 index 0000000..bb5befc --- /dev/null +++ b/src/libmowgli/dns/evloop_res.h @@ -0,0 +1,49 @@ +/* + * res.h for referencing functions in res.c, reslib.c + * + * Originally from Charybdis (before that, hybrid), but very little of the + * original remains, so... + */ + +#ifndef __MOWGLI_DNS_RES_H__ +#define __MOWGLI_DNS_RES_H__ + +/* Maximum number of nameservers we track */ +#define MOWGLI_DNS_MAXNS 10 + +typedef struct +{ + mowgli_vio_sockaddr_t nsaddr_list[MOWGLI_DNS_MAXNS]; + int nscount; + + int retrycnt; + + int timeout_count[MOWGLI_DNS_MAXNS]; + + mowgli_vio_t *vio; + mowgli_eventloop_t *eventloop; + mowgli_eventloop_timer_t *timeout_resolver_timer; + + mowgli_list_t request_list; + + mowgli_random_t *rand; + + const char *resolvconf; + bool dns_init; + + char domain[MOWGLI_DNS_RES_HOSTLEN]; +} mowgli_dns_evloop_t; + +extern int mowgli_dns_evloop_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop); +extern int mowgli_dns_evloop_restart(mowgli_dns_t *dns); +extern void mowgli_dns_evloop_destroy(mowgli_dns_t *dns); +extern void mowgli_dns_evloop_delete_queries(mowgli_dns_t *dns, const mowgli_dns_query_t *); +extern void mowgli_dns_evloop_gethost_byname(mowgli_dns_t *dns, const char *, mowgli_dns_query_t *, int); +extern void mowgli_dns_evloop_gethost_byaddr(mowgli_dns_t *dns, const struct sockaddr_storage *, mowgli_dns_query_t *); + +extern void mowgli_dns_evloop_add_local_domain(mowgli_dns_t * dns, char *, size_t); +extern int mowgli_dns_evloop_set_resolvconf(mowgli_dns_t *dns, const char *respath); + +extern const mowgli_dns_ops_t mowgli_dns_evloop_resolver; + +#endif diff --git a/src/libmowgli/dns/evloop_reslib.c b/src/libmowgli/dns/evloop_reslib.c new file mode 100644 index 0000000..9dbbfe8 --- /dev/null +++ b/src/libmowgli/dns/evloop_reslib.c @@ -0,0 +1,1220 @@ +/* + * Copyright (c) 1985, 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. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * 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, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION 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. + */ + +/* + * Portions Copyright (c) 1996-1999 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* Original copyright ISC as above. Code modified specifically for ircd use from the following + * orginal files in bind ... res_comp.c ns_name.c ns_netint.c res_init.c - Dianora */ + +#include "mowgli.h" + +#ifdef _WIN32 +# define EMSGSIZE WSAEMSGSIZE +#endif + +#define MOWGLI_DNS_NS_TYPE_ELT 0x40 /* EDNS0 extended label type */ +#define MOWGLI_DNS_LABELTYPE_BITSTRING 0x41 + +/* from Hybrid Id: reslib.c 177 2005-10-22 09:05:05Z michael $ */ + +static const char digitvalue[256] = +{ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 16 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 32 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 48 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 64 */ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 96 */ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 112 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 128 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 256 */ +}; + +static const char digits[] = "0123456789"; + +static int labellen(const unsigned char *lp); +static bool mowgli_dns_is_special(int ch); +static bool mowgli_dns_is_printable(int ch); +static int mowgli_dns_decode_bitstring(const char **cpp, char *dn, const char *eom); +static int mowgli_dns_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz, unsigned char **dnptrs, unsigned char **lastdnptr); +static int mowgli_dns_dn_find(const unsigned char *, const unsigned char *, const unsigned char *const *, const unsigned char *const *); +static int mowgli_dns_encode_bitsring(const char **, const char *, unsigned char **, unsigned char **, const char *); +static int mowgli_dns_ns_name_uncompress(const unsigned char *, const unsigned char *, const unsigned char *, char *, size_t); +static int mowgli_dns_ns_name_unpack(const unsigned char *, const unsigned char *, const unsigned char *, unsigned char *, size_t); +static int mowgli_dns_ns_name_ntop(const char *, char *, size_t); +static int mowgli_dns_ns_name_skip(const unsigned char **, const unsigned char *); +static int mowgli_dns_mklower(int ch); + +/* + * Expand compressed domain name 'comp_dn' to full domain name. + * 'rmsg' is a pointer to the begining of the message, + * 'eomorig' points to the first location after the message, + * 'exp_dn' is a pointer to a buffer of size 'length' for the result. + * Return size of compressed name or -1 if there was an error. + */ +int +mowgli_dns_dn_expand(const unsigned char *rmsg, const unsigned char *eom, const unsigned char *src, char *dst, int dstsiz) +{ + int n = mowgli_dns_ns_name_uncompress(rmsg, eom, src, dst, (size_t) dstsiz); + + if ((n > 0) && (dst[0] == '.')) + dst[0] = '\0'; + + return n; +} + +/* + * mowgli_dns_ns_name_uncompress(rmsg, eom, src, dst, dstsiz) + * Expand compressed domain name to presentation format. + * return: + * Number of bytes read out of `src', or -1 (with errno set). + * note: + * Root domain returns as "." not "". + */ +static int +mowgli_dns_ns_name_uncompress(const unsigned char *rmsg, const unsigned char *eom, const unsigned char *src, char *dst, size_t dstsiz) +{ + unsigned char tmp[MOWGLI_DNS_NS_MAXCDNAME]; + int n; + + if ((n = mowgli_dns_ns_name_unpack(rmsg, eom, src, tmp, sizeof tmp)) == -1) + return -1; + + if (mowgli_dns_ns_name_ntop((char *) tmp, dst, dstsiz) == -1) + return -1; + + return n; +} + +/* + * mowgli_dns_ns_name_unpack(rmsg, eom, src, dst, dstsiz) + * Unpack a domain name from a message, source may be compressed. + * return: + * -1 if it fails, or consumed octets if it succeeds. + */ +static int +mowgli_dns_ns_name_unpack(const unsigned char *rmsg, const unsigned char *eom, const unsigned char *src, unsigned char *dst, size_t dstsiz) +{ + const unsigned char *srcp, *dstlim; + unsigned char *dstp; + int n, len, checked, l; + + len = -1; + checked = 0; + dstp = dst; + srcp = src; + dstlim = dst + dstsiz; + + if ((srcp < rmsg) || (srcp >= eom)) + { + errno = EMSGSIZE; + return -1; + } + + /* Fetch next label in domain name. */ + while ((n = *srcp++) != 0) + { + /* Check for indirection. */ + switch (n & MOWGLI_DNS_NS_CMPRSFLAGS) + { + case 0: + case MOWGLI_DNS_NS_TYPE_ELT: + + /* Limit checks. */ + if ((l = labellen(srcp - 1)) < 0) + { + errno = EMSGSIZE; + return -1; + } + + if ((dstp + l + 1 >= dstlim) || (srcp + l >= eom)) + { + errno = EMSGSIZE; + return -1; + } + + checked += l + 1; + *dstp++ = n; + memcpy(dstp, srcp, l); + dstp += l; + srcp += l; + break; + + case MOWGLI_DNS_NS_CMPRSFLAGS: + + if (srcp >= eom) + { + errno = EMSGSIZE; + return -1; + } + + if (len < 0) + len = srcp - src + 1; + + srcp = rmsg + (((n & 0x3f) << 8) | (*srcp & 0xff)); + + if ((srcp < rmsg) || (srcp >= eom)) /* Out of range. */ + { + errno = EMSGSIZE; + return -1; + } + + checked += 2; + + /* + * Check for loops in the compressed name; + * if we've looked at the whole message, + * there must be a loop. + */ + if (checked >= eom - rmsg) + { + errno = EMSGSIZE; + return -1; + } + + break; + + default: + errno = EMSGSIZE; + return -1; /* flag error */ + } + } + + *dstp = '\0'; + + if (len < 0) + len = srcp - src; + + return len; +} + +/* + * mowgli_dns_ns_name_ntop(src, dst, dstsiz) + * Convert an encoded domain name to mowgli_dns_is_printable ascii as per RFC1035. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * The root is returned as "." + * All other domains are returned in non absolute form + */ +static int +mowgli_dns_ns_name_ntop(const char *src, char *dst, size_t dstsiz) +{ + const char *cp; + char *dn, *eom; + unsigned char c; + unsigned int n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) + { + if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) + { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return -1; + } + + if (dn != dst) + { + if (dn >= eom) + { + errno = EMSGSIZE; + return -1; + } + + *dn++ = '.'; + } + + if ((l = labellen((const unsigned char *) (cp - 1))) < 0) + { + errno = EMSGSIZE; /* XXX */ + return -1; + } + + if (dn + l >= eom) + { + errno = EMSGSIZE; + return -1; + } + + if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_TYPE_ELT) + { + int m; + + if (n != MOWGLI_DNS_LABELTYPE_BITSTRING) + { + /* XXX: labellen should reject this case */ + errno = EINVAL; + return -1; + } + + if ((m = mowgli_dns_decode_bitstring(&cp, dn, eom)) < 0) + { + errno = EMSGSIZE; + return -1; + } + + dn += m; + continue; + } + + for ((void) NULL; l > 0; l--) + { + c = *cp++; + + if (mowgli_dns_is_special(c)) + { + if (dn + 1 >= eom) + { + errno = EMSGSIZE; + return -1; + } + + *dn++ = '\\'; + *dn++ = (char) c; + } + else if (!mowgli_dns_is_printable(c)) + { + if (dn + 3 >= eom) + { + errno = EMSGSIZE; + return -1; + } + + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } + else + { + if (dn >= eom) + { + errno = EMSGSIZE; + return -1; + } + + *dn++ = (char) c; + } + } + } + + if (dn == dst) + { + if (dn >= eom) + { + errno = EMSGSIZE; + return -1; + } + + *dn++ = '.'; + } + + if (dn >= eom) + { + errno = EMSGSIZE; + return -1; + } + + *dn++ = '\0'; + return dn - dst; +} + +/* + * Pack domain name 'exp_dn' in presentation form into 'comp_dn'. + * Return the size of the compressed name or -1. + * 'length' is the size of the array pointed to by 'comp_dn'. + */ +static int +mowgli_dns_dn_comp(const char *src, unsigned char *dst, int dstsiz, unsigned char **dnptrs, unsigned char **lastdnptr) +{ + return mowgli_dns_ns_name_compress(src, dst, (size_t) dstsiz, dnptrs, lastdnptr); +} + +/* + * Skip over a compressed domain name. Return the size or -1. + */ +int +mowgli_dns_dn_skipname(const unsigned char *ptr, const unsigned char *eom) +{ + const unsigned char *saveptr = ptr; + + if (mowgli_dns_ns_name_skip(&ptr, eom) == -1) + return -1; + + return ptr - saveptr; +} + +/* + * ns_name_skip(ptrptr, eom) + * Advance *ptrptr to skip over the compressed name it points at. + * return: + * 0 on success, -1 (with errno set) on failure. + */ +static int +mowgli_dns_ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom) +{ + const unsigned char *cp; + unsigned int n; + int l; + + cp = *ptrptr; + + while (cp < eom && (n = *cp++) != 0) + { + /* Check for indirection. */ + switch (n & MOWGLI_DNS_NS_CMPRSFLAGS) + { + case 0: /* normal case, n == len */ + cp += n; + continue; + case MOWGLI_DNS_NS_TYPE_ELT: /* EDNS0 extended label */ + + if ((l = labellen(cp - 1)) < 0) + { + errno = EMSGSIZE; /* XXX */ + return -1; + } + + cp += l; + continue; + case MOWGLI_DNS_NS_CMPRSFLAGS: /* indirection */ + cp++; + break; + default:/* illegal type */ + errno = EMSGSIZE; + return -1; + } + + break; + } + + if (cp > eom) + { + errno = EMSGSIZE; + return -1; + } + + *ptrptr = cp; + return 0; +} + +unsigned int +mowgli_dns_ns_get16(const unsigned char *src) +{ + unsigned int dst; + + MOWGLI_DNS_NS_GET16(dst, src); + return dst; +} + +unsigned long +mowgli_dns_ns_get32(const unsigned char *src) +{ + unsigned long dst; + + MOWGLI_DNS_NS_GET32(dst, src); + return dst; +} + +void +mowgli_dns_ns_put16(unsigned int src, unsigned char *dst) +{ + MOWGLI_DNS_NS_PUT16(src, dst); +} + +void +mowgli_dns_ns_put32(unsigned long src, unsigned char *dst) +{ + MOWGLI_DNS_NS_PUT32(src, dst); +} + +/* From ns_name.c */ + +/* + * mowgli_dns_is_special(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted mowgli_dns_is_special ("in need of quoting") ? + * return: + * boolean. + */ +static bool +mowgli_dns_is_special(int ch) +{ + switch (ch) + { + case 0x22: /* '"' */ + case 0x2E: /* '.' */ + case 0x3B: /* ';' */ + case 0x5C: /* '\\' */ + case 0x28: /* '(' */ + case 0x29: /* ')' */ + /* Special modifiers in zone files. */ + case 0x40: /* '@' */ + case 0x24: /* '$' */ + return true; + default: + return false; + } +} + +static int +labellen(const unsigned char *lp) +{ + int bitlen; + unsigned char l = *lp; + + if ((l & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) + /* should be avoided by the caller */ + return -1; + + if ((l & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_TYPE_ELT) + { + if (l == MOWGLI_DNS_LABELTYPE_BITSTRING) + { + if ((bitlen = *(lp + 1)) == 0) + bitlen = 256; + + return (bitlen + 7) / 8 + 1; + } + + return -1; /* unknwon ELT */ + } + + return l; +} + +/* + * mowgli_dns_is_printable(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * return: + * boolean. + */ +static bool +mowgli_dns_is_printable(int ch) +{ + return (ch > 0x20 && ch < 0x7f) ? true : false; +} + +static int +mowgli_dns_decode_bitstring(const char **cpp, char *dn, const char *eom) +{ + const char *cp = *cpp; + char *beg = dn, tc; + int b, blen, plen; + + if ((blen = (*cp & 0xff)) == 0) + blen = 256; + + plen = (blen + 3) / 4; + plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); + + if (dn + plen >= eom) + return -1; + + cp++; + dn += sprintf(dn, "\\[x"); + + for (b = blen; b > 7; b -= 8, cp++) + dn += sprintf(dn, "%02x", *cp & 0xff); + + if (b > 4) + { + tc = *cp++; + dn += sprintf(dn, "%02x", tc & (0xff << (8 - b))); + } + else if (b > 0) + { + tc = *cp++; + dn += sprintf(dn, "%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b))); + } + + dn += sprintf(dn, "/%d]", blen); + + *cpp = cp; + return dn - beg; +} + +/* + * mowgli_dns_ns_name_pton(src, dst, dstsiz) + * Convert a ascii string into an encoded domain name as per RFC1035. + * return: + * -1 if it fails + * 1 if string was fully qualified + * 0 is string was not fully qualified + * notes: + * Enforces label and domain length limits. + */ +static int +mowgli_dns_ns_name_pton(const char *src, unsigned char *dst, size_t dstsiz) +{ + unsigned char *label, *bp, *eom; + char *cp; + int c, n, escaped, e = 0; + + escaped = 0; + bp = dst; + eom = dst + dstsiz; + label = bp++; + + while ((c = *src++) != 0) + { + if (escaped) + { + if (c == '[') /* start a bit string label */ + { + if ((cp = strchr(src, ']')) == NULL) + { + errno = EINVAL; /* ??? */ + return -1; + } + + if ((e = mowgli_dns_encode_bitsring(&src, cp + 2, &label, &bp, (const char *) eom)) != 0) + { + errno = e; + return -1; + } + + escaped = 0; + label = bp++; + + if ((c = *src++) == 0) + { + goto done; + } + else if (c != '.') + { + errno = EINVAL; + return -1; + } + + continue; + } + else if ((cp = strchr(digits, c)) != NULL) + { + n = (cp - digits) * 100; + + if (((c = *src++) == 0) || ((cp = strchr(digits, c)) == NULL)) + { + errno = EMSGSIZE; + return -1; + } + + n += (cp - digits) * 10; + + if (((c = *src++) == 0) || ((cp = strchr(digits, c)) == NULL)) + { + errno = EMSGSIZE; + return -1; + } + + n += (cp - digits); + + if (n > 255) + { + errno = EMSGSIZE; + return -1; + } + + c = n; + } + + escaped = 0; + } + else if (c == '\\') + { + escaped = 1; + continue; + } + else if (c == '.') + { + c = (bp - label - 1); + + if ((c & MOWGLI_DNS_NS_CMPRSFLAGS) != 0)/* Label too big. */ + { + errno = EMSGSIZE; + return -1; + } + + if (label >= eom) + { + errno = EMSGSIZE; + return -1; + } + + *label = c; + + /* Fully qualified ? */ + if (*src == '\0') + { + if (c != 0) + { + if (bp >= eom) + { + errno = EMSGSIZE; + return -1; + } + + *bp++ = '\0'; + } + + if ((bp - dst) > MOWGLI_DNS_NS_MAXCDNAME) + { + errno = EMSGSIZE; + return -1; + } + + return 1; + } + + if ((c == 0) || (*src == '.')) + { + errno = EMSGSIZE; + return -1; + } + + label = bp++; + continue; + } + + if (bp >= eom) + { + errno = EMSGSIZE; + return -1; + } + + *bp++ = (unsigned char) c; + } + + c = (bp - label - 1); + + if ((c & MOWGLI_DNS_NS_CMPRSFLAGS) != 0)/* Label too big. */ + { + errno = EMSGSIZE; + return -1; + } + +done: + + if (label >= eom) + { + errno = EMSGSIZE; + return -1; + } + + *label = c; + + if (c != 0) + { + if (bp >= eom) + { + errno = EMSGSIZE; + return -1; + } + + *bp++ = 0; + } + + if ((bp - dst) > MOWGLI_DNS_NS_MAXCDNAME) /* src too big */ + { + errno = EMSGSIZE; + return -1; + } + + return 0; +} + +/* + * mowgli_dns_ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) + * Pack domain name 'domain' into 'comp_dn'. + * return: + * Size of the compressed name, or -1. + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. The array + * ends with NULL. + * 'lastdnptr' is a pointer to the end of the array pointed to + * by 'dnptrs'. + * Side effects: + * The list of pointers in dnptrs is updated for labels inserted into + * the message as we compress the name. If 'dnptr' is NULL, we don't + * try to compress names. If 'lastdnptr' is NULL, we don't update the + * list. + */ +static int +mowgli_dns_ns_name_pack(const unsigned char *src, unsigned char *dst, int dstsiz, unsigned char **dnptrs, unsigned char **lastdnptr) +{ + unsigned char *dstp; + unsigned char **cpp, **lpp; + const unsigned char *eob, *rmsg; + const unsigned char *srcp; + int n, l, first = 1; + + srcp = src; + dstp = dst; + eob = dstp + dstsiz; + lpp = cpp = NULL; + + if (dnptrs != NULL) + { + if ((rmsg = *dnptrs++) != NULL) + { + for (cpp = dnptrs; *cpp != NULL; cpp++) + (void) NULL; + + lpp = cpp; /* end of list to search */ + } + } + else + { + rmsg = NULL; + } + + /* make sure the domain we are about to add is legal */ + l = 0; + + do + { + int l0; + + n = *srcp; + + if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) + { + errno = EMSGSIZE; + return -1; + } + + if ((l0 = labellen(srcp)) < 0) + { + errno = EINVAL; + return -1; + } + + l += l0 + 1; + + if (l > MOWGLI_DNS_NS_MAXCDNAME) + { + errno = EMSGSIZE; + return -1; + } + + srcp += l0 + 1; + } while (n != 0); + + /* from here on we need to reset compression pointer array on error */ + srcp = src; + + do + { + /* Look to see if we can use pointers. */ + n = *srcp; + + if ((n != 0) && (rmsg != NULL)) + { + l = mowgli_dns_dn_find(srcp, rmsg, (const unsigned char *const *) dnptrs, + (const unsigned char *const *) lpp); + + if (l >= 0) + { + if (dstp + 1 >= eob) + goto cleanup; + + *dstp++ = (l >> 8) | MOWGLI_DNS_NS_CMPRSFLAGS; + *dstp++ = l % 256; + return dstp - dst; + } + + /* Not found, save it. */ + if ((lastdnptr != NULL) && (cpp < lastdnptr - 1) && ((dstp - rmsg) < 0x4000) && first) + { + *cpp++ = dstp; + *cpp = NULL; + first = 0; + } + } + + /* copy label to buffer */ + if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) + /* Should not happen. */ + goto cleanup; + + n = labellen(srcp); + + if (dstp + 1 + n >= eob) + goto cleanup; + + memcpy(dstp, srcp, n + 1); + srcp += n + 1; + dstp += n + 1; + } while (n != 0); + + if (dstp > eob) + { +cleanup: + + if (rmsg != NULL) + *lpp = NULL; + + errno = EMSGSIZE; + return -1; + } + + return dstp - dst; +} + +static int +mowgli_dns_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz, unsigned char **dnptrs, unsigned char **lastdnptr) +{ + unsigned char tmp[MOWGLI_DNS_NS_MAXCDNAME]; + + if (mowgli_dns_ns_name_pton(src, tmp, sizeof tmp) == -1) + return -1; + + return mowgli_dns_ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr); +} + +static int +mowgli_dns_encode_bitsring(const char **bp, const char *end, unsigned char **labelp, unsigned char **dst, const char *eom) +{ + int afterslash = 0; + const char *cp = *bp; + char *tp, c; + const char *beg_blen; + char *end_blen = NULL; + int value = 0, count = 0, tbcount = 0, blen = 0; + + beg_blen = end_blen = NULL; + + /* a bitstring must contain at least 2 characters */ + if (end - cp < 2) + return EINVAL; + + /* XXX: currently, only hex strings are supported */ + if (*cp++ != 'x') + return EINVAL; + + if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */ + return EINVAL; + + for (tp = (char *) (dst + 1); cp < end && tp < eom; cp++) + { + switch ((c = *cp)) + { + case ']': /* end of the bitstring */ + + if (afterslash) + { + if (beg_blen == NULL) + return EINVAL; + + blen = (int) strtol(beg_blen, &end_blen, 10); + + if (*end_blen != ']') + return EINVAL; + } + + if (count) + *tp++ = ((value << 4) & 0xff); + + cp++; /* skip ']' */ + goto done; + case '/': + afterslash = 1; + break; + default: + + if (afterslash) + { + if (!isdigit(c & 0xff)) + return EINVAL; + + if (beg_blen == NULL) + { + if (c == '0') + /* blen never begings with 0 */ + return EINVAL; + + beg_blen = cp; + } + } + else + { + if (!isxdigit(c & 0xff)) + return EINVAL; + + value <<= 4; + value += digitvalue[(int) c]; + count += 4; + tbcount += 4; + + if (tbcount > 256) + return EINVAL; + + if (count == 8) + { + *tp++ = value; + count = 0; + } + } + + break; + } + } + +done: + + if ((cp >= end) || (tp >= eom)) + return EMSGSIZE; + + /* + * bit length validation: + * If a is present, the number of digits in the + * MUST be just sufficient to contain the number of bits specified + * by the . If there are insignificant bits in a final + * hexadecimal or octal digit, they MUST be zero. + * RFC 2673, Section 3.2. + */ + if (blen > 0) + { + int traillen; + + if (((blen + 3) & ~3) != tbcount) + return EINVAL; + + traillen = tbcount - blen; /* between 0 and 3 */ + + if (((value << (8 - traillen)) & 0xff) != 0) + return EINVAL; + } + else + { + blen = tbcount; + } + + if (blen == 256) + blen = 0; + + /* encode the type and the significant bit fields */ + **labelp = MOWGLI_DNS_LABELTYPE_BITSTRING; + **dst = blen; + + *bp = cp; + *dst = (unsigned char *) tp; + + return 0; +} + +/* + * dn_find(domain, rmsg, dnptrs, lastdnptr) + * Search for the counted-label name in an array of compressed names. + * return: + * offset from rmsg if found, or -1. + * notes: + * dnptrs is the pointer to the first name on the list, + * not the pointer to the start of the message. + */ +static int +mowgli_dns_dn_find(const unsigned char *domain, const unsigned char *rmsg, const unsigned char *const *dnptrs, const unsigned char *const *lastdnptr) +{ + const unsigned char *dn, *cp, *sp; + const unsigned char *const *cpp; + unsigned int n; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) + { + sp = *cpp; + + /* + * terminate search on: + * root label + * compression pointer + * unusable offset + */ + while (*sp != 0 && (*sp & MOWGLI_DNS_NS_CMPRSFLAGS) == 0 && (sp - rmsg) < 0x4000) + { + dn = domain; + cp = sp; + + while ((n = *cp++) != 0) + { + /* + * check for indirection + */ + switch (n & MOWGLI_DNS_NS_CMPRSFLAGS) + { + case 0: /* normal case, n == len */ + n = labellen(cp - 1); /* XXX */ + + if (n != *dn++) + goto next; + + for (; n > 0; n--) + if (mowgli_dns_mklower(*dn++) != mowgli_dns_mklower(*cp++)) + goto next; + + /* Is next root for both ? */ + if ((*dn == '\0') && (*cp == '\0')) + return sp - rmsg; + + if (*dn) + continue; + + goto next; + case MOWGLI_DNS_NS_CMPRSFLAGS: /* indirection */ + cp = rmsg + (((n & 0x3f) << 8) | *cp); + break; + + default:/* illegal type */ + errno = EMSGSIZE; + return -1; + } + } + +next:; + sp += *sp + 1; + } + } + + errno = ENOENT; + return -1; +} + +/* + * Thinking in noninternationalized USASCII (per the DNS spec), + * convert this character to lower case if it's upper case. + */ +static int +mowgli_dns_mklower(int ch) +{ + if ((ch >= 0x41) && (ch <= 0x5A)) + return ch + 0x20; + + return ch; +} + +/* From resolv/mkquery.c */ + +/* + * Form all types of queries. + * Returns the size of the result or -1. + */ +int +mowgli_dns_res_mkquery(const char *dname, /* domain name */ + int query_class, int type, /* class and type of query */ + unsigned char *buf, /* buffer to put query */ + int buflen) /* size of buffer */ +{ + mowgli_dns_resheader_t *hp; + unsigned char *cp; + int n; + unsigned char *dnptrs[20], **dpp, **lastdnptr; + + /* + * Initialize header fields. + */ + if ((buf == NULL) || (buflen < MOWGLI_DNS_HFIXEDSIZE)) + return -1; + + memset(buf, 0, MOWGLI_DNS_HFIXEDSIZE); + hp = (mowgli_dns_resheader_t *) buf; + + hp->id = 0; + hp->opcode = MOWGLI_DNS_QUERY; + hp->rd = 1; /* recurse */ + hp->rcode = MOWGLI_DNS_NO_ERRORS; + cp = buf + MOWGLI_DNS_HFIXEDSIZE; + buflen -= MOWGLI_DNS_HFIXEDSIZE; + dpp = dnptrs; + *dpp++ = buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + + if ((buflen -= MOWGLI_DNS_QFIXEDSIZE) < 0) + return -1; + + if ((n = mowgli_dns_dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) + return -1; + + cp += n; + buflen -= n; + MOWGLI_DNS_NS_PUT16(type, cp); + MOWGLI_DNS_NS_PUT16(query_class, cp); + hp->qdcount = htons(1); + + return cp - buf; +} diff --git a/src/libmowgli/dns/evloop_reslib.h b/src/libmowgli/dns/evloop_reslib.h new file mode 100644 index 0000000..0555eab --- /dev/null +++ b/src/libmowgli/dns/evloop_reslib.h @@ -0,0 +1,115 @@ +/* + * dns/reslib.h + * + * $Id: reslib.h 446 2006-02-12 02:46:54Z db $ + */ + +#ifndef __MOWGLI_DNS_RESLIB_H__ +#define __MOWGLI_DNS_RESLIB_H__ + +/* Here we define some values lifted from nameser.h */ +#define MOWGLI_DNS_NS_NOTIFY_OP 4 +#define MOWGLI_DNS_NS_INT16SIZE 2 +#define MOWGLI_DNS_NS_IN6ADDRSIZE 16 +#define MOWGLI_DNS_NS_INADDRSIZE 4 +#define MOWGLI_DNS_NS_INT32SIZE 4 +#define MOWGLI_DNS_NS_CMPRSFLAGS 0xc0 +#define MOWGLI_DNS_NS_MAXCDNAME 255 +#define MOWGLI_DNS_QUERY 0 +#define MOWGLI_DNS_IQUERY 1 +#define MOWGLI_DNS_NO_ERRORS 0 +#define MOWGLI_DNS_SERVFAIL 2 +#define MOWGLI_DNS_NXDOMAIN 3 +#define MOWGLI_DNS_C_IN 1 +#define MOWGLI_DNS_QFIXEDSIZE 4 +#define MOWGLI_DNS_RRFIXEDSIZE 10 +#define MOWGLI_DNS_HFIXEDSIZE 12 + +typedef struct +{ + unsigned id : 16; /* query identification number */ +#ifdef WORDS_BIGENDIAN + + /* fields in third byte */ + unsigned qr : 1;/* response flag */ + unsigned opcode : 4; /* purpose of message */ + unsigned aa : 1;/* authoritive answer */ + unsigned tc : 1;/* truncated message */ + unsigned rd : 1;/* recursion desired */ + /* fields in fourth byte */ + unsigned ra : 1;/* recursion available */ + unsigned unused : 1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ad : 1;/* authentic data from named */ + unsigned cd : 1;/* checking disabled by resolver */ + unsigned rcode : 4; /* response code */ +#else + + /* fields in third byte */ + unsigned rd : 1;/* recursion desired */ + unsigned tc : 1;/* truncated message */ + unsigned aa : 1;/* authoritive answer */ + unsigned opcode : 4; /* purpose of message */ + unsigned qr : 1;/* response flag */ + /* fields in fourth byte */ + unsigned rcode : 4; /* response code */ + unsigned cd : 1;/* checking disabled by resolver */ + unsigned ad : 1;/* authentic data from named */ + unsigned unused : 1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ra : 1;/* recursion available */ +#endif + + /* remaining bytes */ + unsigned qdcount : 16; /* number of question entries */ + unsigned ancount : 16; /* number of answer entries */ + unsigned nscount : 16; /* number of authority entries */ + unsigned arcount : 16; /* number of resource entries */ +} mowgli_dns_resheader_t; + +/* + * Inline versions of get/put short/long. Pointer is advanced. + */ +#define MOWGLI_DNS_NS_GET16(s, cp) { \ + const unsigned char *t_cp = (const unsigned char *) (cp); \ + (s) = ((uint16_t) t_cp[0] << 8) \ + | ((uint16_t) t_cp[1]) \ + ; \ + (cp) += MOWGLI_DNS_NS_INT16SIZE; \ +} + +#define MOWGLI_DNS_NS_GET32(l, cp) { \ + const unsigned char *t_cp = (const unsigned char *) (cp); \ + (l) = ((uint32_t) t_cp[0] << 24) \ + | ((uint32_t) t_cp[1] << 16) \ + | ((uint32_t) t_cp[2] << 8) \ + | ((uint32_t) t_cp[3]) \ + ; \ + (cp) += MOWGLI_DNS_NS_INT32SIZE; \ +} + +#define MOWGLI_DNS_NS_PUT16(s, cp) { \ + uint16_t t_s = (uint16_t) (s); \ + unsigned char *t_cp = (unsigned char *) (cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += MOWGLI_DNS_NS_INT16SIZE; \ +} + +#define MOWGLI_DNS_NS_PUT32(l, cp) { \ + uint32_t t_l = (uint32_t) (l); \ + unsigned char *t_cp = (unsigned char *) (cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += MOWGLI_DNS_NS_INT32SIZE; \ +} + +extern int mowgli_dns_dn_expand(const unsigned char *msg, const unsigned char *eom, const unsigned char *src, char *dst, int dstsiz); +extern int mowgli_dns_dn_skipname(const unsigned char *ptr, const unsigned char *eom); +extern unsigned int mowgli_dns_ns_get16(const unsigned char *src); +extern unsigned long mowgli_dns_ns_get32(const unsigned char *src); +extern void mowgli_dns_ns_put16(unsigned int src, unsigned char *dst); +extern void mowgli_dns_ns_put32(unsigned long src, unsigned char *dst); +extern int mowgli_dns_res_mkquery(const char *dname, int query_class, int type, unsigned char *buf, int buflen); + +#endif diff --git a/src/libmowgli/dns/evloop_reslist_win32.c b/src/libmowgli/dns/evloop_reslist_win32.c new file mode 100644 index 0000000..afce82c --- /dev/null +++ b/src/libmowgli/dns/evloop_reslist_win32.c @@ -0,0 +1,102 @@ +/* + * reslist.c - get nameservers from windows * + * + * Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2007-2008 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "mowgli.h" + +#ifdef MOWGLI_OS_WIN +# include +# include + +int +mowgli_dns_get_windows_nameservers(char *ret_buf, size_t ret_size) +{ + FIXED_INFO *fixedinfo, tfixedinfo; + DWORD size = sizeof(*fixedinfo); + + typedef DWORD (WINAPI * get_net_param_func)(FIXED_INFO *, DWORD *); + get_net_param_func get_network_params; + HMODULE handle; + IP_ADDR_STRING *ip_addr; + int i, count = 0; + size_t ip_size = sizeof("255.255.255.255"); + size_t left = ret_size; + char *ret = ret_buf; + HRESULT res; + + if (!(handle = LoadLibrary("iphlpapi.dll"))) + return 0; + + if (!(get_network_params = (get_net_param_func) GetProcAddress(handle, "GetNetworkParams"))) + goto quit; + + res = (*get_network_params)(&tfixedinfo, &size); + + if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS)) + goto quit; + + fixedinfo = mowgli_alloc(size); + + if (!fixedinfo || ((*get_network_params)(fixedinfo, &size) != ERROR_SUCCESS)) + goto quit; + +# ifdef DEBUG + mowgli_log("Host Name: %s\n", fixedinfo->HostName); + mowgli_log("Domain Name: %s\n", fixedinfo->DomainName); + mowgli_log("DNS Servers:\n\t%s (primary)\n", fixedinfo->DnsServerList.IpAddress.String); +# endif + + if ((strlen(fixedinfo->DnsServerList.IpAddress.String) > 0) && + (inet_addr(fixedinfo->DnsServerList.IpAddress.String) != INADDR_NONE) && (left > ip_size)) + { + ret += sprintf(ret, "%s,", fixedinfo->DnsServerList.IpAddress.String); + left -= ret - ret_buf; + count++; + } + + for (i = 0, ip_addr = fixedinfo->DnsServerList.Next; ip_addr && left > ip_size; ip_addr = ip_addr->Next, i++) + { + if (inet_addr(ip_addr->IpAddress.String) != INADDR_NONE) + { + ret += sprintf(ret, "%s,", ip_addr->IpAddress.String); + left -= ret - ret_buf; + count++; + } + +# ifdef DEBUG + mowgli_log("\t%s (secondary %d)\n", ip_addr->IpAddress.String, i + 1); +# endif + } + + mowgli_free(fixedinfo); + +quit: + + if (handle) + FreeLibrary(handle); + + if (left <= ip_size) + mowgli_log("Too many nameservers. Truncating to %d addressess", count); + + if (ret > ret_buf) + ret[-1] = '\0'; + + return count; +} + +#endif diff --git a/src/libmowgli/eventloop/epoll_pollops.c b/src/libmowgli/eventloop/epoll_pollops.c index 596b992..a77c882 100644 --- a/src/libmowgli/eventloop/epoll_pollops.c +++ b/src/libmowgli/eventloop/epoll_pollops.c @@ -22,15 +22,17 @@ #ifdef HAVE_SYS_EPOLL_H -#include +# include -typedef struct { +typedef struct +{ int epoll_fd; int pfd_size; struct epoll_event *pfd; } mowgli_epoll_eventloop_private_t; -static void mowgli_epoll_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +static void +mowgli_epoll_eventloop_pollsetup(mowgli_eventloop_t *eventloop) { mowgli_epoll_eventloop_private_t *priv; @@ -38,13 +40,14 @@ static void mowgli_epoll_eventloop_pollsetup(mowgli_eventloop_t *eventloop) eventloop->poller = priv; priv->pfd_size = getdtablesize(); - priv->epoll_fd = epoll_create(priv->pfd_size); + priv->epoll_fd = epoll_create1(EPOLL_CLOEXEC); /* Linux 2.6.27+ */ priv->pfd = mowgli_alloc(sizeof(struct epoll_event) * priv->pfd_size); return; } -static void mowgli_epoll_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +static void +mowgli_epoll_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) { mowgli_epoll_eventloop_private_t *priv; @@ -59,7 +62,8 @@ static void mowgli_epoll_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) return; } -static void mowgli_epoll_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +static void +mowgli_epoll_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) { mowgli_epoll_eventloop_private_t *priv; struct epoll_event ep_event; @@ -82,10 +86,12 @@ static void mowgli_epoll_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli } } -static void mowgli_epoll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +static void +mowgli_epoll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) { mowgli_epoll_eventloop_private_t *priv; struct epoll_event ep_event; + int op = -1; unsigned int old_flags; @@ -95,9 +101,9 @@ static void mowgli_epoll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowg priv = eventloop->poller; old_flags = pollable->slot; -#ifdef DEBUG +# ifdef DEBUG mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); -#endif +# endif switch (dir) { @@ -114,9 +120,9 @@ static void mowgli_epoll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowg break; } -#ifdef DEBUG +# ifdef DEBUG mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); -#endif +# endif if (pollable->read_function == NULL) pollable->slot &= ~EPOLLIN; @@ -124,11 +130,11 @@ static void mowgli_epoll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowg if (pollable->write_function == NULL) pollable->slot &= ~EPOLLOUT; - if (old_flags == 0 && pollable->slot == 0) + if ((old_flags == 0) && (pollable->slot == 0)) return; else if (pollable->slot <= 0) op = EPOLL_CTL_DEL; - else if (old_flags == 0 && pollable->slot != 0) + else if ((old_flags == 0) && (pollable->slot != 0)) op = EPOLL_CTL_ADD; else if (pollable->slot != old_flags) op = EPOLL_CTL_MOD; @@ -150,7 +156,8 @@ static void mowgli_epoll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowg return; } -static void mowgli_epoll_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +static void +mowgli_epoll_eventloop_select(mowgli_eventloop_t *eventloop, int delay) { mowgli_epoll_eventloop_private_t *priv; int i, num, o_errno; @@ -177,15 +184,16 @@ static void mowgli_epoll_eventloop_select(mowgli_eventloop_t *eventloop, int del { mowgli_eventloop_pollable_t *pollable = priv->pfd[i].data.ptr; - if (priv->pfd[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR) && pollable->read_function != NULL) - pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + if (priv->pfd[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)) + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ); - if (priv->pfd[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR) && pollable->write_function != NULL) - pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + if (priv->pfd[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR)) + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE); } } -mowgli_eventloop_ops_t _mowgli_epoll_pollops = { +mowgli_eventloop_ops_t _mowgli_epoll_pollops = +{ .timeout_once = mowgli_simple_eventloop_timeout_once, .run_once = mowgli_simple_eventloop_run_once, .pollsetup = mowgli_epoll_eventloop_pollsetup, diff --git a/src/libmowgli/eventloop/eventloop.c b/src/libmowgli/eventloop/eventloop.c index d2045cd..d8eb422 100644 --- a/src/libmowgli/eventloop/eventloop.c +++ b/src/libmowgli/eventloop/eventloop.c @@ -46,7 +46,8 @@ extern mowgli_eventloop_ops_t _mowgli_kqueue_pollops; extern mowgli_eventloop_ops_t _mowgli_winsock_pollops; #endif -mowgli_eventloop_t *mowgli_eventloop_create(void) +mowgli_eventloop_t * +mowgli_eventloop_create(void) { mowgli_eventloop_t *eventloop; @@ -81,18 +82,21 @@ mowgli_eventloop_t *mowgli_eventloop_create(void) if (mowgli_mutex_init(&eventloop->mutex) != 0) { - mowgli_log("couldn't create mutex for eventloop %p, aborting...", eventloop); + mowgli_log("couldn't create mutex for eventloop %p, aborting...", (void *) eventloop); abort(); } eventloop->eventloop_ops->pollsetup(eventloop); - mowgli_eventloop_synchronize(eventloop); + eventloop->deadline = -1; + + mowgli_eventloop_calibrate(eventloop); return eventloop; } -void mowgli_eventloop_destroy(mowgli_eventloop_t *eventloop) +void +mowgli_eventloop_destroy(mowgli_eventloop_t *eventloop) { eventloop->eventloop_ops->pollshutdown(eventloop); @@ -100,7 +104,8 @@ void mowgli_eventloop_destroy(mowgli_eventloop_t *eventloop) mowgli_heap_free(eventloop_heap, eventloop); } -void mowgli_eventloop_run(mowgli_eventloop_t *eventloop) +void +mowgli_eventloop_run(mowgli_eventloop_t *eventloop) { return_if_fail(eventloop != NULL); @@ -109,12 +114,15 @@ void mowgli_eventloop_run(mowgli_eventloop_t *eventloop) eventloop->death_requested = false; while (!eventloop->death_requested) + { eventloop->eventloop_ops->run_once(eventloop); + } mowgli_mutex_unlock(&eventloop->mutex); } -void mowgli_eventloop_run_once(mowgli_eventloop_t *eventloop) +void +mowgli_eventloop_run_once(mowgli_eventloop_t *eventloop) { return_if_fail(eventloop != NULL); @@ -125,7 +133,8 @@ void mowgli_eventloop_run_once(mowgli_eventloop_t *eventloop) mowgli_mutex_unlock(&eventloop->mutex); } -void mowgli_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int timeout) +void +mowgli_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int timeout) { return_if_fail(eventloop != NULL); @@ -139,7 +148,8 @@ void mowgli_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int timeout) mowgli_mutex_unlock(&eventloop->mutex); } -void mowgli_eventloop_break(mowgli_eventloop_t *eventloop) +void +mowgli_eventloop_break(mowgli_eventloop_t *eventloop) { return_if_fail(eventloop != NULL); @@ -147,7 +157,8 @@ void mowgli_eventloop_break(mowgli_eventloop_t *eventloop) } /* convenience function to request null pollops */ -void mowgli_eventloop_timers_only(mowgli_eventloop_t *eventloop) +void +mowgli_eventloop_timers_only(mowgli_eventloop_t *eventloop) { return_if_fail(eventloop != NULL); @@ -155,14 +166,16 @@ void mowgli_eventloop_timers_only(mowgli_eventloop_t *eventloop) } /* userdata setting/getting functions (for bindings) */ -void *mowgli_eventloop_get_data(mowgli_eventloop_t *eventloop) +void * +mowgli_eventloop_get_data(mowgli_eventloop_t *eventloop) { return_val_if_fail(eventloop != NULL, NULL); return eventloop->data; } -void mowgli_eventloop_set_data(mowgli_eventloop_t *eventloop, void *data) +void +mowgli_eventloop_set_data(mowgli_eventloop_t *eventloop, void *data) { return_if_fail(eventloop != NULL); diff --git a/src/libmowgli/eventloop/eventloop.h b/src/libmowgli/eventloop/eventloop.h index 4c07b27..42a257c 100644 --- a/src/libmowgli/eventloop/eventloop.h +++ b/src/libmowgli/eventloop/eventloop.h @@ -21,6 +21,13 @@ #ifndef __MOWGLI_EVENTLOOP_EVENTLOOP_H__ #define __MOWGLI_EVENTLOOP_EVENTLOOP_H__ +#ifdef MOWGLI_OS_OSX + +# include +# include + +#endif + #ifndef _WIN32 typedef int mowgli_descriptor_t; @@ -31,13 +38,15 @@ typedef SOCKET mowgli_descriptor_t; #endif -typedef enum { +typedef enum +{ MOWGLI_EVENTLOOP_TYPE_POLLABLE, MOWGLI_EVENTLOOP_TYPE_HELPER, MOWGLI_EVENTLOOP_TYPE_ERROR = -1 } mowgli_eventloop_io_type_t; -typedef struct { +typedef struct +{ mowgli_eventloop_io_type_t type; } mowgli_eventloop_io_obj_t; @@ -48,7 +57,8 @@ typedef struct _mowgli_helper mowgli_eventloop_helper_proc_t; typedef struct _mowgli_linebuf mowgli_linebuf_t; -typedef enum { +typedef enum +{ MOWGLI_EVENTLOOP_IO_READ, MOWGLI_EVENTLOOP_IO_WRITE, MOWGLI_EVENTLOOP_IO_ERROR = -1 @@ -57,7 +67,8 @@ typedef enum { typedef void mowgli_eventloop_io_t; /* checked casts */ -static inline mowgli_eventloop_pollable_t *mowgli_eventloop_io_pollable(mowgli_eventloop_io_t *io) +static inline mowgli_eventloop_pollable_t * +mowgli_eventloop_io_pollable(mowgli_eventloop_io_t *io) { mowgli_eventloop_io_obj_t *obj = (mowgli_eventloop_io_obj_t *) io; @@ -67,7 +78,8 @@ static inline mowgli_eventloop_pollable_t *mowgli_eventloop_io_pollable(mowgli_e return (mowgli_eventloop_pollable_t *) io; } -static inline mowgli_eventloop_helper_proc_t *mowgli_eventloop_io_helper(mowgli_eventloop_io_t *io) +static inline mowgli_eventloop_helper_proc_t * +mowgli_eventloop_io_helper(mowgli_eventloop_io_t *io) { mowgli_eventloop_io_obj_t *obj = (mowgli_eventloop_io_obj_t *) io; @@ -77,7 +89,8 @@ static inline mowgli_eventloop_helper_proc_t *mowgli_eventloop_io_helper(mowgli_ return (mowgli_eventloop_helper_proc_t *) io; } -static inline mowgli_eventloop_io_type_t mowgli_eventloop_io_type(mowgli_eventloop_io_t *io) +static inline mowgli_eventloop_io_type_t +mowgli_eventloop_io_type(mowgli_eventloop_io_t *io) { mowgli_eventloop_io_obj_t *obj = (mowgli_eventloop_io_obj_t *) io; @@ -86,9 +99,10 @@ static inline mowgli_eventloop_io_type_t mowgli_eventloop_io_type(mowgli_eventlo return obj->type; } -typedef void mowgli_eventloop_io_cb_t(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata); +typedef void mowgli_eventloop_io_cb_t (mowgli_eventloop_t * eventloop, mowgli_eventloop_io_t * io, mowgli_eventloop_io_dir_t dir, void *userdata); -struct _mowgli_pollable { +struct _mowgli_pollable +{ mowgli_eventloop_io_obj_t type; mowgli_descriptor_t fd; @@ -106,7 +120,8 @@ struct _mowgli_pollable { mowgli_eventloop_t *eventloop; }; -typedef struct { +typedef struct +{ void (*timeout_once)(mowgli_eventloop_t *eventloop, int timeout); void (*run_once)(mowgli_eventloop_t *eventloop); void (*pollsetup)(mowgli_eventloop_t *eventloop); @@ -116,7 +131,8 @@ typedef struct { void (*destroy)(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable); } mowgli_eventloop_ops_t; -struct _mowgli_eventloop { +struct _mowgli_eventloop +{ time_t currtime; time_t deadline; @@ -131,41 +147,124 @@ struct _mowgli_eventloop { bool death_requested; void *data; + + time_t epochbias; }; -typedef void mowgli_event_dispatch_func_t(void *userdata); +typedef void mowgli_event_dispatch_func_t (void *userdata); -typedef struct { +typedef struct +{ mowgli_node_t node; mowgli_event_dispatch_func_t *func; void *arg; const char *name; time_t frequency; - time_t when; + time_t deadline; bool active; } mowgli_eventloop_timer_t; -static inline void mowgli_eventloop_set_time(mowgli_eventloop_t *eventloop, time_t newtime) +static inline void +mowgli_eventloop_set_time(mowgli_eventloop_t *eventloop, time_t newtime) { return_if_fail(eventloop != NULL); eventloop->currtime = newtime; } -static inline time_t mowgli_eventloop_get_time(mowgli_eventloop_t *eventloop) +static inline time_t +mowgli_eventloop_get_time(mowgli_eventloop_t *eventloop) { return_val_if_fail(eventloop != NULL, 0); - return eventloop->currtime; + return eventloop->epochbias + eventloop->currtime; } -static inline void mowgli_eventloop_synchronize(mowgli_eventloop_t *eventloop) +static inline void +mowgli_eventloop_synchronize(mowgli_eventloop_t *eventloop) { - mowgli_eventloop_set_time(eventloop, time(NULL)); + long long time_; + +#if defined(CLOCK_MONOTONIC) + struct timespec tp; + + clock_gettime(CLOCK_MONOTONIC, &tp); + time_ = tp.tv_sec; +#elif defined(CLOCK_HIGHRES) + struct timespec tp; + + clock_gettime(CLOCK_HIGHRES, &tp); + time_ = tp.tv_sec; +#elif defined(MOWGLI_OS_WIN) + static ULONGLONG (CALLBACK *GetTickCount64)(void) = NULL; + static OSVERSIONINFOEX *winver = NULL; + static bool load_err = false; + + if (winver == NULL) + { + winver = mowgli_alloc(sizeof(OSVERSIONINFOEX)); + winver->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + if (!GetVersionEx((OSVERSIONINFO *) winver)) + { + mowgli_free(winver); + winver = NULL; /* FIXME */ + } + } + + if (winver && (winver->dwMajorVersion >= 6)) + { + if ((GetTickCount64 == NULL) && !load_err) + { + HINSTANCE hKernel32; + + hKernel32 = GetModuleHandle("KERNEL32"); + GetTickCount64 = GetProcAddress(hKernel32, "GetTickCount64"); + + if (GetTickCount64 == NULL) + load_err = true; + } + + if (load_err) + { + time_ = time(NULL); + } + else + { + soft_assert(GetTickCount64 != NULL); + + time_ = (int) (GetTickCount64() * 1e-3); + } + } + else + { + time_ = time(NULL); + } + +#elif defined(MOWGLI_OS_OSX) + static mach_timebase_info_data_t timebase; + + if (timebase.denom == 0) + mach_timebase_info(&timebase); + + time_ = (int) (mach_absolute_time() * timebase.numer / timebase.denom * 1e-9); +#else + time_ = time(NULL); +#endif + mowgli_eventloop_set_time(eventloop, (time_t) time_); +} + +/* Sets the bias of eventloop->currtime relative to Jan 1 00:00:00 1970 */ +static inline void +mowgli_eventloop_calibrate(mowgli_eventloop_t *eventloop) +{ + mowgli_eventloop_synchronize(eventloop); + eventloop->epochbias = time(NULL) - eventloop->currtime; } -static inline bool mowgli_eventloop_ignore_errno(int error) +static inline bool +mowgli_eventloop_ignore_errno(int error) { switch (error) { @@ -178,6 +277,9 @@ static inline bool mowgli_eventloop_ignore_errno(int error) #if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN) case EAGAIN: #endif +#ifdef ETIME + case ETIME: +#endif #ifdef EINTR case EINTR: #endif @@ -198,9 +300,10 @@ static inline bool mowgli_eventloop_ignore_errno(int error) return false; } -typedef void mowgli_eventloop_helper_start_fn_t(mowgli_eventloop_helper_proc_t *helper, void *userdata); +typedef void mowgli_eventloop_helper_start_fn_t (mowgli_eventloop_helper_proc_t * helper, void *userdata); -struct _mowgli_helper { +struct _mowgli_helper +{ mowgli_eventloop_io_obj_t type; mowgli_process_t *child; @@ -254,6 +357,7 @@ extern mowgli_eventloop_pollable_t *mowgli_pollable_create(mowgli_eventloop_t *e extern void mowgli_pollable_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable); extern void mowgli_pollable_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function); extern void mowgli_pollable_set_nonblocking(mowgli_eventloop_pollable_t *pollable, bool nonblocking); +extern void mowgli_pollable_set_cloexec(mowgli_eventloop_pollable_t *pollable, bool cloexec); +extern void mowgli_pollable_trigger(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir); #endif - diff --git a/src/libmowgli/eventloop/helper.c b/src/libmowgli/eventloop/helper.c index b89e447..5acc5f0 100644 --- a/src/libmowgli/eventloop/helper.c +++ b/src/libmowgli/eventloop/helper.c @@ -20,7 +20,8 @@ #include "mowgli.h" -typedef struct { +typedef struct +{ mowgli_eventloop_helper_start_fn_t *start_fn; void *userdata; mowgli_descriptor_t fd; @@ -30,6 +31,7 @@ static void mowgli_helper_trampoline(mowgli_helper_create_req_t *req) { mowgli_eventloop_helper_proc_t *helper; + #ifndef _WIN32 int i, x; #endif @@ -42,22 +44,20 @@ mowgli_helper_trampoline(mowgli_helper_create_req_t *req) helper->fd = req->fd; #ifndef _WIN32 + for (i = 0; i < 1024; i++) - { if (i != req->fd) close(i); - } x = open("/dev/null", O_RDWR); for (i = 0; i < 2; i++) - { if (req->fd != i) dup2(x, i); - } if (x > 2) close(x); + #endif helper->eventloop = mowgli_eventloop_create(); @@ -194,10 +194,16 @@ mowgli_helper_io_trampoline(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t { mowgli_eventloop_helper_proc_t *helper = userdata; - switch (dir) { + switch (dir) + { case MOWGLI_EVENTLOOP_IO_READ: + if (helper->read_function != NULL) - return helper->read_function(eventloop, helper, MOWGLI_EVENTLOOP_IO_READ, helper->userdata); + { + helper->read_function(eventloop, helper, MOWGLI_EVENTLOOP_IO_READ, helper->userdata); + return; + } + default: break; } diff --git a/src/libmowgli/eventloop/kqueue_pollops.c b/src/libmowgli/eventloop/kqueue_pollops.c index 7bfa2bb..113d7b3 100644 --- a/src/libmowgli/eventloop/kqueue_pollops.c +++ b/src/libmowgli/eventloop/kqueue_pollops.c @@ -23,15 +23,17 @@ #ifdef HAVE_KQUEUE -#include +# include -typedef struct { +typedef struct +{ int kqueue_fd; int nevents; struct kevent *events; } mowgli_kqueue_eventloop_private_t; -static void mowgli_kqueue_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +static void +mowgli_kqueue_eventloop_pollsetup(mowgli_eventloop_t *eventloop) { mowgli_kqueue_eventloop_private_t *priv; @@ -42,10 +44,14 @@ static void mowgli_kqueue_eventloop_pollsetup(mowgli_eventloop_t *eventloop) priv->kqueue_fd = kqueue(); priv->events = mowgli_alloc(sizeof(struct kevent) * priv->nevents); + /* attempt to set the fd as close-on-exec, but ignore errors */ + fcntl(priv->kqueue_fd, F_SETFD, FD_CLOEXEC); + return; } -static void mowgli_kqueue_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +static void +mowgli_kqueue_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) { mowgli_kqueue_eventloop_private_t *priv; @@ -60,7 +66,8 @@ static void mowgli_kqueue_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) return; } -static void mowgli_kqueue_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +static void +mowgli_kqueue_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) { mowgli_kqueue_eventloop_private_t *priv; struct kevent event; @@ -71,19 +78,20 @@ static void mowgli_kqueue_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgl priv = eventloop->poller; EV_SET(&event, pollable->fd, EVFILT_READ | EVFILT_WRITE, EV_DELETE, 0, 0, pollable); + if (kevent(priv->kqueue_fd, &event, 1, NULL, 0, - &(const struct timespec){ .tv_sec = 0, .tv_nsec = 0} - ) != 0) - { + &(const struct timespec) { .tv_sec = 0, .tv_nsec = 0 } + ) != 0) mowgli_log("mowgli_kqueue_eventloop_setselect(): kevent failed: %d (%s)", errno, strerror(errno)); - } } -static void mowgli_kqueue_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +static void +mowgli_kqueue_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) { mowgli_kqueue_eventloop_private_t *priv; mowgli_eventloop_io_cb_t **fptr; struct kevent event; + int filter; bool change; @@ -93,9 +101,9 @@ static void mowgli_kqueue_eventloop_setselect(mowgli_eventloop_t *eventloop, mow priv = eventloop->poller; change = false; -#ifdef DEBUG +# ifdef DEBUG mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); -#endif +# endif switch (dir) { @@ -119,21 +127,21 @@ static void mowgli_kqueue_eventloop_setselect(mowgli_eventloop_t *eventloop, mow if (!change) return; -#ifdef DEBUG +# ifdef DEBUG mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); -#endif +# endif EV_SET(&event, pollable->fd, filter, - event_function ? EV_ADD : EV_DELETE, 0, 0, pollable); + event_function ? EV_ADD : EV_DELETE, 0, 0, pollable); + if (kevent(priv->kqueue_fd, &event, 1, NULL, 0, - &(const struct timespec){ .tv_sec = 0, .tv_nsec = 0} - ) != 0) - { + &(const struct timespec) { .tv_sec = 0, .tv_nsec = 0 } + ) != 0) mowgli_log("mowgli_kqueue_eventloop_setselect(): kevent failed: %d (%s)", errno, strerror(errno)); - } } -static void mowgli_kqueue_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +static void +mowgli_kqueue_eventloop_select(mowgli_eventloop_t *eventloop, int delay) { mowgli_kqueue_eventloop_private_t *priv; int i, num, o_errno; @@ -143,8 +151,8 @@ static void mowgli_kqueue_eventloop_select(mowgli_eventloop_t *eventloop, int de priv = eventloop->poller; num = kevent(priv->kqueue_fd, NULL, 0, priv->events, priv->nevents, - delay >= 0 ? &(const struct timespec){ .tv_sec = delay / 1000, - .tv_nsec = delay % 1000 * 1000000 } : NULL); + delay >= 0 ? &(const struct timespec) { .tv_sec = delay / 1000, + .tv_nsec = delay % 1000 * 1000000 } : NULL); o_errno = errno; mowgli_eventloop_synchronize(eventloop); @@ -162,13 +170,11 @@ static void mowgli_kqueue_eventloop_select(mowgli_eventloop_t *eventloop, int de { mowgli_eventloop_pollable_t *pollable = priv->events[i].udata; - if (priv->events[i].filter == EVFILT_READ && - pollable->read_function != NULL) - pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + if (priv->events[i].filter == EVFILT_READ) + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ); - if (priv->events[i].filter == EVFILT_WRITE && - pollable->write_function != NULL) - pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + if (priv->events[i].filter == EVFILT_WRITE) + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE); /* XXX Perhaps we need to recheck read_function and * write_function now. @@ -176,7 +182,8 @@ static void mowgli_kqueue_eventloop_select(mowgli_eventloop_t *eventloop, int de } } -mowgli_eventloop_ops_t _mowgli_kqueue_pollops = { +mowgli_eventloop_ops_t _mowgli_kqueue_pollops = +{ .timeout_once = mowgli_simple_eventloop_timeout_once, .run_once = mowgli_simple_eventloop_run_once, .pollsetup = mowgli_kqueue_eventloop_pollsetup, diff --git a/src/libmowgli/eventloop/null_pollops.c b/src/libmowgli/eventloop/null_pollops.c index 8fcabe4..7788aec 100644 --- a/src/libmowgli/eventloop/null_pollops.c +++ b/src/libmowgli/eventloop/null_pollops.c @@ -20,7 +20,8 @@ #include "mowgli.h" -void mowgli_simple_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int timeout) +void +mowgli_simple_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int timeout) { time_t delay, currtime; int t; @@ -33,7 +34,7 @@ void mowgli_simple_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int tim currtime = mowgli_eventloop_get_time(eventloop); delay = mowgli_eventloop_next_timer(eventloop); - if (delay <= currtime) + while (delay != -1 && delay <= currtime) { mowgli_eventloop_run_timers(eventloop); mowgli_eventloop_synchronize(eventloop); @@ -44,28 +45,26 @@ void mowgli_simple_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int tim if (timeout) t = timeout; + else if (delay == -1) + t = 5000; /* arbitrary 5 second default timeout */ else - { - if (delay <= currtime) - t = -1; - else - t = (delay - currtime) * 1000; - } + t = (delay - currtime) * 1000; #ifdef DEBUG mowgli_log("delay: %ld, currtime: %ld, select period: %d", delay, currtime, t); #endif eventloop->eventloop_ops->select(eventloop, t); - } -void mowgli_simple_eventloop_run_once(mowgli_eventloop_t *eventloop) +void +mowgli_simple_eventloop_run_once(mowgli_eventloop_t *eventloop) { eventloop->eventloop_ops->timeout_once(eventloop, 0); } -void mowgli_simple_eventloop_error_handler(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +void +mowgli_simple_eventloop_error_handler(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) { mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(io); @@ -73,24 +72,28 @@ void mowgli_simple_eventloop_error_handler(mowgli_eventloop_t *eventloop, mowgli mowgli_pollable_destroy(eventloop, pollable); } -static void mowgli_null_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +static void +mowgli_null_eventloop_pollsetup(mowgli_eventloop_t *eventloop) { return; } -static void mowgli_null_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +static void +mowgli_null_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) { return; } -static void mowgli_null_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +static void +mowgli_null_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) { return; } -static void mowgli_null_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +static void +mowgli_null_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) { - mowgli_log("null eventloop does not really do polling, events for pollable<%p> will be ignored", pollable); + mowgli_log("null eventloop does not really do polling, events for pollable<%p> will be ignored", (void *) pollable); switch (dir) { @@ -108,12 +111,16 @@ static void mowgli_null_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgl return; } -static void mowgli_null_eventloop_select(mowgli_eventloop_t *eventloop, int time) +static void +mowgli_null_eventloop_select(mowgli_eventloop_t *eventloop, int time) { + for (; time > 999999; time -= 999999) + usleep(999999); usleep(time); } -mowgli_eventloop_ops_t _mowgli_null_pollops = { +mowgli_eventloop_ops_t _mowgli_null_pollops = +{ .timeout_once = mowgli_simple_eventloop_timeout_once, .run_once = mowgli_simple_eventloop_run_once, .pollsetup = mowgli_null_eventloop_pollsetup, diff --git a/src/libmowgli/eventloop/poll_pollops.c b/src/libmowgli/eventloop/poll_pollops.c index 0bea454..6c5d7e5 100644 --- a/src/libmowgli/eventloop/poll_pollops.c +++ b/src/libmowgli/eventloop/poll_pollops.c @@ -22,22 +22,25 @@ #ifdef HAVE_POLL_H -#include +# include -#ifndef POLLRDNORM -#define POLLRDNORM POLLIN -#endif -#ifndef POLLWRNORM -#define POLLWRNORM POLLOUT -#endif +# ifndef POLLRDNORM +# define POLLRDNORM POLLIN +# endif +# ifndef POLLWRNORM +# define POLLWRNORM POLLOUT +# endif -typedef struct { +typedef struct +{ struct pollfd pollfds[FD_SETSIZE]; + nfds_t nfds; mowgli_list_t pollable_list; } mowgli_poll_eventloop_private_t; -static nfds_t update_poll_fds(mowgli_eventloop_t *eventloop) +static nfds_t +update_poll_fds(mowgli_eventloop_t *eventloop) { mowgli_node_t *n, *tn; mowgli_poll_eventloop_private_t *priv; @@ -49,13 +52,13 @@ static nfds_t update_poll_fds(mowgli_eventloop_t *eventloop) memset(priv->pollfds, '\0', sizeof(priv->pollfds)); - MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) - { + MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) + { mowgli_eventloop_pollable_t *pollable = n->data; -#ifdef DEBUG +# ifdef DEBUG mowgli_log("considering fd %d pollable %p count %d", pollable->fd, pollable, priv->pollable_list.count); -#endif +# endif if (pollable->read_function || pollable->write_function) { @@ -72,13 +75,16 @@ static nfds_t update_poll_fds(mowgli_eventloop_t *eventloop) slot++; } else + { pollable->slot = -1; + } } - return slot; + return slot; } -static void mowgli_poll_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +static void +mowgli_poll_eventloop_pollsetup(mowgli_eventloop_t *eventloop) { mowgli_poll_eventloop_private_t *priv; @@ -88,7 +94,8 @@ static void mowgli_poll_eventloop_pollsetup(mowgli_eventloop_t *eventloop) return; } -static void mowgli_poll_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +static void +mowgli_poll_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) { mowgli_node_t *n, *tn; mowgli_poll_eventloop_private_t *priv; @@ -106,7 +113,8 @@ static void mowgli_poll_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) return; } -static void mowgli_poll_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +static void +mowgli_poll_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) { mowgli_poll_eventloop_private_t *priv; @@ -118,7 +126,8 @@ static void mowgli_poll_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_ mowgli_node_delete(&pollable->node, &priv->pollable_list); } -static void mowgli_poll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +static void +mowgli_poll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) { mowgli_poll_eventloop_private_t *priv; @@ -127,9 +136,9 @@ static void mowgli_poll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgl priv = eventloop->poller; -#ifdef DEBUG +# ifdef DEBUG mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); -#endif +# endif if (pollable->read_function || pollable->write_function) mowgli_node_delete(&pollable->node, &priv->pollable_list); @@ -147,9 +156,9 @@ static void mowgli_poll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgl break; } -#ifdef DEBUG +# ifdef DEBUG mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); -#endif +# endif if (pollable->read_function || pollable->write_function) mowgli_node_add(pollable, &pollable->node, &priv->pollable_list); @@ -157,7 +166,8 @@ static void mowgli_poll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgl return; } -static void mowgli_poll_eventloop_select(mowgli_eventloop_t *eventloop, int time) +static void +mowgli_poll_eventloop_select(mowgli_eventloop_t *eventloop, int time) { mowgli_node_t *n, *tn; nfds_t nfds; @@ -181,17 +191,17 @@ static void mowgli_poll_eventloop_select(mowgli_eventloop_t *eventloop, int time pollable = n->data; slot = pollable->slot; - if (slot == -1 || priv->pollfds[slot].revents == 0) + if ((slot == -1) || (priv->pollfds[slot].revents == 0)) continue; if (priv->pollfds[slot].revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR) && pollable->read_function) { -#ifdef DEBUG +# ifdef DEBUG mowgli_log("run %p(%p, %p, MOWGLI_EVENTLOOP_IO_READ, %p)\n", pollable->read_function, eventloop, pollable, pollable->userdata); -#endif +# endif priv->pollfds[slot].events &= ~(POLLRDNORM | POLLIN); - pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ); } } @@ -200,23 +210,24 @@ static void mowgli_poll_eventloop_select(mowgli_eventloop_t *eventloop, int time pollable = n->data; slot = pollable->slot; - if (slot == -1 || priv->pollfds[slot].revents == 0) + if ((slot == -1) || (priv->pollfds[slot].revents == 0)) continue; if (priv->pollfds[slot].revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR) && pollable->write_function) { -#ifdef DEBUG +# ifdef DEBUG mowgli_log("run %p(%p, %p, MOWGLI_EVENTLOOP_IO_WRITE, %p)\n", pollable->write_function, eventloop, pollable, pollable->userdata); -#endif +# endif priv->pollfds[slot].events &= ~(POLLWRNORM | POLLOUT); - pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE); } } } } -mowgli_eventloop_ops_t _mowgli_poll_pollops = { +mowgli_eventloop_ops_t _mowgli_poll_pollops = +{ .timeout_once = mowgli_simple_eventloop_timeout_once, .run_once = mowgli_simple_eventloop_run_once, .pollsetup = mowgli_poll_eventloop_pollsetup, diff --git a/src/libmowgli/eventloop/pollable.c b/src/libmowgli/eventloop/pollable.c index e2c2e2a..5f9526e 100644 --- a/src/libmowgli/eventloop/pollable.c +++ b/src/libmowgli/eventloop/pollable.c @@ -22,7 +22,8 @@ static mowgli_heap_t *pollable_heap = NULL; -mowgli_eventloop_pollable_t *mowgli_pollable_create(mowgli_eventloop_t *eventloop, mowgli_descriptor_t fd, void *userdata) +mowgli_eventloop_pollable_t * +mowgli_pollable_create(mowgli_eventloop_t *eventloop, mowgli_descriptor_t fd, void *userdata) { mowgli_eventloop_pollable_t *pollable; @@ -41,7 +42,8 @@ mowgli_eventloop_pollable_t *mowgli_pollable_create(mowgli_eventloop_t *eventloo return pollable; } -void mowgli_pollable_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +void +mowgli_pollable_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) { return_if_fail(eventloop != NULL); return_if_fail(pollable != NULL); @@ -52,7 +54,8 @@ void mowgli_pollable_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pol mowgli_heap_free(pollable_heap, pollable); } -void mowgli_pollable_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +void +mowgli_pollable_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) { return_if_fail(eventloop != NULL); return_if_fail(pollable != NULL); @@ -61,7 +64,8 @@ void mowgli_pollable_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_p eventloop->eventloop_ops->setselect(eventloop, pollable, dir, event_function); } -void mowgli_pollable_set_nonblocking(mowgli_eventloop_pollable_t *pollable, bool nonblocking) +void +mowgli_pollable_set_nonblocking(mowgli_eventloop_pollable_t *pollable, bool nonblocking) { #if defined(HAVE_FCNTL) unsigned long flags; @@ -86,3 +90,53 @@ void mowgli_pollable_set_nonblocking(mowgli_eventloop_pollable_t *pollable, bool ioctlsocket(pollable->fd, FIONBIO, &mode); #endif } + +void +mowgli_pollable_set_cloexec(mowgli_eventloop_pollable_t *pollable, bool cloexec) +{ +#if defined(FD_CLOEXEC) + unsigned long flags; + + return_if_fail(pollable != NULL); + + flags = fcntl(pollable->fd, F_GETFD); + + if (cloexec) + flags |= FD_CLOEXEC; + else + flags &= ~FD_CLOEXEC; + + fcntl(pollable->fd, F_SETFD, flags); +#elif defined(HAVE_WINSOCK2_H) + return_if_fail(pollable != NULL); + + SetHandleInformation((HANDLE)pollable->fd, HANDLE_FLAG_INHERIT, !cloexec); +#endif +} + +void +mowgli_pollable_trigger(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir) +{ + mowgli_eventloop_io_cb_t *event_function; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + switch (dir) + { + case MOWGLI_EVENTLOOP_IO_READ: + event_function = pollable->read_function; + break; + case MOWGLI_EVENTLOOP_IO_WRITE: + event_function = pollable->write_function; + break; + default: + event_function = NULL; + return; + } + + if (event_function == NULL) + return; + + event_function(eventloop, pollable, dir, pollable->userdata); +} diff --git a/src/libmowgli/eventloop/ports_pollops.c b/src/libmowgli/eventloop/ports_pollops.c index bc838da..0c68fd5 100644 --- a/src/libmowgli/eventloop/ports_pollops.c +++ b/src/libmowgli/eventloop/ports_pollops.c @@ -22,15 +22,17 @@ #ifdef HAVE_PORT_CREATE -#include +# include -typedef struct { +typedef struct +{ int port_fd; int pfd_size; port_event_t *pfd; } mowgli_ports_eventloop_private_t; -static void mowgli_ports_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +static void +mowgli_ports_eventloop_pollsetup(mowgli_eventloop_t *eventloop) { mowgli_ports_eventloop_private_t *priv; @@ -44,7 +46,8 @@ static void mowgli_ports_eventloop_pollsetup(mowgli_eventloop_t *eventloop) return; } -static void mowgli_ports_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +static void +mowgli_ports_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) { mowgli_ports_eventloop_private_t *priv; @@ -59,7 +62,8 @@ static void mowgli_ports_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) return; } -static void mowgli_ports_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +static void +mowgli_ports_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) { mowgli_ports_eventloop_private_t *priv; @@ -78,7 +82,8 @@ static void mowgli_ports_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli } } -static void mowgli_ports_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +static void +mowgli_ports_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) { mowgli_ports_eventloop_private_t *priv; unsigned int old_flags; @@ -89,9 +94,9 @@ static void mowgli_ports_eventloop_setselect(mowgli_eventloop_t *eventloop, mowg priv = eventloop->poller; old_flags = pollable->slot; -#ifdef DEBUG +# ifdef DEBUG mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); -#endif +# endif switch (dir) { @@ -108,9 +113,9 @@ static void mowgli_ports_eventloop_setselect(mowgli_eventloop_t *eventloop, mowg break; } -#ifdef DEBUG +# ifdef DEBUG mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); -#endif +# endif if (pollable->read_function == NULL) pollable->slot &= ~POLLIN; @@ -118,8 +123,10 @@ static void mowgli_ports_eventloop_setselect(mowgli_eventloop_t *eventloop, mowg if (pollable->write_function == NULL) pollable->slot &= ~POLLOUT; - if (old_flags == 0 && pollable->slot == 0) + if ((old_flags == 0) && (pollable->slot == 0)) + { return; + } else if (pollable->slot == 0) { port_dissociate(priv->port_fd, PORT_SOURCE_FD, (uintptr_t) pollable->fd); @@ -137,24 +144,25 @@ static void mowgli_ports_eventloop_setselect(mowgli_eventloop_t *eventloop, mowg return; } -static void mowgli_ports_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +static void +mowgli_ports_eventloop_select(mowgli_eventloop_t *eventloop, int delay) { mowgli_ports_eventloop_private_t *priv; - int i, num, o_errno, nget = 1; + int i, ret, o_errno, nget = 1; return_if_fail(eventloop != NULL); priv = eventloop->poller; - num = port_getn(priv->port_fd, priv->pfd, priv->pfd_size, &nget, - delay >= 0 ? &(struct timespec){ .tv_sec = delay / 1000, .tv_nsec = delay % 1000 * 1000000 } : NULL); + ret = port_getn(priv->port_fd, priv->pfd, priv->pfd_size, &nget, + delay >= 0 ? &(struct timespec) { .tv_sec = delay / 1000, .tv_nsec = delay % 1000 * 1000000 } : NULL); o_errno = errno; mowgli_eventloop_synchronize(eventloop); - if (num < 0) + if (ret == -1) { - if (mowgli_eventloop_ignore_errno(errno)) + if (mowgli_eventloop_ignore_errno(o_errno)) return; mowgli_log("mowgli_ports_eventloop_select(): port_getn failed: %d (%s)", o_errno, strerror(o_errno)); @@ -165,15 +173,19 @@ static void mowgli_ports_eventloop_select(mowgli_eventloop_t *eventloop, int del { mowgli_eventloop_pollable_t *pollable = priv->pfd[i].portev_user; - if (priv->pfd[i].portev_events & (POLLIN | POLLHUP | POLLERR) && pollable->read_function != NULL) - pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + if (priv->pfd[i].portev_source != PORT_SOURCE_FD) + continue; - if (priv->pfd[i].portev_events & (POLLOUT | POLLHUP | POLLERR) && pollable->write_function != NULL) - pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + if (priv->pfd[i].portev_events & (POLLIN | POLLHUP | POLLERR)) + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ); + + if (priv->pfd[i].portev_events & (POLLOUT | POLLHUP | POLLERR)) + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE); } } -mowgli_eventloop_ops_t _mowgli_ports_pollops = { +mowgli_eventloop_ops_t _mowgli_ports_pollops = +{ .timeout_once = mowgli_simple_eventloop_timeout_once, .run_once = mowgli_simple_eventloop_run_once, .pollsetup = mowgli_ports_eventloop_pollsetup, diff --git a/src/libmowgli/eventloop/qnx_pollops.c b/src/libmowgli/eventloop/qnx_pollops.c index 7417ef4..6c114d5 100644 --- a/src/libmowgli/eventloop/qnx_pollops.c +++ b/src/libmowgli/eventloop/qnx_pollops.c @@ -22,15 +22,17 @@ #ifdef HAVE_DISPATCH_BLOCK -#include -#include +# include +# include -typedef struct { +typedef struct +{ dispatch_t *dpp; dispatch_context_t *ctp; } mowgli_qnx_eventloop_private_t; -static void mowgli_qnx_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +static void +mowgli_qnx_eventloop_pollsetup(mowgli_eventloop_t *eventloop) { mowgli_qnx_eventloop_private_t *priv; @@ -42,7 +44,8 @@ static void mowgli_qnx_eventloop_pollsetup(mowgli_eventloop_t *eventloop) return; } -static void mowgli_qnx_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +static void +mowgli_qnx_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) { mowgli_qnx_eventloop_private_t *priv; @@ -59,7 +62,8 @@ static void mowgli_qnx_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) return; } -static void mowgli_qnx_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +static void +mowgli_qnx_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) { mowgli_qnx_eventloop_private_t *priv; @@ -77,7 +81,8 @@ static void mowgli_qnx_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_e } } -static void mowgli_qnx_eventloop_event_cb(select_context_t *ctp, mowgli_descriptor_t fd, unsigned int flags, void *userdata) +static void +mowgli_qnx_eventloop_event_cb(select_context_t *ctp, mowgli_descriptor_t fd, unsigned int flags, void *userdata) { mowgli_eventloop_t *eventloop; mowgli_eventloop_pollable_t *pollable; @@ -91,16 +96,17 @@ static void mowgli_qnx_eventloop_event_cb(select_context_t *ctp, mowgli_descript return_if_fail(eventloop != NULL); if (flags & (SELECT_FLAG_READ | SELECT_FLAG_EXCEPT)) - pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ); if (flags & (SELECT_FLAG_WRITE | SELECT_FLAG_EXCEPT)) - pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE); } -static void mowgli_qnx_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +static void +mowgli_qnx_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) { mowgli_qnx_eventloop_private_t *priv; - select_attr_t attr = {}; + select_attr_t attr = { }; unsigned int old_flags; return_if_fail(eventloop != NULL); @@ -109,9 +115,9 @@ static void mowgli_qnx_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli priv = eventloop->poller; old_flags = pollable->slot; -#ifdef DEBUG +# ifdef DEBUG mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); -#endif +# endif switch (dir) { @@ -128,9 +134,9 @@ static void mowgli_qnx_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli break; } -#ifdef DEBUG +# ifdef DEBUG mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); -#endif +# endif if (pollable->read_function == NULL) pollable->slot &= ~SELECT_FLAG_READ; @@ -138,14 +144,13 @@ static void mowgli_qnx_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli if (pollable->write_function == NULL) pollable->slot &= ~SELECT_FLAG_WRITE; - if (old_flags == 0 && pollable->slot == 0) + if ((old_flags == 0) && (pollable->slot == 0)) return; if (old_flags) select_detach(priv->dpp, pollable->fd); if (pollable->slot) - { if (select_attach(priv->dpp, &attr, pollable->fd, pollable->slot, mowgli_qnx_eventloop_event_cb, pollable) != 0) { if (mowgli_eventloop_ignore_errno(errno)) @@ -153,12 +158,12 @@ static void mowgli_qnx_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli mowgli_log("mowgli_qnx_eventloop_setselect(): select_attach failed: %d (%s)", errno, strerror(errno)); } - } return; } -static void mowgli_qnx_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +static void +mowgli_qnx_eventloop_select(mowgli_eventloop_t *eventloop, int delay) { dispatch_context_t *new_ctp; mowgli_qnx_eventloop_private_t *priv; @@ -168,14 +173,16 @@ static void mowgli_qnx_eventloop_select(mowgli_eventloop_t *eventloop, int delay priv = eventloop->poller; /* set timeout if needed */ - dispatch_timeout(priv->dpp, delay >= 0 ? &(struct timespec){ .tv_sec = delay / 1000, .tv_nsec = delay % 1000 * 1000000 } : NULL); + dispatch_timeout(priv->dpp, delay >= 0 ? &(struct timespec) { .tv_sec = delay / 1000, .tv_nsec = delay % 1000 * 1000000 } : NULL); if (priv->ctp != NULL) priv->ctp = dispatch_context_alloc(priv->dpp); /* if dispatch_block returns non-NULL, priv->ctp may have been realloc()'d, NULL is error condition */ if ((new_ctp = dispatch_block(priv->ctp)) != NULL) + { priv->ctp = new_ctp; + } else { if (mowgli_eventloop_ignore_errno(errno)) @@ -187,7 +194,8 @@ static void mowgli_qnx_eventloop_select(mowgli_eventloop_t *eventloop, int delay mowgli_eventloop_synchronize(eventloop); } -mowgli_eventloop_ops_t _mowgli_qnx_pollops = { +mowgli_eventloop_ops_t _mowgli_qnx_pollops = +{ .timeout_once = mowgli_simple_eventloop_timeout_once, .run_once = mowgli_simple_eventloop_run_once, .pollsetup = mowgli_qnx_eventloop_pollsetup, diff --git a/src/libmowgli/eventloop/select_pollops.c b/src/libmowgli/eventloop/select_pollops.c index 467b4f5..ee5a966 100644 --- a/src/libmowgli/eventloop/select_pollops.c +++ b/src/libmowgli/eventloop/select_pollops.c @@ -22,15 +22,17 @@ #ifdef HAVE_SELECT -#ifdef HAVE_SYS_SELECT_H -# include -#endif +# ifdef HAVE_SYS_SELECT_H +# include +# endif -typedef struct { +typedef struct +{ mowgli_list_t pollable_list; } mowgli_select_eventloop_private_t; -static void mowgli_select_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +static void +mowgli_select_eventloop_pollsetup(mowgli_eventloop_t *eventloop) { mowgli_select_eventloop_private_t *priv; @@ -40,7 +42,8 @@ static void mowgli_select_eventloop_pollsetup(mowgli_eventloop_t *eventloop) return; } -static void mowgli_select_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +static void +mowgli_select_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) { mowgli_node_t *n, *tn; mowgli_select_eventloop_private_t *priv; @@ -58,7 +61,8 @@ static void mowgli_select_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) return; } -static void mowgli_select_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +static void +mowgli_select_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) { mowgli_select_eventloop_private_t *priv; @@ -70,7 +74,8 @@ static void mowgli_select_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgl mowgli_node_delete(&pollable->node, &priv->pollable_list); } -static void mowgli_select_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +static void +mowgli_select_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) { mowgli_select_eventloop_private_t *priv; @@ -79,9 +84,9 @@ static void mowgli_select_eventloop_setselect(mowgli_eventloop_t *eventloop, mow priv = eventloop->poller; -#ifdef DEBUG +# ifdef DEBUG mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); -#endif +# endif if (pollable->read_function || pollable->write_function) mowgli_node_delete(&pollable->node, &priv->pollable_list); @@ -99,9 +104,9 @@ static void mowgli_select_eventloop_setselect(mowgli_eventloop_t *eventloop, mow break; } -#ifdef DEBUG +# ifdef DEBUG mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); -#endif +# endif if (pollable->read_function || pollable->write_function) mowgli_node_add(pollable, &pollable->node, &priv->pollable_list); @@ -109,7 +114,8 @@ static void mowgli_select_eventloop_setselect(mowgli_eventloop_t *eventloop, mow return; } -static void mowgli_select_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +static void +mowgli_select_eventloop_select(mowgli_eventloop_t *eventloop, int delay) { mowgli_node_t *n, *tn; mowgli_eventloop_pollable_t *pollable; @@ -126,13 +132,13 @@ static void mowgli_select_eventloop_select(mowgli_eventloop_t *eventloop, int de FD_ZERO(&wfds); FD_ZERO(&efds); - MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) - { + MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) + { mowgli_eventloop_pollable_t *pollable = n->data; -#ifdef DEBUG +# ifdef DEBUG mowgli_log("considering fd %d pollable %p count %d", pollable->fd, pollable, priv->pollable_list.count); -#endif +# endif if (pollable->read_function || pollable->write_function) { @@ -164,13 +170,13 @@ static void mowgli_select_eventloop_select(mowgli_eventloop_t *eventloop, int de { pollable = n->data; - if ((FD_ISSET(pollable->fd, &rfds) || FD_ISSET(pollable->fd, &efds)) && pollable->read_function) + if ((FD_ISSET(pollable->fd, &rfds) || FD_ISSET(pollable->fd, &efds))) { -#ifdef DEBUG +# ifdef DEBUG mowgli_log("run %p(%p, %p, MOWGLI_EVENTLOOP_IO_READ, %p)\n", pollable->read_function, eventloop, pollable, pollable->userdata); -#endif +# endif - pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ); } } @@ -178,19 +184,20 @@ static void mowgli_select_eventloop_select(mowgli_eventloop_t *eventloop, int de { pollable = n->data; - if ((FD_ISSET(pollable->fd, &wfds) || FD_ISSET(pollable->fd, &efds)) && pollable->write_function) + if ((FD_ISSET(pollable->fd, &wfds) || FD_ISSET(pollable->fd, &efds))) { -#ifdef DEBUG +# ifdef DEBUG mowgli_log("run %p(%p, %p, MOWGLI_EVENTLOOP_IO_WRITE, %p)\n", pollable->write_function, eventloop, pollable, pollable->userdata); -#endif +# endif - pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE); } } } } -mowgli_eventloop_ops_t _mowgli_select_pollops = { +mowgli_eventloop_ops_t _mowgli_select_pollops = +{ .timeout_once = mowgli_simple_eventloop_timeout_once, .run_once = mowgli_simple_eventloop_run_once, .pollsetup = mowgli_select_eventloop_pollsetup, diff --git a/src/libmowgli/eventloop/timer.c b/src/libmowgli/eventloop/timer.c index d8c5061..efdbdea 100644 --- a/src/libmowgli/eventloop/timer.c +++ b/src/libmowgli/eventloop/timer.c @@ -23,8 +23,8 @@ static mowgli_heap_t *timer_heap = NULL; -static mowgli_eventloop_timer_t *mowgli_timer_add_real(mowgli_eventloop_t *eventloop, - const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when, time_t frequency) +static mowgli_eventloop_timer_t * +mowgli_timer_add_real(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when, time_t frequency) { mowgli_eventloop_timer_t *timer; @@ -39,36 +39,39 @@ static mowgli_eventloop_timer_t *mowgli_timer_add_real(mowgli_eventloop_t *event timer->func = func; timer->name = name; timer->arg = arg; - timer->when = mowgli_eventloop_get_time(eventloop) + when; + timer->deadline = mowgli_eventloop_get_time(eventloop) + when; timer->frequency = frequency; timer->active = true; - if (eventloop->deadline <= mowgli_eventloop_get_time(eventloop) || timer->when <= eventloop->deadline) - eventloop->deadline = timer->when; + if (eventloop->deadline != -1 && timer->deadline <= eventloop->deadline) + eventloop->deadline = timer->deadline; mowgli_node_add(timer, &timer->node, &eventloop->timer_list); #ifdef DEBUG - mowgli_log("[timer(%p) add when:%d active:%d] [eventloop deadline:%d]", timer, timer->when, timer->active, eventloop->deadline); + mowgli_log("[timer(%p) add when:%d active:%d] [eventloop deadline:%d]", timer, timer->deadline, timer->active, eventloop->deadline); #endif return timer; } /* add an event to the table to be continually ran */ -mowgli_eventloop_timer_t *mowgli_timer_add(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when) +mowgli_eventloop_timer_t * +mowgli_timer_add(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when) { return mowgli_timer_add_real(eventloop, name, func, arg, when, when); } /* adds an event to the table to be ran only once */ -mowgli_eventloop_timer_t *mowgli_timer_add_once(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when) +mowgli_eventloop_timer_t * +mowgli_timer_add_once(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when) { return mowgli_timer_add_real(eventloop, name, func, arg, when, 0); } /* delete an event from the table */ -void mowgli_timer_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_timer_t *timer) +void +mowgli_timer_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_timer_t *timer) { return_if_fail(eventloop != NULL); return_if_fail(timer != NULL); @@ -81,7 +84,8 @@ void mowgli_timer_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_timer_ } /* checks all pending events */ -void mowgli_eventloop_run_timers(mowgli_eventloop_t *eventloop) +void +mowgli_eventloop_run_timers(mowgli_eventloop_t *eventloop) { mowgli_node_t *n, *tn; time_t currtime; @@ -94,7 +98,7 @@ void mowgli_eventloop_run_timers(mowgli_eventloop_t *eventloop) { mowgli_eventloop_timer_t *timer = n->data; - if (timer->active && timer->when <= currtime) + if (timer->active && (timer->deadline <= currtime)) { /* now we call it */ eventloop->last_ran = timer->name; @@ -105,7 +109,9 @@ void mowgli_eventloop_run_timers(mowgli_eventloop_t *eventloop) /* event is scheduled more than once */ if (timer->frequency) - timer->when = currtime + timer->frequency; + { + timer->deadline = currtime + timer->frequency; + } else { /* XXX: yuck. find a better way to handle this. */ @@ -118,36 +124,37 @@ void mowgli_eventloop_run_timers(mowgli_eventloop_t *eventloop) } /* returns the time the next mowgli_timer_run() should happen */ -time_t mowgli_eventloop_next_timer(mowgli_eventloop_t *eventloop) +time_t +mowgli_eventloop_next_timer(mowgli_eventloop_t *eventloop) { mowgli_node_t *n; return_val_if_fail(eventloop != NULL, 0); if (eventloop->deadline == -1) - { MOWGLI_ITER_FOREACH(n, eventloop->timer_list.head) { mowgli_eventloop_timer_t *timer = n->data; - if (timer->active && (timer->when < eventloop->deadline || eventloop->deadline == -1)) - eventloop->deadline = timer->when; + if (timer->active && ((timer->deadline < eventloop->deadline) || (eventloop->deadline == -1))) + eventloop->deadline = timer->deadline; #ifdef DEBUG - mowgli_log("timer %p active:%d when:%ld deadline:%ld", timer, timer->active, timer->when, eventloop->deadline); + mowgli_log("timer %p active:%d when:%ld deadline:%ld", timer, timer->active, timer->deadline, eventloop->deadline); #endif } - } #ifdef DEBUG mowgli_log("eventloop deadline:%ld", eventloop->deadline); + #endif return eventloop->deadline; } /* finds an event in the table */ -mowgli_eventloop_timer_t *mowgli_timer_find(mowgli_eventloop_t *eventloop, mowgli_event_dispatch_func_t *func, void *arg) +mowgli_eventloop_timer_t * +mowgli_timer_find(mowgli_eventloop_t *eventloop, mowgli_event_dispatch_func_t *func, void *arg) { mowgli_node_t *n; @@ -158,7 +165,7 @@ mowgli_eventloop_timer_t *mowgli_timer_find(mowgli_eventloop_t *eventloop, mowgl { mowgli_eventloop_timer_t *timer = n->data; - if (timer->func == func && timer->arg == arg) + if ((timer->func == func) && (timer->arg == arg)) return timer; } diff --git a/src/libmowgli/eventloop/windows_pollops.c b/src/libmowgli/eventloop/windows_pollops.c index f1c9c0f..8133bc1 100644 --- a/src/libmowgli/eventloop/windows_pollops.c +++ b/src/libmowgli/eventloop/windows_pollops.c @@ -22,9 +22,10 @@ #ifdef _WIN32 -#define DEFAULT_SOCKETMAX (2048) +# define DEFAULT_SOCKETMAX (2048) -typedef struct { +typedef struct +{ WSAEVENT *pfd; unsigned short pfd_size; unsigned short last_slot; @@ -33,11 +34,13 @@ typedef struct { static WSADATA wsock_env; -void mowgli_winsock_bootstrap(void) +void +mowgli_winsock_bootstrap(void) { int r; r = WSAStartup((short) 0x202, &wsock_env); + if (r != 0) { printf("mowgli bootstrap failure (win32): %d\n", r); @@ -50,7 +53,8 @@ void mowgli_winsock_bootstrap(void) wsock_env.iMaxSockets -= (wsock_env.iMaxSockets % MAXIMUM_WAIT_OBJECTS); } -static void mowgli_winsock_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +static void +mowgli_winsock_eventloop_pollsetup(mowgli_eventloop_t *eventloop) { unsigned short i; mowgli_winsock_eventloop_private_t *priv; @@ -74,7 +78,8 @@ static void mowgli_winsock_eventloop_pollsetup(mowgli_eventloop_t *eventloop) return; } -static unsigned short mowgli_winsock_eventloop_find_slot(mowgli_winsock_eventloop_private_t *priv) +static unsigned short +mowgli_winsock_eventloop_find_slot(mowgli_winsock_eventloop_private_t *priv) { unsigned short i = 1; @@ -84,23 +89,20 @@ static unsigned short mowgli_winsock_eventloop_find_slot(mowgli_winsock_eventloo i = priv->last_slot; for (; i < priv->pfd_size; i++) - { if (priv->pfd[i] == INVALID_HANDLE_VALUE) { priv->last_slot = i; return i; } - } /* miss, try from beginning. */ + for (i = 1; i < priv->pfd_size; i++) - { if (priv->pfd[i] == INVALID_HANDLE_VALUE) { priv->last_slot = i; return i; } - } /* if this happens, we're boned... */ mowgli_log("out of handles for eventloop %p, aborting\n", priv); @@ -109,7 +111,8 @@ static unsigned short mowgli_winsock_eventloop_find_slot(mowgli_winsock_eventloo return 0; } -static void mowgli_winsock_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +static void +mowgli_winsock_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) { unsigned short i; mowgli_winsock_eventloop_private_t *priv; @@ -130,7 +133,8 @@ static void mowgli_winsock_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) return; } -static void mowgli_winsock_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +static void +mowgli_winsock_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) { mowgli_winsock_eventloop_private_t *priv; @@ -152,7 +156,8 @@ static void mowgli_winsock_eventloop_destroy(mowgli_eventloop_t *eventloop, mowg pollable->events = 0; } -static void mowgli_winsock_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +static void +mowgli_winsock_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) { mowgli_winsock_eventloop_private_t *priv; unsigned int old_flags; @@ -163,9 +168,9 @@ static void mowgli_winsock_eventloop_setselect(mowgli_eventloop_t *eventloop, mo priv = eventloop->poller; old_flags = pollable->events; -#ifdef DEBUG +# ifdef DEBUG mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); -#endif +# endif switch (dir) { @@ -182,9 +187,9 @@ static void mowgli_winsock_eventloop_setselect(mowgli_eventloop_t *eventloop, mo break; } -#ifdef DEBUG +# ifdef DEBUG mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); -#endif +# endif if (pollable->read_function == NULL) pollable->events &= ~(FD_READ | FD_CLOSE | FD_ACCEPT | FD_OOB); @@ -192,8 +197,10 @@ static void mowgli_winsock_eventloop_setselect(mowgli_eventloop_t *eventloop, mo if (pollable->write_function == NULL) pollable->events &= ~(FD_WRITE | FD_CONNECT | FD_CLOSE); - if (old_flags == 0 && pollable->events == 0) + if ((old_flags == 0) && (pollable->events == 0)) + { return; + } else if (pollable->events <= 0) { mowgli_winsock_eventloop_destroy(eventloop, pollable); @@ -220,7 +227,8 @@ static void mowgli_winsock_eventloop_setselect(mowgli_eventloop_t *eventloop, mo return; } -static void mowgli_winsock_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +static void +mowgli_winsock_eventloop_select(mowgli_eventloop_t *eventloop, int delay) { mowgli_winsock_eventloop_private_t *priv; int i, j; @@ -252,18 +260,19 @@ static void mowgli_winsock_eventloop_select(mowgli_eventloop_t *eventloop, int d WSAEnumNetworkEvents(pollable->fd, priv->pfd[pollable->slot], &events); - if (events.lNetworkEvents & (FD_READ | FD_CLOSE | FD_ACCEPT | FD_OOB) && pollable->read_function != NULL) - pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + if (events.lNetworkEvents & (FD_READ | FD_CLOSE | FD_ACCEPT | FD_OOB)) + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ); - if (events.lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE) && pollable->write_function != NULL) - pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + if (events.lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE)) + mowgli_pollable_trigger(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE); } } mowgli_eventloop_synchronize(eventloop); } -mowgli_eventloop_ops_t _mowgli_winsock_pollops = { +mowgli_eventloop_ops_t _mowgli_winsock_pollops = +{ .timeout_once = mowgli_simple_eventloop_timeout_once, .run_once = mowgli_simple_eventloop_run_once, .pollsetup = mowgli_winsock_eventloop_pollsetup, diff --git a/src/libmowgli/ext/Makefile b/src/libmowgli/ext/Makefile index d7466b6..1cb198f 100644 --- a/src/libmowgli/ext/Makefile +++ b/src/libmowgli/ext/Makefile @@ -8,14 +8,17 @@ SRCS = confparse.c \ getopt_long.c \ global_storage.c \ program_opts.c \ - proctitle.c + proctitle.c \ + json.c INCLUDES = confparse.h \ error_backtrace.h \ getopt_long.h \ global_storage.h \ program_opts.h \ - proctitle.h + proctitle.h \ + json.h \ + json-inline.h include ../../../buildsys.mk diff --git a/src/libmowgli/ext/confparse.c b/src/libmowgli/ext/confparse.c index 898ba8c..e498055 100644 --- a/src/libmowgli/ext/confparse.c +++ b/src/libmowgli/ext/confparse.c @@ -17,6 +17,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ + /* * Description of config files parsed by this: * @@ -35,6 +36,7 @@ * no matter where the include directive is. Include files must have balanced * braces. */ + /* * Original idea from the csircd config parser written by Fred Jacobs * and Chris Behrens. @@ -52,7 +54,8 @@ static mowgli_config_file_t *mowgli_config_file_load_internal(mowgli_config_file #define CF_ERRORED(cf) ((cf)->curline <= 0) -static void mowgli_config_file_error(mowgli_config_file_t *cf, const char *format, ...) +static void +mowgli_config_file_error(mowgli_config_file_t *cf, const char *format, ...) { va_list ap; char buffer[1024]; @@ -70,16 +73,19 @@ static void mowgli_config_file_error(mowgli_config_file_t *cf, const char *forma if (cf->curline < 0) cf->curline = -cf->curline; - mowgli_log("%s:%d: %s", cf->filename, cf->curline, buffer); + mowgli_log("%s:%d: %s", cf->filename, cf->curline, buffer); /* mark config parse as failed */ cf->curline = -cf->curline; } else + { mowgli_log("mowgli_config_file_parse(): %s", buffer); + } } -static void skip_ws(char **pos, mowgli_config_file_t *cf) +static void +skip_ws(char **pos, mowgli_config_file_t *cf) { int startline; @@ -87,86 +93,110 @@ static void skip_ws(char **pos, mowgli_config_file_t *cf) { switch (**pos) { - case ' ': - case '\t': - case '\r': - case '=': /* XXX */ - break; - case '\n': - cf->curline++; - break; - case '/': - if ((*pos)[1] == '*') + case ' ': + case '\t': + case '\r': + case '=': /* XXX */ + break; + case '\n': + cf->curline++; + break; + case '/': + + if ((*pos)[1] == '*') + { + startline = cf->curline; + (*pos)++; + (*pos)++; + + while (**pos != '\0' && (**pos != '*' || (*pos)[1] != '/')) { - startline = cf->curline; - (*pos)++; + if (**pos == '\n') + cf->curline++; + (*pos)++; - while (**pos != '\0' && (**pos != '*' || (*pos)[1] != '/')) - { - if (**pos == '\n') - cf->curline++; - (*pos)++; - } - if (**pos == '\0') - mowgli_config_file_error(cf, "File ends inside comment starting at line %d", startline); - else - (*pos)++; /* skip '*' */ - } - else if ((*pos)[1] == '/') - { - while (**pos != '\0' && **pos != '\n' && **pos != '\r') - (*pos)++; - continue; } + + if (**pos == '\0') + mowgli_config_file_error(cf, "File ends inside comment starting at line %d", startline); else - return; - break; - case '#': + (*pos)++; /* skip '*' */ + } + else if ((*pos)[1] == '/') + { while (**pos != '\0' && **pos != '\n' && **pos != '\r') + { (*pos)++; + } + continue; - default: + } + else + { return; + } + + break; + case '#': + + while (**pos != '\0' && **pos != '\n' && **pos != '\r') + { + (*pos)++; + } + + continue; + default: + return; } + if (**pos == '\0') return; + (*pos)++; } } -static char *get_value(char **pos, mowgli_config_file_t *cf, char *skipped) +static char * +get_value(char **pos, mowgli_config_file_t *cf, char *skipped) { char *p = *pos; char *q; char *start; *skipped = '\0'; + if (*p == '"') { p++; start = p; q = p; + while (*p != '\0' && *p != '\r' && *p != '\n' && *p != '"') { - if (*p == '\\' && (p[1] == '"' || p[1] == '\\')) + if ((*p == '\\') && ((p[1] == '"') || (p[1] == '\\'))) p++; + *q++ = *p++; } + if (*p == '\0') { mowgli_config_file_error(cf, "File ends inside quoted string"); return NULL; } - if (*p == '\r' || *p == '\n') + + if ((*p == '\r') || (*p == '\n')) { mowgli_config_file_error(cf, "Newline inside quoted string"); return NULL; } + if (*p != '"') { mowgli_config_file_error(cf, "Weird character terminating quoted string (BUG)"); return NULL; } + p++; *q = '\0'; *pos = p; @@ -176,24 +206,34 @@ static char *get_value(char **pos, mowgli_config_file_t *cf, char *skipped) else { start = p; + while (*p != '\0' && *p != '\t' && *p != '\r' && *p != '\n' && - *p != ' ' && *p != '/' && *p != '#' && - *p != ';' && *p != '{' && *p != '}') + *p != ' ' && *p != '/' && *p != '#' && + *p != ';' && *p != '{' && *p != '}') + { p++; + } + if (p == start) return NULL; + *pos = p; skip_ws(pos, cf); + if (p == *pos) *skipped = *p; + *p = '\0'; + if (p == *pos) (*pos)++; + return start; } } -static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char *confdata) +static mowgli_config_file_t * +mowgli_config_file_parse(const char *filename, char *confdata) { mowgli_config_file_t *cf, *subcf, *lastcf; mowgli_config_file_entry_t **pprevce, *ce, *upce; @@ -208,11 +248,14 @@ static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char pprevce = &cf->entries; upce = NULL; p = confdata; + while (*p != '\0') { skip_ws(&p, cf); - if (*p == '\0' || CF_ERRORED(cf)) + + if ((*p == '\0') || CF_ERRORED(cf)) break; + if (*p == '}') { if (upce == NULL) @@ -220,31 +263,39 @@ static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char mowgli_config_file_error(cf, "Extraneous closing brace"); break; } + ce = upce; ce->sectlinenum = cf->curline; pprevce = &ce->next; upce = ce->prevlevel; p++; skip_ws(&p, cf); + if (CF_ERRORED(cf)) break; + if (*p != ';') { mowgli_config_file_error(cf, "Missing semicolon after closing brace for section ending at line %d", ce->sectlinenum); break; } + ce = NULL; p++; continue; } + val = get_value(&p, cf, &c); + if (CF_ERRORED(cf)) break; + if (val == NULL) { mowgli_config_file_error(cf, "Unexpected character trying to read variable name"); break; } + ce = mowgli_alloc(sizeof *ce); ce->fileptr = cf; ce->varlinenum = cf->curline; @@ -252,8 +303,10 @@ static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char ce->prevlevel = upce; *pprevce = ce; pprevce = &ce->next; - if (c == '\0' && (*p == '{' || *p == ';')) + + if ((c == '\0') && ((*p == '{') || (*p == ';'))) c = *p++; + if (c == '{') { pprevce = &ce->entries; @@ -272,16 +325,21 @@ static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char else { val = get_value(&p, cf, &c); + if (CF_ERRORED(cf)) break; + if (val == NULL) { mowgli_config_file_error(cf, "Unexpected character trying to read value for %s", ce->varname); break; } + ce->vardata = val; - if (c == '\0' && (*p == '{' || *p == ';')) + + if ((c == '\0') && ((*p == '{') || (*p == ';'))) c = *p++; + if (c == '{') { pprevce = &ce->entries; @@ -290,18 +348,24 @@ static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char } else if (c == ';') { - if (upce == NULL && !strcasecmp(ce->varname, "include")) + if ((upce == NULL) && !strcasecmp(ce->varname, "include")) { subcf = mowgli_config_file_load_internal(cf, ce->vardata); + if (subcf == NULL) { mowgli_config_file_error(cf, "Error in file included from here"); break; } + lastcf->next = subcf; + while (lastcf->next != NULL) + { lastcf = lastcf->next; + } } + ce = NULL; } else @@ -311,59 +375,74 @@ static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char } } } - if (!CF_ERRORED(cf) && upce != NULL) + + if (!CF_ERRORED(cf) && (upce != NULL)) { mowgli_config_file_error(cf, "One or more sections not closed"); ce = upce; + while (ce->prevlevel != NULL) + { ce = ce->prevlevel; + } + if (ce->vardata != NULL) mowgli_config_file_error(cf, "First unclosed section is %s %s at line %d", - ce->varname, ce->vardata, ce->varlinenum); + ce->varname, ce->vardata, ce->varlinenum); else mowgli_config_file_error(cf, "First unclosed section is %s at line %d", - ce->varname, ce->varlinenum); + ce->varname, ce->varlinenum); } + if (CF_ERRORED(cf)) { mowgli_config_file_free(cf); cf = NULL; } + return cf; } -static void mowgli_config_file_entry_free(mowgli_config_file_entry_t *ceptr) +static void +mowgli_config_file_entry_free(mowgli_config_file_entry_t *ceptr) { mowgli_config_file_entry_t *nptr; for (; ceptr; ceptr = nptr) { nptr = ceptr->next; + if (ceptr->entries) mowgli_config_file_entry_free(ceptr->entries); + /* ce_varname and ce_vardata are inside cf_mem */ mowgli_free(ceptr); } } -void mowgli_config_file_free(mowgli_config_file_t *cfptr) +void +mowgli_config_file_free(mowgli_config_file_t *cfptr) { mowgli_config_file_t *nptr; for (; cfptr; cfptr = nptr) { nptr = cfptr->next; + if (cfptr->entries) mowgli_config_file_entry_free(cfptr->entries); + mowgli_free(cfptr->filename); mowgli_free(cfptr->mem); mowgli_free(cfptr); } } -static mowgli_config_file_t *mowgli_config_file_load_internal(mowgli_config_file_t *parent, const char *filename) +static mowgli_config_file_t * +mowgli_config_file_load_internal(mowgli_config_file_t *parent, const char *filename) { struct stat sb; + FILE *fp; size_t ret; char *buf = NULL; @@ -377,35 +456,42 @@ static mowgli_config_file_t *mowgli_config_file_load_internal(mowgli_config_file } fp = fopen(filename, "rb"); + if (!fp) { mowgli_config_file_error(parent, "Couldn't open \"%s\": %s\n", filename, strerror(errno)); return NULL; } + if (stat(filename, &sb) == -1) { mowgli_config_file_error(parent, "Couldn't fstat \"%s\": %s\n", filename, strerror(errno)); fclose(fp); return NULL; } + if (!S_ISREG(sb.st_mode)) { mowgli_config_file_error(parent, "Not a regular file: \"%s\"\n", filename); fclose(fp); return NULL; } + if (sb.st_size > SSIZE_MAX - 1) { mowgli_config_file_error(parent, "File too large: \"%s\"\n", filename); fclose(fp); return NULL; } + buf = (char *) mowgli_alloc(sb.st_size + 1); + if (sb.st_size) { errno = 0; ret = fread(buf, 1, sb.st_size, fp); - if (ret != (size_t)sb.st_size) + + if (ret != (size_t) sb.st_size) { mowgli_config_file_error(parent, "Error reading \"%s\": %s\n", filename, strerror(errno ? errno : EFAULT)); mowgli_free(buf); @@ -414,17 +500,22 @@ static mowgli_config_file_t *mowgli_config_file_load_internal(mowgli_config_file } } else + { ret = 0; + } + buf[ret] = '\0'; fclose(fp); nestcnt++; cfptr = mowgli_config_file_parse(filename, buf); nestcnt--; + /* buf is owned by cfptr or freed now */ return cfptr; } -mowgli_config_file_t *mowgli_config_file_load(const char *filename) +mowgli_config_file_t * +mowgli_config_file_load(const char *filename) { return mowgli_config_file_load_internal(NULL, filename); } diff --git a/src/libmowgli/ext/confparse.h b/src/libmowgli/ext/confparse.h index d498b87..cedf708 100644 --- a/src/libmowgli/ext/confparse.h +++ b/src/libmowgli/ext/confparse.h @@ -28,7 +28,7 @@ struct _mowgli_configentry int varlinenum; char *varname; char *vardata; - int sectlinenum; /* line containing closing brace */ + int sectlinenum;/* line containing closing brace */ mowgli_config_file_entry_t *entries; mowgli_config_file_entry_t *prevlevel; diff --git a/src/libmowgli/ext/error_backtrace.c b/src/libmowgli/ext/error_backtrace.c index 6c28c22..2adb906 100644 --- a/src/libmowgli/ext/error_backtrace.c +++ b/src/libmowgli/ext/error_backtrace.c @@ -26,14 +26,12 @@ void mowgli_error_context_display(mowgli_error_context_t *e, const char *delim) { - mowgli_node_t *n; - char *bt_msg; - return_if_fail(e != NULL); return_if_fail(delim != NULL); + return_if_fail(MOWGLI_LIST_LENGTH(&e->bt) != 0); - if (MOWGLI_LIST_LENGTH(&e->bt) == 0) - mowgli_throw_exception(mowgli.error_backtrace.no_backtrace); + mowgli_node_t *n; + char *bt_msg; MOWGLI_LIST_FOREACH(n, e->bt.head) { diff --git a/src/libmowgli/ext/error_backtrace.h b/src/libmowgli/ext/error_backtrace.h index d7da7cf..3ec54de 100644 --- a/src/libmowgli/ext/error_backtrace.h +++ b/src/libmowgli/ext/error_backtrace.h @@ -24,7 +24,8 @@ #ifndef __MOWGLI_ERROR_BACKTRACE_H__ #define __MOWGLI_ERROR_BACKTRACE_H__ -typedef struct mowgli_error_context_ { +typedef struct mowgli_error_context_ +{ mowgli_list_t bt; } mowgli_error_context_t; diff --git a/src/libmowgli/ext/getopt_long.c b/src/libmowgli/ext/getopt_long.c index adf64e5..dd70325 100644 --- a/src/libmowgli/ext/getopt_long.c +++ b/src/libmowgli/ext/getopt_long.c @@ -33,37 +33,40 @@ #include "getopt_long.h" -int mowgli_opterr = 1; /* if error message should be printed */ -int mowgli_optind = 1; /* index into parent argv vector */ -int mowgli_optopt = '?'; /* character checked for validity */ -int mowgli_optreset = 0; /* reset getopt */ -char *mowgli_optarg = NULL; /* argument associated with option */ +int mowgli_opterr = 1; /* if error message should be printed */ +int mowgli_optind = 1; /* index into parent argv vector */ +int mowgli_optopt = '?';/* character checked for validity */ +int mowgli_optreset = 0;/* reset getopt */ +char *mowgli_optarg = NULL; /* argument associated with option */ /* XXX: suppress const warnings */ -#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) +#define __UNCONST(a) ((void *) (unsigned long) (const void *) (a)) -#define IGNORE_FIRST (*options == '-' || *options == '+') -#define PRINT_ERROR ((mowgli_opterr) && ((*options != ':') \ - || (IGNORE_FIRST && options[1] != ':'))) +#define IGNORE_FIRST (*options == '-' || *options == '+') +#define PRINT_ERROR ((mowgli_opterr) && ((*options != ':') \ + || (IGNORE_FIRST && options[1] != ':'))) #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) -#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) +#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) + /* XXX: GNU ignores PC if *options == '-' */ -#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') +#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') /* return values */ -#define BADCH (int)'?' -#define BADARG ((IGNORE_FIRST && options[1] == ':') \ - || (*options == ':') ? (int)':' : (int)'?') -#define INORDER (int)1 +#define BADCH (int) '?' +#define BADARG ((IGNORE_FIRST && options[1] == ':') \ + || (*options == ':') ? (int) ':' : (int) '?') +#define INORDER (int) 1 -#define EMSG "" +#define EMSG "" static inline void warnx(const char *fmt, ...) { va_list ap; + va_start(ap, fmt); vfprintf(stderr, fmt, ap); + fputc('\n', stderr); va_end(ap); } @@ -71,11 +74,11 @@ static int getopt_internal(int, char **, const char *); static int gcd(int, int); static void permute_args(int, int, int, char **); -static const char *place = EMSG; /* option letter processing */ +static const char *place = EMSG;/* option letter processing */ /* XXX: set mowgli_optreset to 1 rather than these two */ -static int nonopt_start = -1; /* first non option argument (for permute) */ -static int nonopt_end = -1; /* first option after non options (for permute) */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ /* Error messages */ static const char recargchar[] = "option requires an argument -- %c"; @@ -85,7 +88,6 @@ static const char noarg[] = "option doesn't take an argument -- %.*s"; static const char illoptchar[] = "unknown option -- %c"; static const char illoptstring[] = "unknown option -- %s"; - /* * Compute the greatest common divisor of a and b. */ @@ -95,12 +97,14 @@ gcd(int a, int b) int c; c = a % b; - while (c != 0) { + + while (c != 0) + { a = b; b = c; c = a % b; } - + return b; } @@ -125,14 +129,18 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv) ncycle = gcd(nnonopts, nopts); cyclelen = (opt_end - panonopt_start) / ncycle; - for (i = 0; i < ncycle; i++) { - cstart = panonopt_end+i; + for (i = 0; i < ncycle; i++) + { + cstart = panonopt_end + i; pos = cstart; - for (j = 0; j < cyclelen; j++) { + + for (j = 0; j < cyclelen; j++) + { if (pos >= panonopt_end) pos -= nnonopts; else pos += nopts; + swap = nargv[pos]; nargv[pos] = nargv[cstart]; nargv[cstart] = swap; @@ -148,7 +156,7 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv) static int getopt_internal(int nargc, char **nargv, const char *options) { - char *oli; /* option letter list index */ + char *oli; /* option letter list index */ int optchar; return_val_if_fail(nargv != NULL, -1); @@ -166,116 +174,167 @@ getopt_internal(int nargc, char **nargv, const char *options) if (mowgli_optreset) nonopt_start = nonopt_end = -1; + start: - if (mowgli_optreset || !*place) { /* update scanning pointer */ + + if (mowgli_optreset || !*place) /* update scanning pointer */ + { mowgli_optreset = 0; - if (mowgli_optind >= nargc) { /* end of argument vector */ + + if (mowgli_optind >= nargc) /* end of argument vector */ + { place = EMSG; - if (nonopt_end != -1) { + + if (nonopt_end != -1) + { /* do permutation, if we have to */ permute_args(nonopt_start, nonopt_end, - mowgli_optind, nargv); + mowgli_optind, nargv); mowgli_optind -= nonopt_end - nonopt_start; } - else if (nonopt_start != -1) { + else if (nonopt_start != -1) + { /* * If we skipped non-options, set mowgli_optind * to the first of them. */ mowgli_optind = nonopt_start; } + nonopt_start = nonopt_end = -1; return -1; } + if ((*(place = nargv[mowgli_optind]) != '-') - || (place[1] == '\0')) { /* found non-option */ + || (place[1] == '\0')) /* found non-option */ + { place = EMSG; - if (IN_ORDER) { + + if (IN_ORDER) + { /* - * GNU extension: + * GNU extension: * return non-option as argument to option 1 */ mowgli_optarg = nargv[mowgli_optind++]; return INORDER; } - if (!PERMUTE) { + + if (!PERMUTE) /* * if no permutation wanted, stop parsing * at first non-option */ return -1; - } + /* do permutation */ if (nonopt_start == -1) + { nonopt_start = mowgli_optind; - else if (nonopt_end != -1) { + } + else if (nonopt_end != -1) + { permute_args(nonopt_start, nonopt_end, - mowgli_optind, nargv); + mowgli_optind, nargv); nonopt_start = mowgli_optind - - (nonopt_end - nonopt_start); + (nonopt_end - nonopt_start); nonopt_end = -1; } + mowgli_optind++; + /* process next argument */ goto start; } - if (nonopt_start != -1 && nonopt_end == -1) + + if ((nonopt_start != -1) && (nonopt_end == -1)) nonopt_end = mowgli_optind; - if (place[1] && *++place == '-') { /* found "--" */ + + if (place[1] && (*++place == '-')) /* found "--" */ + { place++; return -2; } } - if ((optchar = (int)*place++) == (int)':' || - (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { + + if (((optchar = (int) *place++) == (int) ':') || + ((oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL)) + { /* option letter unknown or ':' */ if (!*place) ++mowgli_optind; + if (PRINT_ERROR) warnx(illoptchar, optchar); + mowgli_optopt = optchar; return BADCH; } - if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ - /* XXX: what if no long options provided (called by getopt)? */ - if (*place) + + if ((optchar == 'W') && (oli[1] == ';'))/* -W long-option */ + { /* XXX: what if no long options provided (called by getopt)? */ + if (*place) return -2; - if (++mowgli_optind >= nargc) { /* no arg */ + if (++mowgli_optind >= nargc) /* no arg */ + { place = EMSG; + if (PRINT_ERROR) warnx(recargchar, optchar); + mowgli_optopt = optchar; return BADARG; - } else /* white space */ + } + else /* white space */ + { place = nargv[mowgli_optind]; + } + /* * Handle -W arg the same as --arg (which causes getopt to * stop parsing). */ return -2; } - if (*++oli != ':') { /* doesn't take argument */ + + if (*++oli != ':') /* doesn't take argument */ + { if (!*place) ++mowgli_optind; - } else { /* takes (optional) argument */ + } + else /* takes (optional) argument */ + { mowgli_optarg = NULL; - if (*place) /* no white space */ + + if (*place) /* no white space */ + { mowgli_optarg = __UNCONST(place); + } + /* XXX: disable test for :: if PC? (GNU doesn't) */ - else if (oli[1] != ':') { /* arg not optional */ - if (++mowgli_optind >= nargc) { /* no arg */ + else if (oli[1] != ':') /* arg not optional */ + { + if (++mowgli_optind >= nargc) /* no arg */ + { place = EMSG; + if (PRINT_ERROR) warnx(recargchar, optchar); + mowgli_optopt = optchar; return BADARG; - } else + } + else + { mowgli_optarg = nargv[mowgli_optind]; + } } + place = EMSG; ++mowgli_optind; } + /* dump back option letter */ return optchar; } @@ -286,11 +345,11 @@ start: * * [eventually this will replace the real getopt] */ -int -mowgli_getopt(nargc, nargv, options) - int nargc; - char * const *nargv; - const char *options; +int mowgli_getopt(nargc, nargv, options) +int nargc; + +char *const *nargv; +const char *options; { int retval; @@ -298,20 +357,26 @@ mowgli_getopt(nargc, nargv, options) return_val_if_fail(options != NULL, -1); retval = getopt_internal(nargc, __UNCONST(nargv), options); - if (retval == -2) { + + if (retval == -2) + { ++mowgli_optind; + /* * We found an option (--), so if we skipped non-options, * we have to permute. */ - if (nonopt_end != -1) { + if (nonopt_end != -1) + { permute_args(nonopt_start, nonopt_end, mowgli_optind, - __UNCONST(nargv)); + __UNCONST(nargv)); mowgli_optind -= nonopt_end - nonopt_start; } + nonopt_start = nonopt_end = -1; retval = -1; } + return retval; } @@ -320,23 +385,25 @@ mowgli_getopt(nargc, nargv, options) * Parse argc/argv argument vector. */ int -mowgli_getopt_long(int nargc, char * const *nargv, const char *options, - const mowgli_getopt_option_t *long_options, int *idx) +mowgli_getopt_long(int nargc, char *const *nargv, const char *options, const mowgli_getopt_option_t *long_options, int *idx) { int retval; -#define IDENTICAL_INTERPRETATION(_x, _y) \ - (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ - long_options[(_x)].flag == long_options[(_y)].flag && \ +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ long_options[(_x)].val == long_options[(_y)].val) return_val_if_fail(nargv != NULL, -1); return_val_if_fail(options != NULL, -1); return_val_if_fail(long_options != NULL, -1); + /* idx may be NULL */ retval = getopt_internal(nargc, __UNCONST(nargv), options); - if (retval == -2) { + + if (retval == -2) + { char *current_argv, *has_equal; size_t current_argv_len; int i, ambiguous, match; @@ -348,58 +415,75 @@ mowgli_getopt_long(int nargc, char * const *nargv, const char *options, mowgli_optind++; place = EMSG; - if (*current_argv == '\0') { /* found "--" */ - /* + if (*current_argv == '\0') /* found "--" */ + { /* * We found an option (--), so if we skipped * non-options, we have to permute. */ - if (nonopt_end != -1) { + if (nonopt_end != -1) + { permute_args(nonopt_start, nonopt_end, - mowgli_optind, __UNCONST(nargv)); + mowgli_optind, __UNCONST(nargv)); mowgli_optind -= nonopt_end - nonopt_start; } + nonopt_start = nonopt_end = -1; return -1; } - if ((has_equal = strchr(current_argv, '=')) != NULL) { + + if ((has_equal = strchr(current_argv, '=')) != NULL) + { /* argument found (--option=arg) */ current_argv_len = has_equal - current_argv; has_equal++; - } else + } + else + { current_argv_len = strlen(current_argv); + } - for (i = 0; long_options[i].name; i++) { + for (i = 0; long_options[i].name; i++) + { /* find matching long option */ if (strncmp(current_argv, long_options[i].name, - current_argv_len)) + current_argv_len)) continue; if (strlen(long_options[i].name) == - (unsigned)current_argv_len) { + (unsigned) current_argv_len) + { /* exact match */ match = i; ambiguous = 0; break; } - if (match == -1) /* partial match */ + + if (match == -1)/* partial match */ match = i; else if (!IDENTICAL_INTERPRETATION(i, match)) ambiguous = 1; } - if (ambiguous) { + + if (ambiguous) + { /* ambiguous abbreviation */ if (PRINT_ERROR) - warnx(ambig, (int)current_argv_len, - current_argv); + warnx(ambig, (int) current_argv_len, + current_argv); + mowgli_optopt = 0; return BADCH; } - if (match != -1) { /* option found */ - if (long_options[match].has_arg == no_argument - && has_equal) { + + if (match != -1)/* option found */ + { + if ((long_options[match].has_arg == no_argument) + && has_equal) + { if (PRINT_ERROR) - warnx(noarg, (int)current_argv_len, - current_argv); + warnx(noarg, (int) current_argv_len, + current_argv); + /* * XXX: GNU sets mowgli_optopt to val regardless of * flag @@ -408,29 +492,34 @@ mowgli_getopt_long(int nargc, char * const *nargv, const char *options, mowgli_optopt = long_options[match].val; else mowgli_optopt = 0; + return BADARG; } - if (long_options[match].has_arg == required_argument || - long_options[match].has_arg == optional_argument) { + + if ((long_options[match].has_arg == required_argument) || + (long_options[match].has_arg == optional_argument)) + { if (has_equal) mowgli_optarg = has_equal; else if (long_options[match].has_arg == - required_argument) { + required_argument) /* * optional argument doesn't use * next nargv */ mowgli_optarg = nargv[mowgli_optind++]; - } } + if ((long_options[match].has_arg == required_argument) - && (mowgli_optarg == NULL)) { + && (mowgli_optarg == NULL)) + { /* * Missing argument; leading ':' * indicates no error should be generated */ if (PRINT_ERROR) warnx(recargstring, current_argv); + /* * XXX: GNU sets mowgli_optopt to val regardless * of flag @@ -439,23 +528,34 @@ mowgli_getopt_long(int nargc, char * const *nargv, const char *options, mowgli_optopt = long_options[match].val; else mowgli_optopt = 0; + --mowgli_optind; return BADARG; } - } else { /* unknown option */ + } + else /* unknown option */ + { if (PRINT_ERROR) warnx(illoptstring, current_argv); + mowgli_optopt = 0; return BADCH; } - if (long_options[match].flag) { + + if (long_options[match].flag) + { *long_options[match].flag = long_options[match].val; retval = 0; - } else + } + else + { retval = long_options[match].val; + } + if (idx) *idx = match; } + return retval; #undef IDENTICAL_INTERPRETATION } diff --git a/src/libmowgli/ext/getopt_long.h b/src/libmowgli/ext/getopt_long.h index 94c90a9..84653ab 100644 --- a/src/libmowgli/ext/getopt_long.h +++ b/src/libmowgli/ext/getopt_long.h @@ -35,30 +35,34 @@ /* * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions */ -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 -typedef struct { +typedef struct +{ /* name of long option */ const char *name; + /* * one of no_argument, required_argument, and optional_argument: * whether option takes an argument */ int has_arg; + /* if not NULL, set *flag to val when option found */ int *flag; + /* if flag not NULL, value to set *flag to; else return value */ int val; + /* internal value */ int iflag; } mowgli_getopt_option_t; -extern int mowgli_getopt(int nargc, char * const *nargv, const char *options); +extern int mowgli_getopt(int nargc, char *const *nargv, const char *options); -extern int mowgli_getopt_long(int, char * const *, const char *, - const mowgli_getopt_option_t *, int *); +extern int mowgli_getopt_long(int, char *const *, const char *, const mowgli_getopt_option_t *, int *); extern int mowgli_opterr; extern int mowgli_optind; diff --git a/src/libmowgli/ext/global_storage.c b/src/libmowgli/ext/global_storage.c index 4fec74d..f9196ab 100644 --- a/src/libmowgli/ext/global_storage.c +++ b/src/libmowgli/ext/global_storage.c @@ -26,10 +26,9 @@ static mowgli_patricia_t *mowgli_global_storage_dict = NULL; static mowgli_mutex_t mowgli_global_storage_lock; -static void _storage_key_canon(char *key) -{ - -} +static void +_storage_key_canon(char *key) +{ } void mowgli_global_storage_bootstrap(void) @@ -66,4 +65,3 @@ mowgli_global_storage_free(char *name) mowgli_patricia_delete(mowgli_global_storage_dict, name); mowgli_mutex_unlock(&mowgli_global_storage_lock); } - diff --git a/src/libmowgli/ext/global_storage.h b/src/libmowgli/ext/global_storage.h index a26e699..59bc995 100644 --- a/src/libmowgli/ext/global_storage.h +++ b/src/libmowgli/ext/global_storage.h @@ -24,7 +24,6 @@ #ifndef MOWGLI_GLOBAL_STORAGE_H #define MOWGLI_GLOBAL_STORAGE_H -extern void mowgli_global_storage_bootstrap(void); extern void *mowgli_global_storage_get(char *name); extern void mowgli_global_storage_put(char *name, void *value); extern void mowgli_global_storage_free(char *name); diff --git a/src/libmowgli/ext/json-inline.h b/src/libmowgli/ext/json-inline.h new file mode 100644 index 0000000..787b7a7 --- /dev/null +++ b/src/libmowgli/ext/json-inline.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2012 Alex Iadicicco + * Rights to this code are as documented in COPYING. + * + * JSON inline functions, to simplify refcounting etc for other users + */ + +#ifndef MOWGLI_JSON_INLINE_H +#define MOWGLI_JSON_INLINE_H + +/* We don't need to include any other headers here. This is in a separate + file to keep clutter out of the main json.h */ + +/* string */ +static inline void +mowgli_json_string_reset(mowgli_json_t *s) +{ + mowgli_string_reset(MOWGLI_JSON_STRING(s)); +} + +static inline void +mowgli_json_string_append(mowgli_json_t *s, const char *src, size_t n) +{ + mowgli_string_append(MOWGLI_JSON_STRING(s), src, n); +} + +static inline void +mowgli_json_string_append_char(mowgli_json_t *s, const char c) +{ + mowgli_string_append_char(MOWGLI_JSON_STRING(s), c); +} + +/* array */ +static inline size_t +mowgli_json_array_size(mowgli_json_t *arr) +{ + return MOWGLI_JSON_ARRAY(arr)->count; +} + +static inline void +mowgli_json_array_add(mowgli_json_t *arr, mowgli_json_t *data) +{ + mowgli_node_add(mowgli_json_incref(data), mowgli_node_create(), MOWGLI_JSON_ARRAY(arr)); +} + +static inline void +mowgli_json_array_add_head(mowgli_json_t *arr, mowgli_json_t *data) +{ + mowgli_node_add_head(mowgli_json_incref(data), mowgli_node_create(), MOWGLI_JSON_ARRAY(arr)); +} + +static inline void +mowgli_json_array_insert(mowgli_json_t *arr, mowgli_json_t *data, size_t pos) +{ + mowgli_node_insert(mowgli_json_incref(data), mowgli_node_create(), MOWGLI_JSON_ARRAY(arr), pos); +} + +static inline void +mowgli_json_array_delete(mowgli_json_t *arr, mowgli_json_t *data) +{ + mowgli_node_t *n = mowgli_node_find(data, MOWGLI_JSON_ARRAY(arr)); + + if (n == NULL) + return; + + mowgli_node_delete(n, MOWGLI_JSON_ARRAY(arr)); + mowgli_json_decref(data); +} + +static inline bool +mowgli_json_array_contains(mowgli_json_t *arr, mowgli_json_t *data) +{ + return mowgli_node_find(data, MOWGLI_JSON_ARRAY(arr)) != NULL; +} + +static inline mowgli_json_t * +mowgli_json_array_nth(mowgli_json_t *arr, size_t pos) +{ + return (mowgli_json_t *) mowgli_node_nth_data(MOWGLI_JSON_ARRAY(arr), pos); +} + +/* object */ +static inline size_t +mowgli_json_object_size(mowgli_json_t *obj) +{ + return mowgli_patricia_size(MOWGLI_JSON_OBJECT(obj)); +} + +static inline void +mowgli_json_object_add(mowgli_json_t *obj, const char *key, mowgli_json_t *data) +{ + mowgli_patricia_add(MOWGLI_JSON_OBJECT(obj), key, mowgli_json_incref(data)); +} + +static inline mowgli_json_t * +mowgli_json_object_retrieve(mowgli_json_t *obj, const char *key) +{ + return (mowgli_json_t *) mowgli_patricia_retrieve(MOWGLI_JSON_OBJECT(obj), key); +} + +static inline mowgli_json_t * +mowgli_json_object_delete(mowgli_json_t *obj, const char *key) +{ + return (mowgli_json_t *) mowgli_patricia_delete(MOWGLI_JSON_OBJECT(obj), key); +} + +#endif diff --git a/src/libmowgli/ext/json.c b/src/libmowgli/ext/json.c new file mode 100644 index 0000000..3e273a4 --- /dev/null +++ b/src/libmowgli/ext/json.c @@ -0,0 +1,1475 @@ +/* + * Copyright (C) 2012 Alex Iadicicco + * Rights to this code are as documented in COPYING + * + * Structs and functions for interacting with JSON documents from C + */ + +#include + +/* TOC: + * 0. JSON subsystem constants + * 1. Reference counters + * 2. Object creation and deletion + * 3. Serializer (a.k.a. formatter, printer, etc.) + * 4. Deserializer (a.k.a. parser, etc.) + */ + +/* + * 0. JSON SUBSYSTEM CONSTANTS + */ + +#define LL_STACK_SIZE 128 + +#define JSON_REFCOUNT_CONSTANT -42 + +static mowgli_json_t json_null = +{ + .tag = MOWGLI_JSON_TAG_NULL, + .refcount = JSON_REFCOUNT_CONSTANT, +}; +mowgli_json_t *mowgli_json_null = &json_null; + +static mowgli_json_t json_true = +{ + .tag = MOWGLI_JSON_TAG_BOOLEAN, + .refcount = JSON_REFCOUNT_CONSTANT, + { .v_bool = true, } +}; +mowgli_json_t *mowgli_json_true = &json_true; + +static mowgli_json_t json_false = +{ + .tag = MOWGLI_JSON_TAG_BOOLEAN, + .refcount = JSON_REFCOUNT_CONSTANT, + { .v_bool = false, } +}; +mowgli_json_t *mowgli_json_false = &json_false; + +static mowgli_json_t *json_alloc(mowgli_json_tag_t tag); +static void json_destroy(mowgli_json_t *n); +static void destroy_extra_string(mowgli_json_t *n); +static void destroy_extra_array(mowgli_json_t *n); +static void destroy_extra_object(mowgli_json_t *n); + +typedef void (*destroy_extra_cb_t)(mowgli_json_t *); +static destroy_extra_cb_t destroy_extra[] = +{ + [MOWGLI_JSON_TAG_STRING] = destroy_extra_string, + [MOWGLI_JSON_TAG_ARRAY] = destroy_extra_array, + [MOWGLI_JSON_TAG_OBJECT] = destroy_extra_object, +}; + +/* + * 1. REFERENCE COUNTERS + */ + +mowgli_json_t * +mowgli_json_incref(mowgli_json_t *n) +{ + if ((n == NULL) || (n->refcount == JSON_REFCOUNT_CONSTANT)) + return n; + + n->refcount++; + + return n; +} + +mowgli_json_t * +mowgli_json_decref(mowgli_json_t *n) +{ + if ((n == NULL) || (n->refcount == JSON_REFCOUNT_CONSTANT)) + return n; + + n->refcount--; + + if (n->refcount <= 0) + { + json_destroy(n); + return NULL; + } + + return n; +} + +/* Debugging tool to recursively dump reference counts for an object + and any children it may have. This function will never be called + outside of development, so is commented here. + void dump_refs(mowgli_json_t *n) + { + char *s = "unk"; + mowgli_patricia_iteration_state_t st; + + switch (n->tag) { + case MOWGLI_JSON_TAG_NULL: s = "null"; break; + case MOWGLI_JSON_TAG_BOOLEAN: s = "boolean"; break; + case MOWGLI_JSON_TAG_INTEGER: s = "integer"; break; + case MOWGLI_JSON_TAG_FLOAT: s = "float"; break; + case MOWGLI_JSON_TAG_STRING: s = "string"; break; + case MOWGLI_JSON_TAG_ARRAY: s = "array"; break; + case MOWGLI_JSON_TAG_OBJECT: s = "object"; break; + } + + if (n->refcount == JSON_REFCOUNT_CONSTANT) + printf("- %s\n", s); + else + printf("%d %s\n", n->refcount, s); + + if (n->tag == MOWGLI_JSON_TAG_ARRAY) { + mowgli_node_t *cur; + + MOWGLI_LIST_FOREACH(cur, n->v_array->head) { + dump_refs(cur->data); + } + } else if (n->tag == MOWGLI_JSON_TAG_OBJECT) { + mowgli_json_t *cur; + + mowgli_patricia_foreach_start(n->v_object, &st); + while ((cur = mowgli_patricia_foreach_cur(n->v_object, &st)) != NULL) { + dump_refs(cur); + mowgli_patricia_foreach_next(n->v_object, &st); + } + } + } + */ + +/* + * 2. OBJECT CREATION AND DELETION + */ + +static mowgli_json_t * +json_alloc(mowgli_json_tag_t tag) +{ + mowgli_json_t *n; + + n = mowgli_alloc(sizeof(*n)); + + n->tag = tag; + n->refcount = 0; + + return n; +} + +static void +json_destroy(mowgli_json_t *n) +{ + return_if_fail(n != NULL); + + if (destroy_extra[n->tag] != NULL) + destroy_extra[n->tag](n); + + mowgli_free(n); +} + +mowgli_json_t * +mowgli_json_create_integer(int v_int) +{ + mowgli_json_t *n = json_alloc(MOWGLI_JSON_TAG_INTEGER); + + n->v.v_int = v_int; + return n; +} + +mowgli_json_t * +mowgli_json_create_float(double v_float) +{ + mowgli_json_t *n = json_alloc(MOWGLI_JSON_TAG_FLOAT); + + n->v.v_float = v_float; + return n; +} + +mowgli_json_t * +mowgli_json_create_string_n(const char *str, size_t len) +{ + mowgli_json_t *n = json_alloc(MOWGLI_JSON_TAG_STRING); + + n->v.v_string = mowgli_string_create(); + mowgli_string_append(n->v.v_string, str, len); + + return n; +} + +mowgli_json_t * +mowgli_json_create_string(const char *str) +{ + return mowgli_json_create_string_n(str, strlen(str)); +} + +static void +destroy_extra_string(mowgli_json_t *n) +{ + mowgli_string_destroy(n->v.v_string); +} + +mowgli_json_t * +mowgli_json_create_array(void) +{ + mowgli_json_t *n = json_alloc(MOWGLI_JSON_TAG_ARRAY); + + n->v.v_array = mowgli_list_create(); + return n; +} + +static void +destroy_extra_array(mowgli_json_t *n) +{ + mowgli_node_t *cur, *next; + + MOWGLI_LIST_FOREACH_SAFE(cur, next, n->v.v_array->head) + { + mowgli_json_decref((mowgli_json_t *) cur->data); + mowgli_node_delete(cur, n->v.v_array); + } + + mowgli_list_free(n->v.v_array); +} + +mowgli_json_t * +mowgli_json_create_object(void) +{ + mowgli_json_t *n = json_alloc(MOWGLI_JSON_TAG_OBJECT); + + n->v.v_object = mowgli_patricia_create(NULL); + return n; +} + +static void +destroy_extra_object_cb(const char *key, void *data, void *privdata) +{ + mowgli_json_decref((mowgli_json_t *) data); +} + +static void +destroy_extra_object(mowgli_json_t *n) +{ + mowgli_patricia_destroy(n->v.v_object, destroy_extra_object_cb, NULL); +} + +/* + * 3. SERIALIZER (A.K.A. FORMATTER, PRINTER, ETC.) + */ + +#define TAB_STRING " " +#define TAB_LEN 4 + +static void +serialize_pretty_indent(mowgli_json_output_t *out, int pretty) +{ + int i; + + for (i = 0; i < pretty; i++) + out->append(out, TAB_STRING, TAB_LEN); +} + +static void +serialize_pretty_break(mowgli_json_output_t *out, int pretty) +{ + if (pretty < 1) + return; + + out->append_char(out, '\n'); +} + +static int +serialize_pretty_increment(int pretty) +{ + return pretty > 0 ? pretty + 1 : 0; +} + +static void +serialize_boolean(mowgli_json_t *n, mowgli_json_output_t *out, int pretty) +{ + if (n->v.v_bool) + out->append(out, "true", 4); + else + out->append(out, "false", 5); +} + +static void +serialize_int(mowgli_json_t *n, mowgli_json_output_t *out, int pretty) +{ + char buf[32]; + size_t len; + + len = snprintf(buf, 32, "%d", n->v.v_int); + out->append(out, buf, len); +} + +static void +serialize_float(mowgli_json_t *n, mowgli_json_output_t *out, int pretty) +{ + char buf[32]; + size_t len; + + len = snprintf(buf, 32, "%g", n->v.v_float); + out->append(out, buf, len); +} + +static const char *serialize_hex_digits = "0123456789abcdef"; +static const char *serialize_escape = "\"\\\b\f\n\r\t"; +static void +serialize_string_data(const char *p, size_t len, mowgli_json_output_t *out) +{ + unsigned i; + unsigned char c; + + out->append_char(out, '"'); + + for (i = 0; i < len; i++) + { + c = p[i]; + + if (strchr(serialize_escape, c)) + { + out->append_char(out, '\\'); + + switch (c) + { + case '"': out->append_char(out, '"'); break; + case '\\': out->append_char(out, '\\'); break; + + // case '/': out->append_char(out, '/'); break; + case '\b': out->append_char(out, 'b'); break; + case '\f': out->append_char(out, 'f'); break; + case '\n': out->append_char(out, 'n'); break; + case '\r': out->append_char(out, 'r'); break; + case '\t': out->append_char(out, 't'); break; + default:// hurrr + out->append_char(out, c); + } + } + else if ((c < 0x20) || (c > 0x7f)) + { + out->append_char(out, '\\'); + + /* XXX: \u output does not do UTF-8 */ + out->append_char(out, 'u'); + out->append_char(out, '0'); + out->append_char(out, '0'); + out->append_char(out, serialize_hex_digits[(c >> 4) & 0xf]); + out->append_char(out, serialize_hex_digits[(c >> 0) & 0xf]); + } + else + { + out->append_char(out, c); + } + } + + out->append_char(out, '"'); +} + +static void +serialize_string(mowgli_json_t *n, mowgli_json_output_t *out, int pretty) +{ + serialize_string_data(n->v.v_string->str, n->v.v_string->pos, out); +} + +static void +serialize_array(mowgli_json_t *n, mowgli_json_output_t *out, int pretty) +{ + mowgli_node_t *cur; + + out->append_char(out, '['); + serialize_pretty_break(out, pretty); + + MOWGLI_LIST_FOREACH(cur, n->v.v_array->head) + { + serialize_pretty_indent(out, pretty); + mowgli_json_serialize(cur->data, out, serialize_pretty_increment(pretty)); + + if (cur->next != NULL) + out->append_char(out, ','); + + serialize_pretty_break(out, pretty); + } + + serialize_pretty_indent(out, pretty - 1); + out->append_char(out, ']'); +} + +struct serialize_object_priv /* lol, this is bullshit */ +{ + int pretty; + int remaining; + mowgli_json_output_t *out; +}; + +static int +serialize_object_cb(const char *key, void *data, void *privdata) +{ + struct serialize_object_priv *priv = privdata; + + priv->remaining--; + + serialize_pretty_indent(priv->out, priv->pretty); + + serialize_string_data(key, strlen(key), priv->out); + priv->out->append_char(priv->out, ':'); + + if (priv->pretty) + priv->out->append_char(priv->out, ' '); + + mowgli_json_serialize(data, priv->out, + serialize_pretty_increment(priv->pretty)); + + if (priv->remaining) + priv->out->append_char(priv->out, ','); + + serialize_pretty_break(priv->out, priv->pretty); + + return 0; +} + +static void +serialize_object(mowgli_json_t *n, mowgli_json_output_t *out, int pretty) +{ + struct serialize_object_priv priv; + + out->append_char(out, '{'); + serialize_pretty_break(out, pretty); + + priv.pretty = pretty; + priv.remaining = mowgli_patricia_size(n->v.v_object); + priv.out = out; + mowgli_patricia_foreach(n->v.v_object, serialize_object_cb, &priv); + + serialize_pretty_indent(out, pretty - 1); + out->append_char(out, '}'); +} + +typedef void (*serializer_t)(mowgli_json_t *, mowgli_json_output_t *, int); +static serializer_t serializers[] = +{ + [MOWGLI_JSON_TAG_BOOLEAN] = serialize_boolean, + [MOWGLI_JSON_TAG_INTEGER] = serialize_int, + [MOWGLI_JSON_TAG_FLOAT] = serialize_float, + [MOWGLI_JSON_TAG_STRING] = serialize_string, + [MOWGLI_JSON_TAG_ARRAY] = serialize_array, + [MOWGLI_JSON_TAG_OBJECT] = serialize_object, +}; + +void +mowgli_json_serialize(mowgli_json_t *n, mowgli_json_output_t *out, int pretty) +{ + if (n && serializers[n->tag]) + serializers[n->tag](n, out, pretty); + else + out->append(out, "null", 4); +} + +static void +to_string_append(mowgli_json_output_t *out, const char *str, size_t len) +{ + mowgli_string_append(out->priv, str, len); +} + +static void +to_string_append_char(mowgli_json_output_t *out, const char c) +{ + mowgli_string_append_char(out->priv, c); +} + +void +mowgli_json_serialize_to_string(mowgli_json_t *n, mowgli_string_t *str, int pretty) +{ + mowgli_json_output_t out; + + out.append = to_string_append; + out.append_char = to_string_append_char; + out.priv = str; + + mowgli_json_serialize(n, &out, pretty); +} + +/* + * 4. DESERIALIZER (A.K.A. PARSER, ETC.) + */ + +/* LL(1) parser format: + + Terminal symbols: { } [ ] : , STR NUM ID + + Rule table: + 0. [invalid] + + 1. := + 2. := + + 3. := + 4. := + 5. := STR + 6. := NUM + 7. := ID + + 8. := { + 9. := } + 10. := + 11. := + 12. := , + 13. := } + 14. := STR : + + 15. := [ + 16. := ] + 17. := + 18. := + 19. := , + 20. := ] + + Transition table: + { } [ ] : , STR NUM ID + --- --- --- --- --- --- --- --- --- + json-document 1 2 + value 3 4 5 6 7 + object 8 + obj-body 9 10 + obj-elems 11 + obj-tail 13 12 + obj-elem 14 + array 15 + arr-body 17 17 16 17 17 17 + arr-elems 18 18 18 18 18 + arr-tail 20 19 + + These two tables are effectively a program for an LL(1) parser. The + hard work has been done. The remaining steps are to attach appropriate + actions to the rules above, and to implement the LL(1) parsing + algorithm. + */ + +enum ll_sym +{ + SYM_NONE, + + TS_BEGIN_OBJECT,/* { */ + TS_END_OBJECT, /* } */ + TS_BEGIN_ARRAY, /* [ */ + TS_END_ARRAY, /* ] */ + TS_NAME_SEP, /* : */ + TS_VALUE_SEP, /* , */ + TS_STRING, + TS_NUMBER, + TS_IDENTIFIER, + + NTS_JSON_DOCUMENT, + NTS_VALUE, + NTS_OBJECT, + NTS_OBJ_BODY, + NTS_OBJ_ELEMS, + NTS_OBJ_TAIL, + NTS_OBJ_ELEM, + NTS_ARRAY, + NTS_ARR_BODY, + NTS_ARR_ELEMS, + NTS_ARR_TAIL, + + SYM_COUNT +}; + +struct ll_token +{ + enum ll_sym sym; + + mowgli_json_t *val; +}; + +#define ERRBUFSIZE 128 + +/* typedef'd to mowgli_json_parse_t in json.h */ +struct _mowgli_json_parse_t +{ + /* output queue */ + mowgli_list_t *out; + + /* error buffer */ + char error[ERRBUFSIZE]; + + /* parser */ + bool multidoc; + mowgli_list_t *build; + enum ll_sym stack[LL_STACK_SIZE]; + + unsigned top; + + /* lexer */ + mowgli_string_t *buf; + enum + { + LEX_LIMBO, + LEX_STRING, + LEX_STRING_ESC, + LEX_STRING_ESC_U, + LEX_NUMBER, + LEX_IDENTIFIER + } lex; + + unsigned lex_u; +}; + +typedef void ll_action_t (mowgli_json_parse_t *, struct ll_token *tok); + +/* Human-readable versions of symbols used in errors, etc. */ +static char *ll_sym_name[] = +{ + [SYM_NONE] = "(none)", + + [TS_BEGIN_OBJECT] = "'{'", + [TS_END_OBJECT] = "'}'", + [TS_BEGIN_ARRAY] = "'['", + [TS_END_ARRAY] = "']'", + [TS_NAME_SEP] = "':'", + [TS_VALUE_SEP] = "','", + [TS_STRING] = "string", + [TS_NUMBER] = "number", + [TS_IDENTIFIER] = "identifier", + + [NTS_JSON_DOCUMENT] = "json-document", + [NTS_VALUE] = "value", + [NTS_OBJECT] = "object", + [NTS_OBJ_BODY] = "object body", + [NTS_OBJ_ELEMS] = "object elements", + [NTS_OBJ_TAIL] = "object tail", + [NTS_OBJ_ELEM] = "object element", + + [NTS_ARRAY] = "array", + [NTS_ARR_BODY] = "array body", + [NTS_ARR_ELEMS] = "array elements", + [NTS_ARR_TAIL] = "array tail", + + [SYM_COUNT] = "(none)", +}; + +/* The LL(1) parser table. Uglier than it could have been, unfortunately */ +static unsigned char ll_table[SYM_COUNT][SYM_COUNT] = +{ + [NTS_JSON_DOCUMENT] = + { + [TS_BEGIN_OBJECT] = 1, + [TS_BEGIN_ARRAY] = 2, + }, + + [NTS_VALUE] = + { + [TS_BEGIN_OBJECT] = 3, + [TS_BEGIN_ARRAY] = 4, + [TS_STRING] = 5, + [TS_NUMBER] = 6, + [TS_IDENTIFIER] = 7, + }, + + [NTS_OBJECT] = + { + [TS_BEGIN_OBJECT] = 8, + }, + [NTS_OBJ_BODY] = + { + [TS_END_OBJECT] = 9, + [TS_STRING] = 10, + }, + [NTS_OBJ_ELEMS] = + { + [TS_STRING] = 11, + }, + [NTS_OBJ_TAIL] = + { + [TS_END_OBJECT] = 13, + [TS_VALUE_SEP] = 12, + }, + [NTS_OBJ_ELEM] = + { + [TS_STRING] = 14, + }, + + [NTS_ARRAY] = + { + [TS_BEGIN_ARRAY] = 15, + }, + [NTS_ARR_BODY] = + { + [TS_BEGIN_OBJECT] = 17, + [TS_BEGIN_ARRAY] = 17, + [TS_END_ARRAY] = 16, + [TS_STRING] = 17, + [TS_NUMBER] = 17, + [TS_IDENTIFIER] = 17, + }, + [NTS_ARR_ELEMS] = + { + [TS_BEGIN_OBJECT] = 18, + [TS_BEGIN_ARRAY] = 18, + [TS_STRING] = 18, + [TS_NUMBER] = 18, + [TS_IDENTIFIER] = 18, + }, + [NTS_ARR_TAIL] = + { + [TS_END_ARRAY] = 20, + [TS_VALUE_SEP] = 19, + }, +}; + +/* The LL(1) rule table */ +static enum ll_sym ll_rules[][3] = +{ + { 0 }, /* 0 */ + + { NTS_OBJECT }, + { NTS_ARRAY }, + + { NTS_OBJECT }, + { NTS_ARRAY }, + { TS_STRING }, /* 5 */ + { TS_NUMBER }, + { TS_IDENTIFIER }, + + { TS_BEGIN_OBJECT, NTS_OBJ_BODY }, + { TS_END_OBJECT }, + { NTS_OBJ_ELEMS }, /* 10 */ + { NTS_OBJ_ELEM, NTS_OBJ_TAIL }, + { TS_VALUE_SEP, NTS_OBJ_ELEMS }, + { TS_END_OBJECT }, + { TS_STRING, TS_NAME_SEP, NTS_VALUE }, + + { TS_BEGIN_ARRAY, NTS_ARR_BODY }, /* 15 */ + { TS_END_ARRAY }, + { NTS_ARR_ELEMS }, + { NTS_VALUE, NTS_ARR_TAIL }, + { TS_VALUE_SEP, NTS_ARR_ELEMS }, + { TS_END_ARRAY }, /* 20 */ +}; + +static struct ll_token * +ll_token_alloc(enum ll_sym sym, mowgli_json_t *val) +{ + struct ll_token *tok; + + tok = mowgli_alloc(sizeof(*tok)); + tok->sym = sym; + tok->val = val; + + return tok; +} + +static void +ll_token_free(struct ll_token *tok) +{ + mowgli_json_decref(tok->val); + mowgli_free(tok); +} + +static bool +parse_out_empty(mowgli_json_parse_t *parse) +{ + return MOWGLI_LIST_LENGTH(parse->out) == 0; +} + +static void +parse_out_enqueue(mowgli_json_parse_t *parse, mowgli_json_t *val) +{ + mowgli_node_add(val, mowgli_node_create(), parse->out); +} + +static mowgli_json_t * +parse_out_dequeue(mowgli_json_parse_t *parse) +{ + mowgli_json_t *n; + mowgli_node_t *head; + + if (MOWGLI_LIST_LENGTH(parse->out) == 0) + return NULL; + + head = parse->out->head; + + if (head == NULL) + return NULL; + + n = head->data; + mowgli_node_delete(head, parse->out); + mowgli_node_free(head); + + return n; +} + +static void +parse_error(mowgli_json_parse_t *parse, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + vsnprintf(parse->error, ERRBUFSIZE, fmt, va); + va_end(va); + + /* TODO: shut down everything, yadda yadda */ +} + +static void +ll_build_push(mowgli_json_parse_t *parse, mowgli_json_t *val) +{ + mowgli_node_add_head(val, mowgli_node_create(), parse->build); +} + +static mowgli_json_t * +ll_build_pop(mowgli_json_parse_t *parse) +{ + mowgli_json_t *n; + mowgli_node_t *head; + + if (MOWGLI_LIST_LENGTH(parse->build) == 0) + return NULL; + + head = parse->build->head; + + if (head == NULL) /* shouldn't happen... */ + return NULL; + + n = head->data; + mowgli_node_delete(head, parse->build); + mowgli_node_free(head); + + return n; +} + +static mowgli_json_t obj_start_marker = +{ + .refcount = JSON_REFCOUNT_CONSTANT, +}; +static mowgli_json_t arr_start_marker = +{ + .refcount = JSON_REFCOUNT_CONSTANT, +}; + +static void +ll_act_echo(mowgli_json_parse_t *parse, struct ll_token *tok) +{ + ll_build_push(parse, mowgli_json_incref(tok->val)); +} + +static void +ll_act_obj_start(mowgli_json_parse_t *parse, struct ll_token *tok) +{ + ll_build_push(parse, &obj_start_marker); +} + +static void +ll_act_obj_end(mowgli_json_parse_t *parse, struct ll_token *tok) +{ + mowgli_json_t *obj; + mowgli_json_t *key, *val; + + obj = mowgli_json_incref(mowgli_json_create_object()); + + for (;;) + { + val = ll_build_pop(parse); + + if (val == &obj_start_marker) + break; + + key = ll_build_pop(parse); + + if (key == &obj_start_marker) + break; /* should never happen, but in case */ + + if (MOWGLI_JSON_TAG(key) != MOWGLI_JSON_TAG_STRING) + break; /* should also never happen */ + + mowgli_json_object_add(obj, MOWGLI_JSON_STRING_STR(key), val); + mowgli_json_decref(key); + mowgli_json_decref(val); + } + + ll_build_push(parse, obj); +} + +static void +ll_act_arr_start(mowgli_json_parse_t *parse, struct ll_token *tok) +{ + ll_build_push(parse, &arr_start_marker); +} + +static void +ll_act_arr_end(mowgli_json_parse_t *parse, struct ll_token *tok) +{ + mowgli_json_t *arr; + mowgli_json_t *val; + + arr = mowgli_json_incref(mowgli_json_create_array()); + + for (;;) + { + val = ll_build_pop(parse); + + if (val == &arr_start_marker) + break; + + mowgli_json_array_add_head(arr, val); + mowgli_json_decref(val); + } + + ll_build_push(parse, arr); +} + +static ll_action_t *ll_action[] = +{ + NULL, /* 0 */ + + NULL, + NULL, + + NULL, + NULL, + ll_act_echo, /* 5 */ + ll_act_echo, + ll_act_echo, + + ll_act_obj_start, + ll_act_obj_end, + NULL, /* 10 */ + NULL, + NULL, + ll_act_obj_end, + ll_act_echo, + + ll_act_arr_start, /* 15 */ + ll_act_arr_end, + NULL, + NULL, + NULL, + ll_act_arr_end, /* 20 */ +}; + +static void +ll_push(mowgli_json_parse_t *parse, enum ll_sym sym) +{ + parse->stack[parse->top++] = sym; +} + +static enum ll_sym +ll_pop(mowgli_json_parse_t *parse) +{ + if (parse->top <= 0) + return SYM_NONE; + + return parse->stack[--parse->top]; +} + +static bool +ll_stack_empty(mowgli_json_parse_t *parse) +{ + return parse->top == 0; +} + +static void +ll_cycle(mowgli_json_parse_t *parse) +{ + mowgli_json_t *n; + + n = ll_build_pop(parse); + + if (n != NULL) + parse_out_enqueue(parse, n); + + if (parse->multidoc) + ll_push(parse, NTS_JSON_DOCUMENT); +} + +static void +ll_parse(mowgli_json_parse_t *parse, struct ll_token *tok) +{ + enum ll_sym top, sym; + + int rule, i; + + for (;;) + { + if (ll_stack_empty(parse)) + { + parse_error(parse, "Unexpected %s after JSON input", ll_sym_name[tok->sym]); + break; + } + + top = ll_pop(parse); + + if (top == tok->sym) + { + /* perfect! */ + + if (ll_stack_empty(parse)) + ll_cycle(parse); + + break; + } + + rule = ll_table[top][tok->sym]; + + if (rule == 0) + { + parse_error(parse, "Expected %s, got %s", ll_sym_name[top], + ll_sym_name[tok->sym]); + break; + } + + if (ll_action[rule] != NULL) + ll_action[rule](parse, tok); + + for (i = 2; i >= 0; i--) + { + sym = ll_rules[rule][i]; + + if (sym != SYM_NONE) + ll_push(parse, sym); + } + } + + ll_token_free(tok); +} + +static void +lex_easy(mowgli_json_parse_t *parse, enum ll_sym sym) +{ + ll_parse(parse, ll_token_alloc(sym, NULL)); +} + +static void +lex_append(mowgli_json_parse_t *parse, char c) +{ + mowgli_string_append_char(parse->buf, c); +} + +static mowgli_json_t * +lex_string_scan(char *s, size_t n) +{ + mowgli_json_t *val; + mowgli_string_t *str; + char ubuf[5]; + char *end = s + n; + + val = mowgli_json_incref(mowgli_json_create_string("")); + str = val->v.v_string; + + ubuf[4] = '\0'; /* always */ + + while (s < end) + { + if (*s == '\\') + { + /* Should this be moved to a separate function? */ + s++; + + switch (*s) + { + case '\"': + case '\\': + case '/': + mowgli_string_append_char(str, *s); + break; + + case 'b': mowgli_string_append_char(str, 0x8); break; + case 'f': mowgli_string_append_char(str, 0xc); break; + case 'n': mowgli_string_append_char(str, 0xa); break; + case 'r': mowgli_string_append_char(str, 0xd); break; + case 't': mowgli_string_append_char(str, 0x9); break; + + /* XXX: this is not the right way to parse \u */ + case 'u': + s++; + + if (end - s < 4) + { + /* error */ + } + else + { + memcpy(ubuf, s, 4); + mowgli_string_append_char(str, strtol(ubuf, NULL, 16) & 0xff); + } + + s += 3; /* +3 points to last char */ + break; + + default:/* aww */ + break; + } + } + else + { + mowgli_string_append_char(str, *s); + } + + s++; + } + + return val; +} + +static void +lex_tokenize(mowgli_json_parse_t *parse) +{ + char *s = parse->buf->str; + size_t n = parse->buf->pos; + enum ll_sym sym = SYM_NONE; + mowgli_json_t *val = NULL; + + switch (parse->lex) + { + case LEX_STRING: + sym = TS_STRING; + val = lex_string_scan(s, n); + break; + + case LEX_NUMBER: + + if (strchr(s, '.') || strchr(s, 'e')) + val = mowgli_json_incref(mowgli_json_create_float(strtod(s, NULL))); + + else + val = mowgli_json_incref(mowgli_json_create_integer(strtol(s, NULL, 0))); + + sym = TS_NUMBER; + break; + + case LEX_IDENTIFIER: + sym = TS_IDENTIFIER; + + if (!strcmp(s, "null")) + val = mowgli_json_null; + + else if (!strcmp(s, "true")) + val = mowgli_json_true; + + else if (!strcmp(s, "false")) + val = mowgli_json_false; + + else + val = mowgli_json_null; + + /* error condition! */ + + break; + + default: + + /* we should not be tokenizing here! */ + break; + } + + mowgli_string_reset(parse->buf); + parse->lex = LEX_LIMBO; + + ll_parse(parse, ll_token_alloc(sym, val)); +} + +/* lex_char returns true if it wants the char to be sent through again */ +static bool +lex_char(mowgli_json_parse_t *parse, char c) +{ + switch (parse->lex) + { + case LEX_LIMBO: + + /* the easy ones */ + switch (c) + { + case '{': lex_easy(parse, TS_BEGIN_OBJECT); return false; + case '}': lex_easy(parse, TS_END_OBJECT); return false; + case '[': lex_easy(parse, TS_BEGIN_ARRAY); return false; + case ']': lex_easy(parse, TS_END_ARRAY); return false; + case ':': lex_easy(parse, TS_NAME_SEP); return false; + case ',': lex_easy(parse, TS_VALUE_SEP); return false; + } + + if ((c == '-') || (c == '.') || isdigit(c)) + { + parse->lex = LEX_NUMBER; + return true; + } + else if (isalpha(c)) + { + parse->lex = LEX_IDENTIFIER; + return true; + } + else if (c == '"') + { + parse->lex = LEX_STRING; + return false; + } + else if (isspace(c)) + { + return false; + } + + parse_error(parse, "Cannot process character '%c' in input stream", c); + + return false; + + case LEX_STRING: + + if (c == '\\') + { + lex_append(parse, c); + parse->lex = LEX_STRING_ESC; + } + else if (c == '"') + { + lex_tokenize(parse); + } + else + { + lex_append(parse, c); + } + + return false; + + case LEX_STRING_ESC: + lex_append(parse, c); + + if (c == 'u') + { + parse->lex_u = 0; + parse->lex = LEX_STRING_ESC_U; + } + else + { + parse->lex = LEX_STRING; + } + + return false; + + case LEX_STRING_ESC_U: + lex_append(parse, c); + + parse->lex_u++; + + if (parse->lex_u >= 4) + parse->lex = LEX_STRING; + + return false; + + case LEX_NUMBER: + + if ((c == '-') || (c == '.') || isdigit(c) || (toupper(c) == 'E')) + { + lex_append(parse, c); + return false; + } + else + { + lex_tokenize(parse); + return true; + } + + break; + + case LEX_IDENTIFIER: + + if (isalpha(c)) + { + lex_append(parse, c); + return false; + } + else + { + lex_tokenize(parse); + return true; + } + + break; + } + + /* This should never happen... */ + parse->lex = LEX_LIMBO; + return false; +} + +mowgli_json_parse_t * +mowgli_json_parse_create(bool multidoc) +{ + mowgli_json_parse_t *parse; + + parse = mowgli_alloc(sizeof(*parse)); + + parse->out = mowgli_list_create(); + parse->error[0] = '\0'; + parse->multidoc = multidoc; + parse->build = mowgli_list_create(); + parse->top = 0; + parse->buf = mowgli_string_create(); + parse->lex = LEX_LIMBO; + + ll_push(parse, NTS_JSON_DOCUMENT); + + return parse; +} + +void +mowgli_json_parse_destroy(mowgli_json_parse_t *parse) +{ + mowgli_node_t *n; + + return_if_fail(parse != NULL); + + MOWGLI_LIST_FOREACH(n, parse->out->head) + mowgli_json_decref(n->data); + MOWGLI_LIST_FOREACH(n, parse->build->head) + mowgli_json_decref(n->data); + + mowgli_list_free(parse->out); + mowgli_list_free(parse->build); + mowgli_string_destroy(parse->buf); + + mowgli_free(parse); +} + +void +mowgli_json_parse_reset(mowgli_json_parse_t *parse, bool multidoc) +{ + mowgli_node_t *n, *tn; + + if (parse->out == NULL) + parse->out = mowgli_list_create(); + + if (parse->build == NULL) + parse->build = mowgli_list_create(); + + MOWGLI_LIST_FOREACH_SAFE(n, tn, parse->out->head) + { + mowgli_json_decref(n->data); + mowgli_node_delete(n, parse->out); + } + MOWGLI_LIST_FOREACH_SAFE(n, tn, parse->build->head) + { + mowgli_json_decref(n->data); + mowgli_node_delete(n, parse->build); + } + + parse->error[0] = '\0'; + parse->multidoc = multidoc; + parse->top = 0; + + if (parse->buf == NULL) + parse->buf = mowgli_string_create(); + else + mowgli_string_reset(parse->buf); + + parse->lex = LEX_LIMBO; + + ll_push(parse, NTS_JSON_DOCUMENT); +} + +void +mowgli_json_parse_data(mowgli_json_parse_t *parse, const char *data, size_t len) +{ + while (len > 0) + { + /* We cannot continue parsing if there's an error! */ + if (mowgli_json_parse_error(parse)) + return; + + while (lex_char(parse, *data)) + { } + + data++; + len--; + } +} + +char * +mowgli_json_parse_error(mowgli_json_parse_t *parse) +{ + if (parse->error[0]) + return parse->error; + + return NULL; +} + +bool +mowgli_json_parse_more(mowgli_json_parse_t *parse) +{ + return !parse_out_empty(parse); +} + +mowgli_json_t * +mowgli_json_parse_next(mowgli_json_parse_t *parse) +{ + return parse_out_dequeue(parse); +} + +/* Note: Static parsers like these should last the life of the program, + since mowgli_json_parse_destroy will attempt to mowgli_free the + parser. */ + +static mowgli_json_parse_t static_parser; + +mowgli_json_t * +mowgli_json_parse_file(const char *path) +{ + char *s; + char buf[512]; + size_t n; + mowgli_json_t *ret; + FILE *f; + + mowgli_json_parse_reset(&static_parser, false); + + f = fopen(path, "r"); + + if (f == NULL) + { + mowgli_log("Could not open %s for reading", path); + return NULL; + } + + s = NULL; + + while (!feof(f) && s == NULL) + { + n = fread(buf, 1, 512, f); + mowgli_json_parse_data(&static_parser, buf, n); + + s = mowgli_json_parse_error(&static_parser); + } + + if (s != NULL) + { + mowgli_log("%s: %s", path, s); + ret = NULL; + } + else + { + ret = mowgli_json_parse_next(&static_parser); + + if (ret == NULL) + mowgli_log("%s: Incomplete JSON document", path); + } + + fclose(f); + + return ret; +} + +mowgli_json_t * +mowgli_json_parse_string(const char *data) +{ + mowgli_json_t *ret; + char *s; + + mowgli_json_parse_reset(&static_parser, false); + + mowgli_json_parse_data(&static_parser, data, strlen(data)); + + if ((s = mowgli_json_parse_error(&static_parser)) != NULL) + { + mowgli_log("%s", s); + ret = NULL; + } + else + { + ret = mowgli_json_parse_next(&static_parser); + + if (ret == NULL) + mowgli_log("Incomplete JSON document"); + } + + return ret; +} diff --git a/src/libmowgli/ext/json.h b/src/libmowgli/ext/json.h new file mode 100644 index 0000000..247018a --- /dev/null +++ b/src/libmowgli/ext/json.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2012 Alex Iadicicco + * Rights to this code are as documented in COPYING. + * + * Structs and functions for interacting with JSON documents from C + */ + +/* A note about refcounting: + + Since JSON cannot represent recursive structures, it makes sense + to use refcounting. If a recursive structure is created then it's + guaranteed to be the programmer's fault, and the programmer deserves + every memory leak he gets. + + When cared for and fed daily, refcounting is a very nifty tool. Entire + structures can be destroyed cleanly by a single mowgli_json_decref. To + fully take advantage of this, know the refcounting rules: + + o JSON objects as arguments should NEVER have a reference for + the callee. If the callee wants to keep the object somewhere, + they will incref themselves. + + o When returning a JSON object, be sure to leave a single reference + for the caller. (If you tried to decref before returning, you + could potentially drop the refcount to zero.) + + o Newly created structures are the sole exception to the previous + rule. This is because it is useful to be able to use constructors + as arguments to functions as follows: + mowgli_json_object_add(obj, "sum", mowgli_json_create_integer(10)); + Note that this ONLY applies to the mowgli_json_create_* + constructors provided by mowgli.json. The typical case of + assigning a new structure to a variable name then looks like this: + my_integer = mowgli_json_incref(mowgli_json_create_integer(0)); + + Since failure to pay attention to reference counts will cause memory + problems, *always double check your reference counting*! + + --aji */ + +#ifndef MOWGLI_JSON_H +#define MOWGLI_JSON_H + +/* Types with public definitons */ +typedef enum +{ + MOWGLI_JSON_TAG_NULL, + MOWGLI_JSON_TAG_BOOLEAN, + + /* JSON does not distinguish between integers or floating points + (they are both just number types), but in C we are forced to + make the distinction */ + MOWGLI_JSON_TAG_INTEGER, + MOWGLI_JSON_TAG_FLOAT, + MOWGLI_JSON_TAG_STRING, + MOWGLI_JSON_TAG_ARRAY, + MOWGLI_JSON_TAG_OBJECT, +} mowgli_json_tag_t; +typedef struct _mowgli_json_t mowgli_json_t; + +/* Types whose definitons are kept private */ +typedef struct _mowgli_json_parse_t mowgli_json_parse_t; + +struct _mowgli_json_t +{ + mowgli_json_tag_t tag; + int refcount; + + union + { + bool v_bool; + int v_int; + double v_float; + mowgli_string_t *v_string; + mowgli_list_t *v_array; + mowgli_patricia_t *v_object; + } v; +}; + +/* Helper macros useful for cleanly interacting with mowgli_json_t + structs. These are just helpers and are not intended to provide a + consistent interface. They are as likely to change as the mowgli_json_t + struct itself. */ +#define MOWGLI_JSON_TAG(n) ((n)->tag) +#define MOWGLI_JSON_BOOLEAN(n) ((n)->v.v_bool) +#define MOWGLI_JSON_INTEGER(n) ((n)->v.v_int) +#define MOWGLI_JSON_FLOAT(n) ((n)->v.v_float) +#define MOWGLI_JSON_NUMBER(n) ((n)->tag == MOWGLI_JSON_TAG_FLOAT ? \ + (n)->v.v_float : (n)->v.v_int) +#define MOWGLI_JSON_STRING(n) ((n)->v.v_string) +#define MOWGLI_JSON_STRING_STR(n) ((n)->v.v_string->str) +#define MOWGLI_JSON_STRING_LEN(n) ((n)->v.v_string->pos) +#define MOWGLI_JSON_ARRAY(n) ((n)->v.v_array) +#define MOWGLI_JSON_OBJECT(n) ((n)->v.v_object) + +/* Users of the JSON parser/formatter are not required to use these + constants, but the parser will ALWAYS parse the symbols "null", + "true", and "false" into these constants */ +extern mowgli_json_t *mowgli_json_null; +extern mowgli_json_t *mowgli_json_true; +extern mowgli_json_t *mowgli_json_false; + +/* These simply return the node argument. If the node was destroyed, + the return value will be NULL. Note that in all other cases (invalid + refcount, unknown type, etc.) the node will be returned untouched */ +extern mowgli_json_t *mowgli_json_incref(mowgli_json_t *n); +extern mowgli_json_t *mowgli_json_decref(mowgli_json_t *n); + +extern mowgli_json_t *mowgli_json_create_integer(int v_int); +extern mowgli_json_t *mowgli_json_create_float(double v_float); + +/* #define mowgli_json_create_number(V) _Generic((V), \ + int: mowgli_json_create_integer, \ + double: mowgli_json_create_float)(V) */ +extern mowgli_json_t *mowgli_json_create_string_n(const char *str, size_t len); +extern mowgli_json_t *mowgli_json_create_string(const char *str); +extern mowgli_json_t *mowgli_json_create_array(void); +extern mowgli_json_t *mowgli_json_create_object(void); + +#include "json-inline.h" + +typedef struct _mowgli_json_output_t mowgli_json_output_t; + +struct _mowgli_json_output_t +{ + void (*append)(mowgli_json_output_t *out, const char *str, size_t len); + void (*append_char)(mowgli_json_output_t *out, const char c); + void *priv; +}; + +extern void mowgli_json_serialize(mowgli_json_t *n, mowgli_json_output_t *out, int pretty); +extern void mowgli_json_serialize_to_string(mowgli_json_t *n, mowgli_string_t *str, int pretty); + +/* extended parsing interface. The 'multidoc' parameter here indicates + whether we intend to parse multiple documents from a single data source + or not. If you are expecting exactly one complete JSON document, + indicate 'false'. */ +extern mowgli_json_parse_t *mowgli_json_parse_create(bool multidoc); +extern void mowgli_json_parse_destroy(mowgli_json_parse_t *parse); +extern void mowgli_json_parse_reset(mowgli_json_parse_t *parse, bool multidoc); +extern void mowgli_json_parse_data(mowgli_json_parse_t *parse, const char *data, size_t len); +extern char *mowgli_json_parse_error(mowgli_json_parse_t *parse); +extern bool mowgli_json_parse_more(mowgli_json_parse_t *parse); +extern mowgli_json_t *mowgli_json_parse_next(mowgli_json_parse_t *parse); + +/* Simple parsing interface. These expect the given data source to + represent exactly one complete JSON document */ +extern mowgli_json_t *mowgli_json_parse_file(const char *path); +extern mowgli_json_t *mowgli_json_parse_string(const char *data); + +#endif diff --git a/src/libmowgli/ext/proctitle.c b/src/libmowgli/ext/proctitle.c index 91885d5..ee3a764 100644 --- a/src/libmowgli/ext/proctitle.c +++ b/src/libmowgli/ext/proctitle.c @@ -1,9 +1,10 @@ -/* +/* * Code has been calqued from PostgreSQL 9.1 by Elizabeth J. Myers. * Below is their copyright header. * * Do note I've made extensive changes to this code, including adding - * Linux (and Irix?) prctl support. + * Linux (and Irix?) prctl support. Also added support for searching for + * argc/argv. */ /*-------------------------------------------------------------------- @@ -17,26 +18,28 @@ * * Copyright (c) 2000-2011, PostgreSQL Global Development Group * various details abducted from various places - *-------------------------------------------------------------------- + ***-------------------------------------------------------------------- */ #include "mowgli.h" #ifdef HAVE_SYS_PSTAT_H -#include /* for HP-UX */ +# include /* for HP-UX */ #endif #ifdef HAVE_PS_STRINGS -#include /* for old BSD */ -#include +# include /* for old BSD */ +# include #endif -#if defined(__darwin__) -#include +#ifdef MOWGLI_OS_OSX +# include #endif #ifdef HAVE_SYS_PRCTL_H -#include +# include #endif +#if !defined(MOWGLI_OS_WIN) && !defined(MOWGLI_OS_OSX) extern char **environ; +#endif /* * Alternative ways of updating ps display: @@ -66,63 +69,62 @@ extern char **environ; * (This is the default, as it is safest.) */ #if defined(HAVE_SETPROCTITLE) -#define MOWGLI_SETPROC_USE_SETPROCTITLE +# define MOWGLI_SETPROC_USE_SETPROCTITLE #elif defined(PR_SET_NAME) && defined(HAVE_SYS_PRCTL_H) -#define MOWGLI_SETPROC_USE_PRCTL +# define MOWGLI_SETPROC_USE_PRCTL #elif defined(HAVE_PSTAT) && defined(PSTAT_SETCMD) -#define MOWGLI_SETPROC_USE_PSTAT +# define MOWGLI_SETPROC_USE_PSTAT #elif defined(HAVE_PS_STRINGS) -#define MOWGLI_SETPROC_USE_PS_STRINGS +# define MOWGLI_SETPROC_USE_PS_STRINGS #elif (defined(BSD) || defined(__bsdi__) || defined(__hurd__)) && !defined(__darwin__) -#define MOWGLI_SETPROC_USE_CHANGE_ARGV +# define MOWGLI_SETPROC_USE_CHANGE_ARGV #elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__ksr__) || defined(__osf__) || defined(__svr4__) || defined(__svr5__) || defined(__darwin__) -#define MOWGLI_SETPROC_USE_CLOBBER_ARGV +# define MOWGLI_SETPROC_USE_CLOBBER_ARGV #elif defined(WIN32) -#define MOWGLI_SETPROC_USE_WIN32 +# define MOWGLI_SETPROC_USE_WIN32 #else -#define MOWGLI_SETPROC_USE_NONE +# define MOWGLI_SETPROC_USE_NONE #endif - /* Different systems want the buffer padded differently */ #if defined(_AIX) || defined(__linux__) || defined(__svr4__) || defined(__darwin__) -#define PS_PADDING '\0' +# define PS_PADDING '\0' #else -#define PS_PADDING ' ' +# define PS_PADDING ' ' #endif - #ifndef MOWGLI_SETPROC_USE_CLOBBER_ARGV + /* all but one option need a buffer to write their ps line in */ -#define PS_BUFFER_SIZE 256 +# define PS_BUFFER_SIZE 256 static char ps_buffer[PS_BUFFER_SIZE]; static const size_t ps_buffer_size = PS_BUFFER_SIZE; -#else /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ -static char *ps_buffer; /* will point to argv area */ +#else /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ +static char *ps_buffer; /* will point to argv area */ static size_t ps_buffer_size; /* space determined at run time */ -#endif /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ +#endif /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ static size_t ps_buffer_fixed_size; -static size_t ps_buffer_cur_len; /* nominal strlen(ps_buffer) */ +static size_t ps_buffer_cur_len;/* nominal strlen(ps_buffer) */ /* save the original argv[] location here */ static int save_argc; static char **save_argv; +int mowgli_argc = 0; +char **mowgli_argv = NULL; + /* - * Call this early in startup to save the original argc/argv values. + * Save the original argc/argv values. * If needed, we make a copy of the original argv[] array to preserve it * from being clobbered by subsequent ps_display actions. - * - * (The original argv[] will not be overwritten by this routine, but may be - * overwritten during mowgli_proctitle_set. Also, the physical location of the - * environment strings may be moved, so this should be called before any code - * that might try to hang onto a getenv() result.) */ char ** mowgli_proctitle_init(int argc, char **argv) { - save_argc = argc; + if ((argc == 0) || (argv == NULL)) + save_argc = argc; + save_argv = argv; #if defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV) @@ -139,12 +141,10 @@ mowgli_proctitle_init(int argc, char **argv) * check for contiguous argv strings */ for (i = 0; i < argc; i++) - { - if (i == 0 || end_of_area + 1 == argv[i]) + if ((i == 0) || (end_of_area + 1 == argv[i])) end_of_area = argv[i] + strlen(argv[i]); - } - if (end_of_area == NULL) /* probably can't happen? */ + if (end_of_area == NULL)/* probably can't happen? */ { ps_buffer = NULL; ps_buffer_size = 0; @@ -155,10 +155,8 @@ mowgli_proctitle_init(int argc, char **argv) * check for contiguous environ strings following argv */ for (i = 0; environ[i] != NULL; i++) - { if (end_of_area + 1 == environ[i]) end_of_area = environ[i] + strlen(environ[i]); - } ps_buffer = argv[0]; ps_buffer_size = end_of_area - argv[0]; @@ -167,12 +165,14 @@ mowgli_proctitle_init(int argc, char **argv) * move the environment out of the way */ new_environ = (char **) mowgli_alloc((i + 1) * sizeof(char *)); + for (i = 0; environ[i] != NULL; i++) new_environ[i] = mowgli_strdup(environ[i]); + new_environ[i] = NULL; environ = new_environ; -#endif /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ +#endif /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ #if defined(MOWGLI_SETPROC_USE_CHANGE_ARGV) || defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV) @@ -188,24 +188,30 @@ mowgli_proctitle_init(int argc, char **argv) */ char **new_argv; - int i; + int j; new_argv = (char **) mowgli_alloc((argc + 1) * sizeof(char *)); - for (i = 0; i < argc; i++) - new_argv[i] = mowgli_strdup(argv[i]); + + for (j = 0; j < argc; j++) + new_argv[j] = mowgli_strdup(argv[j]); + new_argv[argc] = NULL; -#if defined(__darwin__) +# ifdef MOWGLI_OS_OSX + /* * Darwin (and perhaps other NeXT-derived platforms?) has a static * copy of the argv pointer, which we may fix like so: */ *_NSGetArgv() = new_argv; -#endif +# endif argv = new_argv; -#endif /* MOWGLI_SETPROC_USE_CHANGE_ARGV or MOWGLI_SETPROC_USE_CLOBBER_ARGV */ +#endif /* MOWGLI_SETPROC_USE_CHANGE_ARGV or MOWGLI_SETPROC_USE_CLOBBER_ARGV */ + + mowgli_argc = argc; + mowgli_argv = argv; return argv; } @@ -216,10 +222,12 @@ mowgli_proctitle_set(const char *fmt, ...) #ifndef MOWGLI_SETPROC_USE_NONE va_list va; -#if defined(MOWGLI_SETPROC_USE_CHANGE_ARGV) || defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV) +# if defined(MOWGLI_SETPROC_USE_CHANGE_ARGV) || defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV) + if (!save_argv) return; -#endif + +# endif va_start(va, fmt); vsnprintf(ps_buffer, ps_buffer_size, fmt, va); @@ -229,45 +237,46 @@ mowgli_proctitle_set(const char *fmt, ...) ps_buffer_cur_len = ps_buffer_fixed_size = strlen(ps_buffer); -#ifdef MOWGLI_SETPROC_USE_CHANGE_ARGV +# ifdef MOWGLI_SETPROC_USE_CHANGE_ARGV save_argv[0] = ps_buffer; save_argv[1] = NULL; -#endif +# endif + +# ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV -#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV for (int i = 1; i < save_argc; i++) save_argv[i] = ps_buffer + ps_buffer_size; /* Pad unused bytes */ - printf("%d %d\n", ps_buffer_size, ps_buffer_cur_len); memset(ps_buffer + ps_buffer_cur_len, PS_PADDING, ps_buffer_size - ps_buffer_cur_len + 1); -#endif +# endif -#ifdef MOWGLI_SETPROC_USE_SETPROCTITLE +# ifdef MOWGLI_SETPROC_USE_SETPROCTITLE setproctitle("%s", ps_buffer); -#endif +# endif + +# ifdef MOWGLI_SETPROC_USE_PRCTL -#ifdef MOWGLI_SETPROC_USE_PRCTL /* Limit us to 16 chars to be safe */ char procbuf[16]; mowgli_strlcpy(procbuf, ps_buffer, sizeof(procbuf)); prctl(PR_SET_NAME, procbuf, 0, 0, 0); - printf("%s\n", procbuf); -#endif +# endif -#ifdef MOWGLI_SETPROC_USE_PSTAT +# ifdef MOWGLI_SETPROC_USE_PSTAT union pstun pst; pst.pst_command = ps_buffer; pstat(PSTAT_SETCMD, pst, ps_buffer_cur_len, 0, 0); -#endif /* MOWGLI_SETPROC_USE_PSTAT */ +# endif /* MOWGLI_SETPROC_USE_PSTAT */ -#ifdef MOWGLI_SETPROC_USE_PS_STRINGS +# ifdef MOWGLI_SETPROC_USE_PS_STRINGS PS_STRINGS->ps_nargvstr = 1; PS_STRINGS->ps_argvstr = ps_buffer; -#endif /* MOWGLI_SETPROC_USE_PS_STRINGS */ +# endif /* MOWGLI_SETPROC_USE_PS_STRINGS */ + +# ifdef MOWGLI_SETPROC_USE_WIN32 -#ifdef MOWGLI_SETPROC_USE_WIN32 /* * Win32 does not support showing any changed arguments. To make it at * all possible to track which backend is doing what, we create a @@ -282,11 +291,10 @@ mowgli_proctitle_set(const char *fmt, ...) sprintf(name, "mowgli_ident(%d): %s", getpid(), ps_buffer); ident_handle = CreateEvent(NULL, TRUE, FALSE, name); -#endif /* MOWGLI_SETPROC_USE_WIN32 */ -#endif /* not MOWGLI_SETPROC_USE_NONE */ +# endif /* MOWGLI_SETPROC_USE_WIN32 */ +#endif /* not MOWGLI_SETPROC_USE_NONE */ } - /* * Returns what's currently in the ps display, in case someone needs * it. Note that only the activity part is returned. On some platforms @@ -297,12 +305,14 @@ const char * mowgli_proctitle_get(int *displen) { #ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV + /* If ps_buffer is a pointer, it might still be null */ if (!ps_buffer) { *displen = 0; return ""; } + #endif *displen = (int) (ps_buffer_cur_len - ps_buffer_fixed_size); diff --git a/src/libmowgli/ext/proctitle.h b/src/libmowgli/ext/proctitle.h index 479ee84..cee99f0 100644 --- a/src/libmowgli/ext/proctitle.h +++ b/src/libmowgli/ext/proctitle.h @@ -6,7 +6,7 @@ * * src/include/utils/ps_status.h * - *------------------------------------------------------------------------- + ***------------------------------------------------------------------------- */ #ifndef __PS_STATUS_H__ @@ -14,10 +14,13 @@ extern bool mowgli_proctitle_update; +extern char **mowgli_argv; +extern int mowgli_argc; + extern char **mowgli_proctitle_init(int argc, char **argv); extern void mowgli_proctitle_set(const char *fmt, ...); extern const char *mowgli_proctitle_get(int *displen); -#endif /* __PS_STATUS_H__ */ +#endif /* __PS_STATUS_H__ */ diff --git a/src/libmowgli/ext/program_opts.c b/src/libmowgli/ext/program_opts.c index 75acd53..d07c063 100644 --- a/src/libmowgli/ext/program_opts.c +++ b/src/libmowgli/ext/program_opts.c @@ -58,21 +58,14 @@ mowgli_program_opts_lookup_name(mowgli_program_opts_t *opts, size_t opts_size, c size_t i; if (strlen(name) > 1) - { for (i = 0; i < opts_size; i++) - { if (!strcasecmp(name, opts[i].longopt)) return &opts[i]; - } - } - else - { - for (i = 0; i < opts_size; i++) - { - if (*name == opts[i].smallopt) - return &opts[i]; - } - } + + else + for (i = 0; i < opts_size; i++) + if (*name == opts[i].smallopt) + return &opts[i]; return NULL; } @@ -94,6 +87,7 @@ mowgli_program_opts_convert(const mowgli_program_opts_t *opts, size_t opts_size) g_opts[i].name = opts[i].longopt; g_opts[i].iflag = i; + if (opts[i].has_param) g_opts[i].has_arg = 1; } @@ -118,6 +112,7 @@ mowgli_program_opts_compute_optstr(const mowgli_program_opts_t *opts, size_t opt continue; *p++ = opts[i].smallopt; + if (opts[i].has_param) *p++ = ':'; } @@ -132,7 +127,7 @@ mowgli_program_opts_dispatch(const mowgli_program_opts_t *opt, const char *optar { return_if_fail(opt != NULL); - if (opt->has_param && optarg == NULL) + if (opt->has_param && (optarg == NULL)) { fprintf(stderr, "no optarg for option %s", opt->longopt); return; @@ -163,24 +158,26 @@ mowgli_program_opts_parse(const mowgli_program_opts_t *opts, size_t opts_size, i const mowgli_program_opts_t *opt = NULL; c = mowgli_getopt_long(*argc, *argv, shortops, g_opts, &opt_index); + if (c == -1) break; switch (c) { case 0: + /* long-option was provided, resolve it. */ opt = &opts[g_opts[opt_index].iflag]; break; default: + for (i = 0; i < opts_size; i++) - { if (opts[i].smallopt == c) { opt = &opts[i]; break; } - } + break; } diff --git a/src/libmowgli/ext/program_opts.h b/src/libmowgli/ext/program_opts.h index f418b96..e79580d 100644 --- a/src/libmowgli/ext/program_opts.h +++ b/src/libmowgli/ext/program_opts.h @@ -26,7 +26,8 @@ typedef void (*mowgli_program_opts_consumer_t)(const char *arg, void *userdata); -typedef struct { +typedef struct +{ const char *longopt; const char smallopt; bool has_param; diff --git a/src/libmowgli/linebuf/linebuf.c b/src/libmowgli/linebuf/linebuf.c index 8b13040..0395680 100644 --- a/src/libmowgli/linebuf/linebuf.c +++ b/src/libmowgli/linebuf/linebuf.c @@ -28,9 +28,18 @@ static mowgli_heap_t *linebuf_heap = NULL; static void mowgli_linebuf_read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata); static void mowgli_linebuf_write_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata); static void mowgli_linebuf_process(mowgli_linebuf_t *linebuf); +static void mowgli_linebuf_do_shutdown(mowgli_linebuf_t *linebuf); static int mowgli_linebuf_error(mowgli_vio_t *vio); +#ifdef NOTYET +static mowgli_vio_evops_t linebuf_evops = +{ + .read_cb = mowgli_linebuf_read_data, + .write_cb = mowgli_linebuf_write_data +}; +#endif + mowgli_linebuf_t * mowgli_linebuf_create(mowgli_linebuf_readline_cb_t *cb, void *userdata) { @@ -41,7 +50,8 @@ mowgli_linebuf_create(mowgli_linebuf_readline_cb_t *cb, void *userdata) linebuf = mowgli_heap_alloc(linebuf_heap); - linebuf->delim = "\r\n"; /* Sane default */ + /* Sane default */ + mowgli_linebuf_delim(linebuf, "\r\n", "\r\n"); linebuf->readline_cb = cb; linebuf->flags = 0; @@ -51,7 +61,9 @@ mowgli_linebuf_create(mowgli_linebuf_readline_cb_t *cb, void *userdata) mowgli_linebuf_setbuflen(&(linebuf->readbuf), 65536); mowgli_linebuf_setbuflen(&(linebuf->writebuf), 65536); - linebuf->return_normal_strings = true; /* This is generally what you want, but beware of malicious \0's in input data! */ + linebuf->eventloop = NULL; + + linebuf->return_normal_strings = true; /* This is generally what you want, but beware of malicious \0's in input data! */ linebuf->userdata = userdata; @@ -61,22 +73,43 @@ mowgli_linebuf_create(mowgli_linebuf_readline_cb_t *cb, void *userdata) } /* Attach the linebuf instance to the eventloop -- socket must be created first with VIO instance! */ -void mowgli_linebuf_attach_to_eventloop(mowgli_linebuf_t *linebuf, mowgli_eventloop_t *eventloop) +void +mowgli_linebuf_attach_to_eventloop(mowgli_linebuf_t *linebuf, mowgli_eventloop_t *eventloop) { return_if_fail(eventloop != NULL); return_if_fail(linebuf != NULL); return_if_fail(linebuf->vio != NULL); return_if_fail((linebuf->vio->flags & MOWGLI_VIO_FLAGS_ISCLOSED) == 0); - mowgli_vio_eventloop_attach(linebuf->vio, eventloop); - mowgli_pollable_setselect(eventloop, linebuf->vio->io, MOWGLI_EVENTLOOP_IO_READ, mowgli_linebuf_read_data); - mowgli_pollable_setselect(eventloop, linebuf->vio->io, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); +#ifdef NOTYET + mowgli_vio_eventloop_attach(linebuf->vio, eventloop, &linebuf_evops); +#else + mowgli_vio_eventloop_attach(linebuf->vio, eventloop, NULL); +#endif + mowgli_pollable_setselect(eventloop, linebuf->vio->io.e, MOWGLI_EVENTLOOP_IO_READ, mowgli_linebuf_read_data); + mowgli_pollable_setselect(eventloop, linebuf->vio->io.e, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); linebuf->eventloop = eventloop; } -void mowgli_linebuf_destroy(mowgli_linebuf_t *linebuf) +/* Detach the linebuf instance from the eventloop */ +void +mowgli_linebuf_detach_from_eventloop(mowgli_linebuf_t *linebuf) +{ + return_if_fail(linebuf != NULL); + return_if_fail(linebuf->eventloop != NULL); + mowgli_pollable_setselect(linebuf->eventloop, linebuf->vio->io.e, MOWGLI_EVENTLOOP_IO_READ, NULL); + mowgli_pollable_setselect(linebuf->eventloop, linebuf->vio->io.e, MOWGLI_EVENTLOOP_IO_WRITE, NULL); + mowgli_vio_eventloop_detach(linebuf->vio); + linebuf->eventloop = NULL; +} + +void +mowgli_linebuf_destroy(mowgli_linebuf_t *linebuf) { + if (linebuf->eventloop != NULL) + mowgli_linebuf_detach_from_eventloop(linebuf); + mowgli_vio_destroy(linebuf->vio); mowgli_free(linebuf->readbuf.buffer); @@ -84,18 +117,21 @@ void mowgli_linebuf_destroy(mowgli_linebuf_t *linebuf) mowgli_heap_free(linebuf_heap, linebuf); } -void mowgli_linebuf_setbuflen(mowgli_linebuf_buf_t *buffer, size_t buflen) +void +mowgli_linebuf_setbuflen(mowgli_linebuf_buf_t *buffer, size_t buflen) { return_if_fail(buffer != NULL); if (buffer->buffer == NULL) + { buffer->buffer = mowgli_alloc(buflen); + } else { char tmpbuf[buffer->maxbuflen]; if (buffer->buflen > 0) - memcpy(tmpbuf, buffer->buffer, buffer->maxbuflen); /* Copy into tmp buffer */ + memcpy(tmpbuf, buffer->buffer, buffer->maxbuflen); /* Copy into tmp buffer */ /* Free old buffer and reallocate */ mowgli_free(buffer->buffer); @@ -109,9 +145,22 @@ void mowgli_linebuf_setbuflen(mowgli_linebuf_buf_t *buffer, size_t buflen) buffer->maxbuflen = buflen; } -static void mowgli_linebuf_read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +void +mowgli_linebuf_delim(mowgli_linebuf_t *linebuf, const char *delim, const char *endl) { - mowgli_linebuf_t *linebuf = (mowgli_linebuf_t *)userdata; + return_if_fail(linebuf != NULL); + return_if_fail(delim != NULL && *delim != '\0'); + return_if_fail(endl != NULL && *endl != '\0'); + + linebuf->delim = delim; + linebuf->endl = endl; + linebuf->endl_len = strlen(endl); +} + +static void +mowgli_linebuf_read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +{ + mowgli_linebuf_t *linebuf = (mowgli_linebuf_t *) userdata; mowgli_linebuf_buf_t *buffer = &(linebuf->readbuf); void *bufpos; size_t offset; @@ -129,9 +178,12 @@ static void mowgli_linebuf_read_data(mowgli_eventloop_t *eventloop, mowgli_event if ((ret = mowgli_vio_read(linebuf->vio, bufpos, offset)) <= 0) { - if (linebuf->vio->error.code != MOWGLI_VIO_ERR_NONE) - /* Let's never come back here */ - mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_READ, NULL); + if (linebuf->vio->error.type == MOWGLI_VIO_ERR_NONE) + return; + + /* Let's never come back here */ + mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_READ, NULL); + mowgli_linebuf_do_shutdown(linebuf); return; } @@ -147,29 +199,43 @@ static void mowgli_linebuf_read_data(mowgli_eventloop_t *eventloop, mowgli_event mowgli_linebuf_process(linebuf); } -static void mowgli_linebuf_write_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +static void +mowgli_linebuf_write_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) { - mowgli_linebuf_t *linebuf = (mowgli_linebuf_t *)userdata; + mowgli_linebuf_t *linebuf = (mowgli_linebuf_t *) userdata; mowgli_linebuf_buf_t *buffer = &(linebuf->writebuf); int ret; if ((ret = mowgli_vio_write(linebuf->vio, buffer->buffer, buffer->buflen)) <= 0) - { if (linebuf->vio->error.code != MOWGLI_VIO_ERR_NONE) - /* If we have a genuine error, we shouldn't come back to this func + /* If we have a genuine error, we shouldn't come back to this func * Otherwise we'll try again. */ - mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, NULL); - return; - } + if (ret != 0) + { + mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, NULL); + mowgli_log("mowgli_vio_write returned error [%ld]: %s", linebuf->vio->error.code, linebuf->vio->error.string); + return; + } buffer->buflen -= ret; /* Anything else to write? */ if (buffer->buflen == 0) - mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, NULL); + { + if (!mowgli_vio_hasflag(linebuf->vio, MOWGLI_VIO_FLAGS_NEEDWRITE)) + mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, NULL); + + if ((linebuf->flags & MOWGLI_LINEBUF_SHUTTING_DOWN) != 0) + mowgli_linebuf_do_shutdown(linebuf); + } + else + { + mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); + } } -void mowgli_linebuf_writef(mowgli_linebuf_t *linebuf, const char *format, ...) +void +mowgli_linebuf_writef(mowgli_linebuf_t *linebuf, const char *format, ...) { char buf[linebuf->writebuf.maxbuflen]; size_t len; @@ -182,34 +248,48 @@ void mowgli_linebuf_writef(mowgli_linebuf_t *linebuf, const char *format, ...) mowgli_linebuf_write(linebuf, buf, len); } -void mowgli_linebuf_write(mowgli_linebuf_t *linebuf, const char *data, int len) +void +mowgli_linebuf_write(mowgli_linebuf_t *linebuf, const char *data, int len) { char *ptr = linebuf->writebuf.buffer + linebuf->writebuf.buflen; - int delim_len = strlen(linebuf->delim); return_if_fail(len > 0); return_if_fail(data != NULL); - if (linebuf->writebuf.buflen + len + delim_len > linebuf->writebuf.maxbuflen) + if (linebuf->flags & MOWGLI_LINEBUF_SHUTTING_DOWN) + return; + + if (linebuf->writebuf.buflen + len + linebuf->endl_len > linebuf->writebuf.maxbuflen) { linebuf->flags |= MOWGLI_LINEBUF_ERR_WRITEBUF_FULL; mowgli_linebuf_error(linebuf->vio); return; } - memcpy((void *)ptr, data, len); - memcpy((void *)(ptr + len), linebuf->delim, delim_len); + memcpy((void *) ptr, data, len); + memcpy((void *) (ptr + len), linebuf->endl, linebuf->endl_len); - linebuf->writebuf.buflen += len + delim_len; + linebuf->writebuf.buflen += len + linebuf->endl_len; /* Schedule our write */ - mowgli_pollable_setselect(linebuf->eventloop, linebuf->vio->io, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); + mowgli_pollable_setselect(linebuf->eventloop, linebuf->vio->io.e, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); +} + +void +mowgli_linebuf_shut_down(mowgli_linebuf_t *linebuf) +{ + return_if_fail(linebuf != NULL); + + linebuf->flags |= MOWGLI_LINEBUF_SHUTTING_DOWN; + + if (linebuf->writebuf.buflen == 0) + mowgli_linebuf_do_shutdown(linebuf); } -static void mowgli_linebuf_process(mowgli_linebuf_t *linebuf) +static void +mowgli_linebuf_process(mowgli_linebuf_t *linebuf) { mowgli_linebuf_buf_t *buffer = &(linebuf->readbuf); - size_t delim_len = strlen(linebuf->delim); char *line_start; char *cptr; @@ -223,11 +303,12 @@ static void mowgli_linebuf_process(mowgli_linebuf_t *linebuf) while (len < buffer->buflen) { - if (memcmp((void *)cptr, linebuf->delim, delim_len) != 0) + if (!strchr(linebuf->delim, *cptr)) { if (*cptr == '\0') /* Warn about unexpected null chars in the string */ linebuf->flags |= MOWGLI_LINEBUF_LINE_HASNULLCHAR; + cptr++; len++; continue; @@ -239,20 +320,25 @@ static void mowgli_linebuf_process(mowgli_linebuf_t *linebuf) if (linebuf->return_normal_strings) *cptr = '\0'; - linebuf->readline_cb(linebuf, line_start, cptr - line_start, linebuf->userdata); + if ((linebuf->flags & MOWGLI_LINEBUF_SHUTTING_DOWN) == 0) + linebuf->readline_cb(linebuf, line_start, cptr - line_start, linebuf->userdata); /* Next line starts here; begin scanning and set the start of it */ - len += delim_len; - cptr += delim_len; + while (strchr(linebuf->delim, *cptr)) + { + len++; + cptr++; + } + line_start = cptr; /* Reset this for next line */ linebuf->flags &= ~MOWGLI_LINEBUF_LINE_HASNULLCHAR; } - if (linecount == 0 && (buffer->buflen == buffer->maxbuflen)) + if ((linecount == 0) && (buffer->buflen == buffer->maxbuflen)) { - /* No more chars will fit in the buffer and we don't have a line + /* No more chars will fit in the buffer and we don't have a line * We're really screwed, let's trigger an error. */ linebuf->flags |= MOWGLI_LINEBUF_ERR_READBUF_FULL; mowgli_linebuf_error(linebuf->vio); @@ -265,10 +351,20 @@ static void mowgli_linebuf_process(mowgli_linebuf_t *linebuf) memmove(buffer->buffer, line_start, cptr - line_start); } else + { buffer->buflen = 0; + } +} + +static void +mowgli_linebuf_do_shutdown(mowgli_linebuf_t *linebuf) +{ + if (linebuf && linebuf->shutdown_cb) + linebuf->shutdown_cb(linebuf, linebuf->userdata); } -static int mowgli_linebuf_error(mowgli_vio_t *vio) +static int +mowgli_linebuf_error(mowgli_vio_t *vio) { mowgli_linebuf_t *linebuf = vio->userdata; mowgli_vio_error_t *error = &(linebuf->vio->error); @@ -289,4 +385,3 @@ static int mowgli_linebuf_error(mowgli_vio_t *vio) /* Pass this up to higher callback */ return mowgli_vio_error(vio); } - diff --git a/src/libmowgli/linebuf/linebuf.h b/src/libmowgli/linebuf/linebuf.h index 17c45ea..e05629b 100644 --- a/src/libmowgli/linebuf/linebuf.h +++ b/src/libmowgli/linebuf/linebuf.h @@ -21,41 +21,52 @@ #ifndef __MOWGLI_LINEBUF_LINEBUF_H__ #define __MOWGLI_LINEBUF_LINEBUF_H__ -#include "eventloop/eventloop.h" -#include "vio/vio.h" - typedef struct _mowgli_linebuf_buf mowgli_linebuf_buf_t; -typedef void mowgli_linebuf_readline_cb_t(mowgli_linebuf_t *, char *, size_t, void *); +typedef void mowgli_linebuf_readline_cb_t (mowgli_linebuf_t *, char *, size_t, void *); +typedef void mowgli_linebuf_shutdown_cb_t (mowgli_linebuf_t *, void *); + +extern mowgli_linebuf_t *mowgli_linebuf_create(mowgli_linebuf_readline_cb_t *cb, void *userdata); -extern mowgli_linebuf_t * mowgli_linebuf_create(mowgli_linebuf_readline_cb_t *cb, void *userdata); +/* XXX these are unfortunately named and will change */ extern void mowgli_linebuf_attach_to_eventloop(mowgli_linebuf_t *linebuf, mowgli_eventloop_t *eventloop); +extern void mowgli_linebuf_detach_from_eventloop(mowgli_linebuf_t *linebuf); extern void mowgli_linebuf_destroy(mowgli_linebuf_t *linebuf); extern void mowgli_linebuf_setbuflen(mowgli_linebuf_buf_t *buffer, size_t buflen); +extern void mowgli_linebuf_delim(mowgli_linebuf_t *linebuf, const char *delim, const char *endl); extern void mowgli_linebuf_write(mowgli_linebuf_t *linebuf, const char *data, int len); extern void mowgli_linebuf_writef(mowgli_linebuf_t *linebuf, const char *format, ...); +extern void mowgli_linebuf_shut_down(mowgli_linebuf_t *linebuf); -struct _mowgli_linebuf_buf { +struct _mowgli_linebuf_buf +{ char *buffer; size_t buflen; size_t maxbuflen; }; /* Errors */ -#define MOWGLI_LINEBUF_ERR_NONE 0x0000 -#define MOWGLI_LINEBUF_ERR_READBUF_FULL 0x0001 -#define MOWGLI_LINEBUF_ERR_WRITEBUF_FULL 0x0002 +#define MOWGLI_LINEBUF_ERR_NONE 0x0000 +#define MOWGLI_LINEBUF_ERR_READBUF_FULL 0x0001 +#define MOWGLI_LINEBUF_ERR_WRITEBUF_FULL 0x0002 /* Informative */ -#define MOWGLI_LINEBUF_LINE_HASNULLCHAR 0x0004 +#define MOWGLI_LINEBUF_LINE_HASNULLCHAR 0x0004 -struct _mowgli_linebuf { +/* State */ +#define MOWGLI_LINEBUF_SHUTTING_DOWN 0x0100 + +struct _mowgli_linebuf +{ mowgli_linebuf_readline_cb_t *readline_cb; + mowgli_linebuf_shutdown_cb_t *shutdown_cb; mowgli_vio_t *vio; const char *delim; + const char *endl; + size_t endl_len; int flags; @@ -69,11 +80,11 @@ struct _mowgli_linebuf { void *userdata; }; -static inline mowgli_vio_t * mowgli_linebuf_get_vio(mowgli_linebuf_t *linebuf) +static inline mowgli_vio_t * +mowgli_linebuf_get_vio(mowgli_linebuf_t *linebuf) { return_val_if_fail(linebuf != NULL, NULL); return linebuf->vio; } #endif - diff --git a/src/libmowgli/module/Makefile b/src/libmowgli/module/Makefile index 702ed7c..19d885a 100644 --- a/src/libmowgli/module/Makefile +++ b/src/libmowgli/module/Makefile @@ -3,7 +3,7 @@ include ../../../extra.mk STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_MODULE} STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_MODULE} -SRCS = loader_${LIBMOWGLI_OS}.c +SRCS = interface.c loader_${LIBMOWGLI_OS}.c INCLUDES = module.h diff --git a/src/libmowgli/module/interface.c b/src/libmowgli/module/interface.c new file mode 100644 index 0000000..a552605 --- /dev/null +++ b/src/libmowgli/module/interface.c @@ -0,0 +1,73 @@ +/* + * libmowgli: A collection of useful routines for programming. + * module.h: Loadable modules. + * + * Copyright (c) 2007, 2014 William Pitcock + * + * 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 is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "mowgli.h" + +static mowgli_patricia_t *mowgli_interface_dict = NULL; +static mowgli_mutex_t mowgli_interface_lock; + +void +mowgli_interface_bootstrap(void) +{ + mowgli_interface_dict = mowgli_patricia_create(NULL); + mowgli_mutex_init(&mowgli_interface_lock); +} + +void +mowgli_interface_register(mowgli_interface_t *iface) +{ + mowgli_interface_base_t *base_iface = iface; + + mowgli_mutex_lock(&mowgli_interface_lock); + mowgli_patricia_add(mowgli_interface_dict, base_iface->id, iface); + mowgli_mutex_unlock(&mowgli_interface_lock); +} + +void +mowgli_interface_unregister(mowgli_interface_t *iface) +{ + mowgli_interface_base_t *base_iface = iface; + + mowgli_mutex_lock(&mowgli_interface_lock); + mowgli_patricia_delete(mowgli_interface_dict, base_iface->id); + mowgli_mutex_unlock(&mowgli_interface_lock); +} + +mowgli_interface_t * +mowgli_interface_get(const char *id, uint32_t abirev) +{ + mowgli_interface_base_t *base_iface; + + mowgli_mutex_lock(&mowgli_interface_lock); + + base_iface = mowgli_patricia_retrieve(mowgli_interface_dict, id); + if (base_iface->abirev != abirev) + { + mowgli_log("requested interface %s, abi mismatch %d != %d", id, abirev, base_iface->abirev); + base_iface = NULL; + } + + mowgli_mutex_unlock(&mowgli_interface_lock); + + return base_iface; +} diff --git a/src/libmowgli/module/loader_posix.c b/src/libmowgli/module/loader_posix.c index f15c38a..d4114e7 100644 --- a/src/libmowgli/module/loader_posix.c +++ b/src/libmowgli/module/loader_posix.c @@ -30,22 +30,25 @@ #endif #ifndef RTLD_LOCAL -#define RTLD_LOCAL 0 +# define RTLD_LOCAL 0 #endif -mowgli_module_t mowgli_module_open(const char *path) +mowgli_module_t +mowgli_module_open(const char *path) { void *handle = dlopen(path, RTLD_NOW | RTLD_LOCAL); - /* make sure we have something. make this an assertion so that - * there is feedback if something happens. (poor programming practice). - */ - return_val_if_fail(handle != NULL, NULL); + if (handle == NULL) + { + mowgli_log("Failed to open %s: %s", path, dlerror()); + return NULL; + } return handle; } -void * mowgli_module_symbol(mowgli_module_t module, const char *symbol) +void * +mowgli_module_symbol(mowgli_module_t module, const char *symbol) { void *handle; @@ -53,15 +56,17 @@ void * mowgli_module_symbol(mowgli_module_t module, const char *symbol) handle = dlsym(module, symbol); - /* make sure we have something. make this an assertion so that - * there is feedback if something happens. (poor programming practice). - */ - return_val_if_fail(handle != NULL, NULL); + if (handle == NULL) + { + mowgli_log("Failed to find symbol %s: %s", symbol, dlerror()); + return NULL; + } return handle; } -void mowgli_module_close(mowgli_module_t module) +void +mowgli_module_close(mowgli_module_t module) { return_if_fail(module != NULL); diff --git a/src/libmowgli/module/loader_win32.c b/src/libmowgli/module/loader_win32.c index f42a742..70cd1b6 100644 --- a/src/libmowgli/module/loader_win32.c +++ b/src/libmowgli/module/loader_win32.c @@ -23,30 +23,32 @@ #include "mowgli.h" -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #include -mowgli_module_t mowgli_module_open(const char *path) +mowgli_module_t +mowgli_module_open(const char *path) { HANDLE handle = LoadLibraryA(path); - /* make sure we have something. make this an assertion so that + /* make sure we have something. make this an assertion so that * there is feedback if something happens. (poor programming practice). */ return_val_if_fail(handle != NULL, NULL); - return (mowgli_module_t)handle; + return (mowgli_module_t) handle; } -void * mowgli_module_symbol(mowgli_module_t module, const char *symbol) +void * +mowgli_module_symbol(mowgli_module_t module, const char *symbol) { void *handle; return_val_if_fail(module != NULL, NULL); - handle = GetProcAddress((HANDLE)module, symbol); + handle = GetProcAddress((HANDLE) module, symbol); - /* make sure we have something. make this an assertion so that + /* make sure we have something. make this an assertion so that * there is feedback if something happens. (poor programming practice). */ return_val_if_fail(handle != NULL, NULL); @@ -54,9 +56,10 @@ void * mowgli_module_symbol(mowgli_module_t module, const char *symbol) return handle; } -void mowgli_module_close(mowgli_module_t module) +void +mowgli_module_close(mowgli_module_t module) { return_if_fail(module != NULL); - FreeLibrary((HANDLE)module); + FreeLibrary((HANDLE) module); } diff --git a/src/libmowgli/module/module.h b/src/libmowgli/module/module.h index 54fc344..214fd51 100644 --- a/src/libmowgli/module/module.h +++ b/src/libmowgli/module/module.h @@ -2,7 +2,7 @@ * libmowgli: A collection of useful routines for programming. * module.h: Loadable modules. * - * Copyright (c) 2007 William Pitcock + * Copyright (c) 2007, 2014 William Pitcock * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,10 +24,21 @@ #ifndef __MOWGLI_MODULE_H__ #define __MOWGLI_MODULE_H__ -typedef void * mowgli_module_t; +typedef void *mowgli_module_t; extern mowgli_module_t mowgli_module_open(const char *path); -extern void * mowgli_module_symbol(mowgli_module_t module, const char *symbol); +extern void *mowgli_module_symbol(mowgli_module_t module, const char *symbol); extern void mowgli_module_close(mowgli_module_t module); +typedef void mowgli_interface_t; + +typedef struct { + const char *id; + uint32_t abirev; +} mowgli_interface_base_t; + +extern void mowgli_interface_register(mowgli_interface_t *iface); +extern void mowgli_interface_unregister(mowgli_interface_t *iface); +extern mowgli_interface_t *mowgli_interface_get(const char *id, uint32_t abirev); + #endif diff --git a/src/libmowgli/mowgli.h b/src/libmowgli/mowgli.h index 6a64f0d..fca8f70 100644 --- a/src/libmowgli/mowgli.h +++ b/src/libmowgli/mowgli.h @@ -26,7 +26,8 @@ #ifdef __cplusplus # define MOWGLI_DECLS_START extern "C" { -# define MOWGLI_DECLS_END } +# define MOWGLI_DECLS_END \ + } #else # define MOWGLI_DECLS_START # define MOWGLI_DECLS_END @@ -40,12 +41,13 @@ MOWGLI_DECLS_START -#include "platform/constructor.h" #include "platform/machine.h" +#include "platform/cacheline.h" +#include "platform/attributes.h" +#include "platform/constructor.h" #include "core/logger.h" #include "core/assert.h" -#include "core/exception.h" #include "core/iterator.h" #include "container/list.h" @@ -88,10 +90,11 @@ MOWGLI_DECLS_START #include "ext/confparse.h" #include "ext/program_opts.h" +#include "ext/json.h" + #include "linebuf/linebuf.h" #include "dns/dns.h" MOWGLI_DECLS_END #endif - diff --git a/src/libmowgli/object/class.c b/src/libmowgli/object/class.c index 9bddf79..627b59d 100644 --- a/src/libmowgli/object/class.c +++ b/src/libmowgli/object/class.c @@ -23,9 +23,10 @@ #include "mowgli.h" -static mowgli_patricia_t *mowgli_object_class_dict = NULL; +static mowgli_patricia_t *mowgli_object_class_dict; -static void _object_key_canon(char *str) +static void +_object_key_canon(char *str) { while (*str) { @@ -34,17 +35,17 @@ static void _object_key_canon(char *str) } } -void mowgli_object_class_init(mowgli_object_class_t *klass, const char *name, mowgli_destructor_t des, mowgli_boolean_t dynamic) +void +mowgli_object_class_bootstrap() { - /* if the object_class dictionary has not yet been initialized, we will want to do that. */ - if (mowgli_object_class_dict == NULL) - mowgli_object_class_dict = mowgli_patricia_create(_object_key_canon); - - if (klass == NULL) - mowgli_throw_exception_fatal(mowgli.object_class.invalid_object_class_exception); + mowgli_object_class_dict = mowgli_patricia_create(_object_key_canon); +} - if (mowgli_object_class_find_by_name(name) != NULL) - mowgli_throw_exception_fatal(mowgli.object_class.duplicate_object_class_exception); +void +mowgli_object_class_init(mowgli_object_class_t *klass, const char *name, mowgli_destructor_t des, mowgli_boolean_t dynamic) +{ + return_if_fail(klass != NULL); + return_if_fail(mowgli_object_class_find_by_name(name) == NULL); /* initialize object_class::name */ klass->name = mowgli_strdup(name); @@ -64,12 +65,13 @@ void mowgli_object_class_init(mowgli_object_class_t *klass, const char *name, mo mowgli_patricia_add(mowgli_object_class_dict, klass->name, klass); } -int mowgli_object_class_check_cast(mowgli_object_class_t *klass1, mowgli_object_class_t *klass2) +int +mowgli_object_class_check_cast(mowgli_object_class_t *klass1, mowgli_object_class_t *klass2) { - mowgli_node_t *n; + return_val_if_fail(klass1 != NULL, 0); + return_val_if_fail(klass2 != NULL, 0); - if (klass1 == NULL || klass2 == NULL) - mowgli_throw_exception_val(mowgli.object_class.invalid_object_class_exception, 0); + mowgli_node_t *n; MOWGLI_LIST_FOREACH(n, klass1->derivitives.head) { @@ -82,15 +84,17 @@ int mowgli_object_class_check_cast(mowgli_object_class_t *klass1, mowgli_object_ return 0; } -void mowgli_object_class_set_derivitive(mowgli_object_class_t *klass, mowgli_object_class_t *parent) +void +mowgli_object_class_set_derivitive(mowgli_object_class_t *klass, mowgli_object_class_t *parent) { - if (klass == NULL || parent == NULL) - mowgli_throw_exception_fatal(mowgli.object_class.invalid_object_class_exception); + return_if_fail(klass != NULL); + return_if_fail(parent != NULL); mowgli_node_add(klass, mowgli_node_create(), &parent->derivitives); } -void *mowgli_object_class_reinterpret_impl(/* mowgli_object_t */ void *opdata, mowgli_object_class_t *klass) +void * +mowgli_object_class_reinterpret_impl( /* mowgli_object_t */ void *opdata, mowgli_object_class_t *klass) { mowgli_object_t *object = mowgli_object(opdata); @@ -101,24 +105,23 @@ void *mowgli_object_class_reinterpret_impl(/* mowgli_object_t */ void *opdata, m if (mowgli_object_class_check_cast(object->klass, klass)) return object; - mowgli_log("Invalid reinterpreted cast from %s<%p> to %s", object->klass->name, klass->name); + mowgli_log("Invalid reinterpreted cast from %s<%p> to %s", object->klass->name, (void *) object, klass->name); return NULL; } -mowgli_object_class_t *mowgli_object_class_find_by_name(const char *name) +mowgli_object_class_t * +mowgli_object_class_find_by_name(const char *name) { return mowgli_patricia_retrieve(mowgli_object_class_dict, name); } -void mowgli_object_class_destroy(mowgli_object_class_t *klass) +void +mowgli_object_class_destroy(mowgli_object_class_t *klass) { - mowgli_node_t *n, *tn; + return_if_fail(klass != NULL); + return_if_fail(klass->dynamic == TRUE); - if (klass == NULL) - mowgli_throw_exception_fatal(mowgli.object_class.invalid_object_class_exception); - - if (klass->dynamic != TRUE) - mowgli_throw_exception_fatal(mowgli.object_class.nondynamic_object_class_exception); + mowgli_node_t *n, *tn; MOWGLI_LIST_FOREACH_SAFE(n, tn, klass->derivitives.head) { diff --git a/src/libmowgli/object/class.h b/src/libmowgli/object/class.h index 9612aa4..121368b 100644 --- a/src/libmowgli/object/class.h +++ b/src/libmowgli/object/class.h @@ -26,7 +26,8 @@ typedef void (*mowgli_destructor_t)(void *); -typedef struct { +typedef struct +{ char *name; mowgli_list_t derivitives; mowgli_destructor_t destructor; @@ -37,24 +38,25 @@ typedef struct { extern void mowgli_object_class_init(mowgli_object_class_t *klass, const char *name, mowgli_destructor_t des, mowgli_boolean_t dynamic); extern int mowgli_object_class_check_cast(mowgli_object_class_t *klass1, mowgli_object_class_t *klass2); extern void mowgli_object_class_set_derivitive(mowgli_object_class_t *klass, mowgli_object_class_t *parent); -extern void *mowgli_object_class_reinterpret_impl(/* mowgli_object_t */ void *object, mowgli_object_class_t *klass); +extern void *mowgli_object_class_reinterpret_impl( /* mowgli_object_t */ void *object, mowgli_object_class_t *klass); extern mowgli_object_class_t *mowgli_object_class_find_by_name(const char *name); extern void mowgli_object_class_destroy(mowgli_object_class_t *klass); -#define MOWGLI_REINTERPRET_CAST(object, klass) (klass *) mowgli_object_class_reinterpret_impl(object, mowgli_object_class_find_by_name( # klass )); +#define MOWGLI_REINTERPRET_CAST(object, klass) (klass *) mowgli_object_class_reinterpret_impl(object, mowgli_object_class_find_by_name(#klass)) -#define mowgli_forced_cast(from_type, to_type, from, to)\ -do { \ - union cast_union \ - { \ - to_type out; \ - from_type in; \ - } u; \ - typedef int cant_use_union_cast[ \ - sizeof (from_type) == sizeof (u) \ - && sizeof (from_type) == sizeof (to_type) ? 1 : -1];\ - u.in = from; \ - to = u.out; \ -} while (0) +#define mowgli_forced_cast(from_type, to_type, from, to) \ + do \ + { \ + union cast_union \ + { \ + to_type out; \ + from_type in; \ + } u; \ + typedef int cant_use_union_cast[ \ + sizeof(from_type) == sizeof(u) \ + && sizeof(from_type) == sizeof(to_type) ? 1 : -1]; \ + u.in = from; \ + to = u.out; \ + } while (0) #endif diff --git a/src/libmowgli/object/message.c b/src/libmowgli/object/message.c index e4328c8..d99f53b 100644 --- a/src/libmowgli/object/message.c +++ b/src/libmowgli/object/message.c @@ -23,71 +23,61 @@ #include "mowgli.h" -void mowgli_object_class_message_handler_attach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig) +void +mowgli_object_class_message_handler_attach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig) { - if (klass == NULL) - mowgli_throw_exception(mowgli.object_messaging.invalid_object_class_exception); - - if (sig == NULL) - mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception); + return_if_fail(klass != NULL); + return_if_fail(sig != NULL); mowgli_node_add(sig, mowgli_node_create(), &klass->message_handlers); } -void mowgli_object_class_message_handler_detach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig) +void +mowgli_object_class_message_handler_detach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig) { - mowgli_node_t *n; + return_if_fail(klass != NULL); + return_if_fail(sig != NULL); - if (klass == NULL) - mowgli_throw_exception(mowgli.object_messaging.invalid_object_class_exception); - - if (sig == NULL) - mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception); + mowgli_node_t *n; n = mowgli_node_find(sig, &klass->message_handlers); mowgli_node_delete(n, &klass->message_handlers); mowgli_node_free(n); } -void mowgli_object_message_handler_attach(mowgli_object_t *self, mowgli_object_message_handler_t *sig) +void +mowgli_object_message_handler_attach(mowgli_object_t *self, mowgli_object_message_handler_t *sig) { - if (self == NULL) - mowgli_throw_exception(mowgli.object_messaging.invalid_object_exception); - - if (sig == NULL) - mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception); + return_if_fail(self != NULL); + return_if_fail(sig != NULL); mowgli_node_add(sig, mowgli_node_create(), &self->message_handlers); } -void mowgli_object_message_handler_detach(mowgli_object_t *self, mowgli_object_message_handler_t *sig) +void +mowgli_object_message_handler_detach(mowgli_object_t *self, mowgli_object_message_handler_t *sig) { - mowgli_node_t *n; + return_if_fail(self != NULL); + return_if_fail(sig != NULL); - if (self == NULL) - mowgli_throw_exception(mowgli.object_messaging.invalid_object_exception); - - if (sig == NULL) - mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception); + mowgli_node_t *n; n = mowgli_node_find(sig, &self->message_handlers); mowgli_node_delete(n, &self->message_handlers); mowgli_node_free(n); } -void mowgli_object_message_broadcast(mowgli_object_t *self, const char *name, ...) +void +mowgli_object_message_broadcast(mowgli_object_t *self, const char *name, ...) { + return_if_fail(self != NULL); + return_if_fail(name != NULL); + mowgli_argstack_t *stack; mowgli_object_message_handler_t *sig = NULL; mowgli_node_t *n; va_list va; - if (self == NULL) - mowgli_throw_exception(mowgli.object_messaging.invalid_object_exception); - - if (name == NULL) - mowgli_throw_exception(mowgli.null_pointer_exception); - /* try to find a signal to compile the argument stack from, we start with self::klass first. */ MOWGLI_LIST_FOREACH(n, self->klass->message_handlers.head) { @@ -101,7 +91,6 @@ void mowgli_object_message_broadcast(mowgli_object_t *self, const char *name, .. } if (sig == NULL) - { MOWGLI_LIST_FOREACH(n, self->klass->message_handlers.head) { mowgli_object_message_handler_t *sig2 = (mowgli_object_message_handler_t *) n->data; @@ -112,11 +101,10 @@ void mowgli_object_message_broadcast(mowgli_object_t *self, const char *name, .. break; } } - } - /* return if no signals found, else compile the argstack */ - if (sig == NULL) - return; + /* return if no signals found, else compile the argstack */ + if (sig == NULL) + return; va_start(va, name); stack = mowgli_argstack_create_from_va_list(sig->descstr, va); @@ -126,7 +114,7 @@ void mowgli_object_message_broadcast(mowgli_object_t *self, const char *name, .. { sig = (mowgli_object_message_handler_t *) n->data; - if (!strcasecmp(sig->name, name) && sig->handler != NULL) + if (!strcasecmp(sig->name, name) && (sig->handler != NULL)) sig->handler(self, sig, stack); } @@ -134,7 +122,7 @@ void mowgli_object_message_broadcast(mowgli_object_t *self, const char *name, .. { sig = (mowgli_object_message_handler_t *) n->data; - if (!strcasecmp(sig->name, name) && sig->handler != NULL) + if (!strcasecmp(sig->name, name) && (sig->handler != NULL)) sig->handler(self, sig, stack); } diff --git a/src/libmowgli/object/message.h b/src/libmowgli/object/message.h index 4a49d00..aee82af 100644 --- a/src/libmowgli/object/message.h +++ b/src/libmowgli/object/message.h @@ -27,7 +27,8 @@ typedef struct mowgli_object_message_handler_ mowgli_object_message_handler_t; typedef void (*mowgli_object_messaging_func_t)(mowgli_object_t *self, mowgli_object_message_handler_t *sig, mowgli_argstack_t *argstack); -struct mowgli_object_message_handler_ { +struct mowgli_object_message_handler_ +{ char *name; char *descstr; mowgli_object_messaging_func_t handler; diff --git a/src/libmowgli/object/metadata.c b/src/libmowgli/object/metadata.c index 742e0dc..307947e 100644 --- a/src/libmowgli/object/metadata.c +++ b/src/libmowgli/object/metadata.c @@ -23,17 +23,15 @@ #include "mowgli.h" -void mowgli_object_metadata_associate(mowgli_object_t *self, const char *key, void *value) +void +mowgli_object_metadata_associate(mowgli_object_t *self, const char *key, void *value) { + return_if_fail(self != NULL); + return_if_fail(key != NULL); + mowgli_object_metadata_entry_t *e = NULL; mowgli_node_t *n; - if (self == NULL) - mowgli_throw_exception(mowgli.object_metadata.invalid_object_exception); - - if (key == NULL) - mowgli_throw_exception(mowgli.null_pointer_exception); - MOWGLI_LIST_FOREACH(n, self->metadata.head) { e = (mowgli_object_metadata_entry_t *) n->data; @@ -55,17 +53,15 @@ void mowgli_object_metadata_associate(mowgli_object_t *self, const char *key, vo mowgli_node_add(e, mowgli_node_create(), &self->metadata); } -void mowgli_object_metadata_dissociate(mowgli_object_t *self, const char *key) +void +mowgli_object_metadata_dissociate(mowgli_object_t *self, const char *key) { + return_if_fail(self != NULL); + return_if_fail(key != NULL); + mowgli_object_metadata_entry_t *e; mowgli_node_t *n, *tn; - if (self == NULL) - mowgli_throw_exception(mowgli.object_metadata.invalid_object_exception); - - if (key == NULL) - mowgli_throw_exception(mowgli.null_pointer_exception); - MOWGLI_LIST_FOREACH_SAFE(n, tn, self->metadata.head) { e = (mowgli_object_metadata_entry_t *) n->data; @@ -81,17 +77,15 @@ void mowgli_object_metadata_dissociate(mowgli_object_t *self, const char *key) } } -void *mowgli_object_metadata_retrieve(mowgli_object_t *self, const char *key) +void * +mowgli_object_metadata_retrieve(mowgli_object_t *self, const char *key) { + return_null_if_fail(self != NULL); + return_null_if_fail(key != NULL); + mowgli_object_metadata_entry_t *e; mowgli_node_t *n; - if (self == NULL) - mowgli_throw_exception_val(mowgli.object_metadata.invalid_object_exception, NULL); - - if (key == NULL) - mowgli_throw_exception_val(mowgli.null_pointer_exception, NULL); - MOWGLI_LIST_FOREACH(n, self->metadata.head) { e = (mowgli_object_metadata_entry_t *) n->data; diff --git a/src/libmowgli/object/metadata.h b/src/libmowgli/object/metadata.h index 0cdda69..fe2170c 100644 --- a/src/libmowgli/object/metadata.h +++ b/src/libmowgli/object/metadata.h @@ -24,7 +24,8 @@ #ifndef __MOWGLI_OBJECT_METADATA_H__ #define __MOWGLI_OBJECT_METADATA_H__ -typedef struct { +typedef struct +{ char *name; void *data; } mowgli_object_metadata_entry_t; diff --git a/src/libmowgli/object/object.c b/src/libmowgli/object/object.c index 7b24ea7..04a218f 100644 --- a/src/libmowgli/object/object.c +++ b/src/libmowgli/object/object.c @@ -40,7 +40,8 @@ * Side Effects: * - none */ -void mowgli_object_init(mowgli_object_t *obj, const char *name, mowgli_object_class_t *klass, mowgli_destructor_t des) +void +mowgli_object_init(mowgli_object_t *obj, const char *name, mowgli_object_class_t *klass, mowgli_destructor_t des) { return_if_fail(obj != NULL); @@ -48,7 +49,9 @@ void mowgli_object_init(mowgli_object_t *obj, const char *name, mowgli_object_cl obj->name = mowgli_strdup(name); if (klass != NULL) + { obj->klass = klass; + } else { mowgli_object_class_t *tmp = mowgli_alloc(sizeof(mowgli_object_class_t)); @@ -85,8 +88,7 @@ void mowgli_object_init(mowgli_object_t *obj, const char *name, mowgli_object_cl * - none */ void -mowgli_object_init_from_class(mowgli_object_t *obj, const char *name, - mowgli_object_class_t *klass) +mowgli_object_init_from_class(mowgli_object_t *obj, const char *name, mowgli_object_class_t *klass) { return_if_fail(obj != NULL); return_if_fail(klass != NULL); @@ -108,7 +110,8 @@ mowgli_object_init_from_class(mowgli_object_t *obj, const char *name, * Side Effects: * - none */ -void * mowgli_object_ref(void *object) +void * +mowgli_object_ref(void *object) { return_val_if_fail(object != NULL, NULL); @@ -131,7 +134,8 @@ void * mowgli_object_ref(void *object) * Side Effects: * - if the refcount is 0, the object is destroyed. */ -void mowgli_object_unref(void *object) +void +mowgli_object_unref(void *object) { mowgli_object_t *obj = mowgli_object(object); @@ -159,6 +163,8 @@ void mowgli_object_unref(void *object) free(obj); } else - mowgli_throw_exception(mowgli.object.invalid_object_class_exception); + { + mowgli_log_warning("invalid object class"); + } } } diff --git a/src/libmowgli/object/object.h b/src/libmowgli/object/object.h index 0f13ce1..255df10 100644 --- a/src/libmowgli/object/object.h +++ b/src/libmowgli/object/object.h @@ -24,7 +24,8 @@ #ifndef __MOWGLI_OBJECT_H__ #define __MOWGLI_OBJECT_H__ -typedef struct { +typedef struct +{ char *name; int refcount; mowgli_object_class_t *klass; diff --git a/src/libmowgli/platform/Makefile b/src/libmowgli/platform/Makefile index 6b6d7b9..7d883d4 100644 --- a/src/libmowgli/platform/Makefile +++ b/src/libmowgli/platform/Makefile @@ -1,9 +1,17 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_PLATFORM} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_PLATFORM} + SUBDIRS = win32 -INCLUDES = constructor.h machine.h +SRCS = cacheline.c + +INCLUDES = attributes.h cacheline.h constructor.h machine.h include ../../../buildsys.mk includesubdir = $(PACKAGE_NAME)/platform -include ../../../extra.mk +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/platform/attributes.h b/src/libmowgli/platform/attributes.h new file mode 100644 index 0000000..35e5d68 --- /dev/null +++ b/src/libmowgli/platform/attributes.h @@ -0,0 +1,69 @@ +/* + * libmowgli: A collection of useful routines for programming. + * attributes.h: Compiler attributes to help write better code + * + * Copyright (c) 2013 Patrick McFarland + * + * 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 is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef __MOWGLI_PLATFORM_ATTRIBUTES_H__ +#define __MOWGLI_PLATFORM_ATTRIBUTES_H__ + +/* Deprecated */ +#if defined MOWGLI_COMPILER_GCC_COMPAT +# define MOWGLI_DEPRECATED(proto, msg) proto __attribute__((deprecated(msg))) +#elif defined MOWGLI_COMPILER_MSVC +# define MOWGLI_DEPRECATED(proto, msg) __declspec(deprecated(msg)) proto +#else +# define MOWGLI_DEPRECATED(proto, msg) proto +#endif + +/* printf, n is number of args to skip to get to fmt */ +#if defined MOWGLI_COMPILER_GCC_COMPAT +# define MOWGLI_PRINTF(proto, n) proto __attribute__((format(printf, n, n + 1))) +#else +# define MOWGLI_PRINTF(proto) proto +#endif + +/* Hot and cold paths */ +#if MOWGLI_COMPILER_GCC_VERSION > 403000 +# define MOWGLI_HOT(proto) proto __attribute__((hot)) +# define MOWGLI_COLD(proto) proto __attribute__((cold)) +#else +# define MOWGLI_HOT(proto) proto +# define MOWGLI_COLD(proto) proto +#endif + +#if MOWGLI_COMPILER_GCC_VERSION > 408000 +# define MOWGLI_HOT_LABEL(label) label __attribute__((hot)) +# define MOWGLI_COLD_LABEL(label) label __attribute__((cold)) +#else +# define MOWGLI_HOT_LABEL(label) label +# define MOWGLI_COLD_LABEL(label) label +#endif + +/* malloc, n is the arg used for allocation size */ +#ifdef MOWGLI_COMPILER_GCC_COMPAT +# define MOWGLI_MALLOC(proto, n) \ + proto __attribute__((malloc, alloc_size(n), warn_unused_result)) +#else +# define MOWGLI_MALLOC(proto, n) \ + proto +#endif + +#endif diff --git a/src/libmowgli/platform/cacheline.c b/src/libmowgli/platform/cacheline.c new file mode 100644 index 0000000..90c803f --- /dev/null +++ b/src/libmowgli/platform/cacheline.c @@ -0,0 +1,72 @@ +/* + * libmowgli: A collection of useful routines for programming. + * cacheline.c: Platform specific routines to get L1 cache line size + * + * Copyright (c) 2013 Patrick McFarland + * + * 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 is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "mowgli.h" + +#ifdef MOWGLI_OS_OSX +# include +#endif + +size_t cacheline_size; + +void +mowgli_cacheline_bootstrap(void) +{ +#ifdef MOWGLI_OS_LINUX + cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); +#elif defined(MOWGLI_OS_OSX) + size_t size = sizeof(size_t); + sysctlbyname("hw.cachelinesize", &cacheline_size, &size, 0, 0); +#elif defined(MOWGLI_OS_WIN) + DWORD buf_size = 0; + DWORD i = 0; + SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buf = 0; + + GetLogicalProcessorInformation(0, &buf_size); + buf = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *) mowgli_alloc(buf_size); + GetLogicalProcessorInformation(&buf[0], &buf_size); + + for (i = 0; i != buf_size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ++i) + if ((buf[i].Relationship == RelationCache) && (buf[i].Cache.Level == 1)) + { + cacheline_size = buf[i].Cache.LineSize; + break; + } + + mowgli_free(buf); +#else + + // This is often true +# ifdef MOWGLI_CPU_BITS_32 + cacheline_size = 32; +# else + cacheline_size = 64; +# endif +#endif +} + +size_t +mowgli_cacheline_size(void) +{ + return cacheline_size; +} diff --git a/src/libmowgli/platform/cacheline.h b/src/libmowgli/platform/cacheline.h new file mode 100644 index 0000000..a1e6c3f --- /dev/null +++ b/src/libmowgli/platform/cacheline.h @@ -0,0 +1,29 @@ +/* + * libmowgli: A collection of useful routines for programming. + * cacheline.h: Platform specific routines to get L1 cache line size + * + * Copyright (c) 2013 Patrick McFarland + * + * 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 is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef __MOWGLI_PLATFORM_CACHELINE_H__ +#define __MOWGLI_PLATFORM_CACHELINE_H__ + +extern size_t mowgli_cacheline_size(void); + +#endif diff --git a/src/libmowgli/platform/constructor.h b/src/libmowgli/platform/constructor.h index 8446f44..7675703 100644 --- a/src/libmowgli/platform/constructor.h +++ b/src/libmowgli/platform/constructor.h @@ -24,7 +24,7 @@ #ifndef __MOWGLI_PLATFORM_CONSTRUCTOR_H__ #define __MOWGLI_PLATFORM_CONSTRUCTOR_H__ -#ifdef _MSC_VER +#if defined MOWGLI_COMPILER_MSVC /* * Automatic constructors are not yet officially supported in MSVC, however, @@ -34,21 +34,22 @@ * See http://blogs.msdn.com/b/vcblog/archive/2006/10/20/crt-initialization.aspx * for more information. */ -#define MOWGLI_BOOTSTRAP_FUNC(func) \ - static void __cdecl func(void); \ - __declspec(allocate(".CRT$XCU")) void (__cdecl *func##_)(void) = func; \ +# define MOWGLI_BOOTSTRAP_FUNC(func) \ + static void __cdecl func(void); \ + __declspec(allocate(".CRT$XCU")) void(__cdecl * func##_) (void) = func; \ static void __cdecl func(void) - -#elif defined(__GNUC__) || defined(__SUNPRO_C) - -#define MOWGLI_BOOTSTRAP_FUNC(func) \ - static void func(void) __attribute__((constructor)); \ +#elif defined MOWGLI_COMPILER_GCC_COMPAT +# if MOWGLI_COMPILER_GCC_VERSION >= 403000 +# define MOWGLI_BOOTSTRAP_FUNC(func) \ + static void func(void) __attribute__((cold, constructor, flatten)); \ static void func(void) - +# else +# define MOWGLI_BOOTSTRAP_FUNC(func) \ + static void func(void) __attribute__((constructor, flatten)); \ + static void func(void) +# endif #else - -#error MOWGLI_BOOTSTRAP_FUNC not implemented for your platform :( - +# error MOWGLI_BOOTSTRAP_FUNC not implemented for your platform :( #endif #endif diff --git a/src/libmowgli/platform/machine.h b/src/libmowgli/platform/machine.h index b2a2e50..6b23514 100644 --- a/src/libmowgli/platform/machine.h +++ b/src/libmowgli/platform/machine.h @@ -2,7 +2,7 @@ * libmowgli: A collection of useful routines for programming. * machine.h: Defines to discover what machine we're on easily * - * Copyright (c) 2012 Patrick McFarland + * Copyright (c) 2012, 2013 Patrick McFarland * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,8 +21,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "mowgli.h" - /* Machine environment specific macros, mostly sourced from this URL: * http://sourceforge.net/apps/mediawiki/predef/ * @@ -37,298 +35,306 @@ #define __MOWGLI_MACHINE_H__ #if defined __clang__ -#define MOWGLI_COMPILER_CLANG -#define MOWGLI_COMPILER clang +# define MOWGLI_COMPILER_CLANG +# define MOWGLI_COMPILER clang #elif defined __INTEL_COMPILER || defined __ICC || defined __ICL -#define MOWGLI_COMPILER_ICC -#define MOWGLI_COMPILER icc +# define MOWGLI_COMPILER_ICC +# define MOWGLI_COMPILER icc #elif defined __CC_ARM -#define MOWGLI_COMPILER_ARM -#define MOWGLI_COMPILER arm +# define MOWGLI_COMPILER_ARM +# define MOWGLI_COMPILER arm #elif defined __xlc__ || defined __xlC__ -#define MOWGLI_COMPILER_IBM -#define MOWGLI_COMPILER ibm +# define MOWGLI_COMPILER_IBM +# define MOWGLI_COMPILER ibm #elif defined __SUNPRO_C || defined __SUNPRO_CC -#define MOWGLI_COMPILER_SUN -#define MOWGLI_COMPILER sun +# define MOWGLI_COMPILER_SUN +# define MOWGLI_COMPILER sun #elif defined __GNUC__ -#define MOWGLI_COMPILER_GCC -#define MOWGLI_COMPILER gcc +# define MOWGLI_COMPILER_GCC +# define MOWGLI_COMPILER gcc #elif defined _MSC_VER -#define MOWGLI_COMPILER_MSVC -#define MOWGLI_COMPILER msvc +# define MOWGLI_COMPILER_MSVC +# define MOWGLI_COMPILER msvc #else -#define MOWGLI_COMPILER_UNKNOWN -#define MOWGLI_COMPILER unknown +# define MOWGLI_COMPILER_UNKNOWN +# define MOWGLI_COMPILER unknown #endif #if defined __GNUC__ -#define MOWGLI_COMPILER_GCC_COMPAT +# define MOWGLI_COMPILER_GCC_COMPAT +# define MOWGLI_COMPILER_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#else +# define MOWGLI_COMPILER_GCC_VERSION (0) #endif #if defined __amd64__ || defined __amd64 || defined __x86_64__ || defined __x86_64 || defined _M_X64 || defined _M_AMD64 -#define MOWGLI_CPU_X86_64 -#define MOWGLI_CPU x86_64 -#define MOWGLI_CPU_BITS_64 -#define MOWGLI_CPU_BITS 64 -#define MOWGLI_CPU_ENDIAN_LITTLE -#define MOWGLI_CPU_ENDIAN little +# define MOWGLI_CPU_X86_64 +# define MOWGLI_CPU x86_64 +# define MOWGLI_CPU_BITS_64 +# define MOWGLI_CPU_BITS 64 +# define MOWGLI_CPU_ENDIAN_LITTLE +# define MOWGLI_CPU_ENDIAN little #elif defined __i386__ || defined __i386 || defined __IA32__ || defined _M_IX86 || defined __X86__ || defined _X86__ || defined __I86__ -#define MOWGLI_CPU_X86 -#define MOWGLI_CPU x86 -#define MOWGLI_CPU_BITS_32 -#define MOWGLI_CPU_BITS 32 -#define MOWGLI_CPU_ENDIAN_LITTLE -#define MOWGLI_CPU_ENDIAN little +# define MOWGLI_CPU_X86 +# define MOWGLI_CPU x86 +# define MOWGLI_CPU_BITS_32 +# define MOWGLI_CPU_BITS 32 +# define MOWGLI_CPU_ENDIAN_LITTLE +# define MOWGLI_CPU_ENDIAN little #elif defined __arm__ || defined __TARGET_ARCH_ARM || defined _ARM -#if defined __thumb__ || defined __TARGET_ARCH_THUMB -#define MOWGLI_CPU_ARM_THUMB -#endif -#define MOWGLI_CPU_ARM -#define MOWGLI_CPU arm -#define MOWGLI_CPU_BITS_32 -#define MOWGLI_CPU_BITS 32 +# if defined __thumb__ || defined __TARGET_ARCH_THUMB +# define MOWGLI_CPU_ARM_THUMB +# endif +# define MOWGLI_CPU_ARM +# define MOWGLI_CPU arm +# define MOWGLI_CPU_BITS_32 +# define MOWGLI_CPU_BITS 32 + // ARM can be either endian #elif defined __hppa__ || defined __HPPA__ || defined __hppa -#if defined _PA_RISC2_0 || defined __HPPA20__ || defined __RISC2_0__ -#define MOWGLI_CPU_HPPA20 -#define MOWGLI_CPU hppa20 -#define MOWGLI_CPU_BITS_64 -#define MOWGLI_CPU_BITS 64 -#else -#define MOWGLI_CPU_HPPA10 -#define MOWGLI_CPU hppa10 -#define MOWGLI_CPU_BITS_32 -#define MOWGLI_CPU_BITS 32 -#endif -#define MOWGLI_CPU_ENDIAN_BIG -#define MOWGLI_CPU_ENDIAN big +# if defined _PA_RISC2_0 || defined __HPPA20__ || defined __RISC2_0__ +# define MOWGLI_CPU_HPPA20 +# define MOWGLI_CPU hppa20 +# define MOWGLI_CPU_BITS_64 +# define MOWGLI_CPU_BITS 64 +# else +# define MOWGLI_CPU_HPPA10 +# define MOWGLI_CPU hppa10 +# define MOWGLI_CPU_BITS_32 +# define MOWGLI_CPU_BITS 32 +# endif +# define MOWGLI_CPU_ENDIAN_BIG +# define MOWGLI_CPU_ENDIAN big #elif defined __ia64__ || defined __IA64__ || defined _M_IA64 || defined __ia64 || defined __itanium__ -#define MOWGLI_CPU_ITANIUM -#define MOWGLI_CPU itanium -#define MOWGLI_CPU_BITS_64 -#define MOWGLI_CPU_BITS 64 +# define MOWGLI_CPU_ITANIUM +# define MOWGLI_CPU itanium +# define MOWGLI_CPU_BITS_64 +# define MOWGLI_CPU_BITS 64 + // Itanium can be either endian #elif defined __mips__ || defined mips || defined __mips || defined __MIPS__ -#if defined __mips64 || defined __mips64__ -#define MOWGLI_CPU_MIPS64 -#define MOWGLI_CPU mips64 -#define MOWGLI_CPU_BITS_64 -#define MOWGLI_CPU_BITS 64 -#else -#define MOWGLI_CPU_MIPS -#define MOWGLI_CPU mips -#define MOWGLI_CPU_BITS_32 -#define MOWGLI_CPU_BITS 32 -#endif +# if defined __mips64 || defined __mips64__ +# define MOWGLI_CPU_MIPS64 +# define MOWGLI_CPU mips64 +# define MOWGLI_CPU_BITS_64 +# define MOWGLI_CPU_BITS 64 +# else +# define MOWGLI_CPU_MIPS +# define MOWGLI_CPU mips +# define MOWGLI_CPU_BITS_32 +# define MOWGLI_CPU_BITS 32 +# endif + // MIPS can be either endian #elif defined __powerpc || defined __powerpc__ || defined __POWERPC__ || defined __ppc__ || defined _M_PPC -#if defined __ppc64__ || defined __PPC64__ -#define MOWGLI_CPU_POWERPC64 -#define MOWGLI_CPU powerpc64 -#define MOWGLI_CPU_BITS_64 -#define MOWGLI_CPU_BITS 64 -#else -#define MOWGLI_CPU powerpc -#define MOWGLI_CPU_BITS_32 -#define MOWGLI_CPU_BITS 32 -#endif -#define MOWGLI_CPU_POWERPC +# if defined __ppc64__ || defined __PPC64__ +# define MOWGLI_CPU_POWERPC64 +# define MOWGLI_CPU powerpc64 +# define MOWGLI_CPU_BITS_64 +# define MOWGLI_CPU_BITS 64 +# else +# define MOWGLI_CPU powerpc +# define MOWGLI_CPU_BITS_32 +# define MOWGLI_CPU_BITS 32 +# endif +# define MOWGLI_CPU_POWERPC + // PowerPC can be either endian #elif defined __sparc__ || defined __sparc -#if defined __sparcv9 || defined __sparc64 || defined __sparc64__ -#define MOWGLI_CPU_SPARC64 -#define MOWGLI_CPU sparc64 -#define MOWGLI_CPU_BITS_64 -#define MOWGLI_CPU_BITS 64 -#else -#define MOWGLI_CPU_SPARC -#define MOWGLI_CPU sparc -#define MOWGLI_CPU_BITS_32 -#define MOWGLI_CPU_BITS 32 -#endif -#define MOWGLI_CPU_ENDIAN_BIG -#define MOWGLI_CPU_ENDIAN big +# if defined __sparcv9 || defined __sparc64 || defined __sparc64__ +# define MOWGLI_CPU_SPARC64 +# define MOWGLI_CPU sparc64 +# define MOWGLI_CPU_BITS_64 +# define MOWGLI_CPU_BITS 64 +# else +# define MOWGLI_CPU_SPARC +# define MOWGLI_CPU sparc +# define MOWGLI_CPU_BITS_32 +# define MOWGLI_CPU_BITS 32 +# endif +# define MOWGLI_CPU_ENDIAN_BIG +# define MOWGLI_CPU_ENDIAN big #elif defined __alpha || defined __alpha__ || defined _M_ALPHA -#define MOWGLI_CPU_ALPHA -#define MOWGLI_CPU alpha -#define MOWGLI_CPU_BITS_64 -#define MOWGLI_CPU_BITS 64 -#define MOWGLI_CPU_ENDIAN_LITTLE -#define MOWGLI_CPU_ENDIAN little +# define MOWGLI_CPU_ALPHA +# define MOWGLI_CPU alpha +# define MOWGLI_CPU_BITS_64 +# define MOWGLI_CPU_BITS 64 +# define MOWGLI_CPU_ENDIAN_LITTLE +# define MOWGLI_CPU_ENDIAN little #elif defined __avr32__ || defined __AVR32__ -#define MOWGLI_CPU_AVR32 -#define MOWGLI_CPU avr -#define MOWGLI_CPU_BITS_32 -#define MOWGLI_CPU_BITS 32 -#define MOWGLI_CPU_ENDIAN_LITTLE -#define MOWGLI_CPU_ENDIAN little +# define MOWGLI_CPU_AVR32 +# define MOWGLI_CPU avr +# define MOWGLI_CPU_BITS_32 +# define MOWGLI_CPU_BITS 32 +# define MOWGLI_CPU_ENDIAN_LITTLE +# define MOWGLI_CPU_ENDIAN little #elif defined __sh__ || defined __SH__ -#define MOWGLI_CPU_SuperH -#define MOWGLI_CPU superh -#define MOWGLI_CPU_BITS_32 -#define MOWGLI_CPU_BITS 32 +# define MOWGLI_CPU_SuperH +# define MOWGLI_CPU superh +# define MOWGLI_CPU_BITS_32 +# define MOWGLI_CPU_BITS 32 + // SyoerH can be either endian #endif #ifndef MOWGLI_CPU -#define MOWGLI_CPU_UNKNOWN -#define MOWGLI_CPU unknown +# define MOWGLI_CPU_UNKNOWN +# define MOWGLI_CPU unknown #endif #ifndef MOWGLI_CPU_BITS -#if defined _LP64 || defined __LP64 -#define MOWGLI_CPU_BITS 64 -#define MOWGLI_CPU_BITS_64 -#elif -#define MOWGLI_CPU_BITS 32 -#define MOWGLI_CPU_BITS_32 -#endif +# if defined _LP64 || defined __LP64 +# define MOWGLI_CPU_BITS 64 +# define MOWGLI_CPU_BITS_64 +# elif +# define MOWGLI_CPU_BITS 32 +# define MOWGLI_CPU_BITS_32 +# endif #endif #if defined __linux || defined __linux__ -#define MOWGLI_OS_LINUX -#define MOWGLI_OS linux -#define MOWGLI_OS_THREADS_POSIX -#define MOWGLI_OS_THREADS posix -#define MOWGLI_OS_MUTEX_POSIX -#define MOWGLI_OS_MUTEX posix +# define MOWGLI_OS_LINUX +# define MOWGLI_OS linux +# define MOWGLI_OS_THREADS_POSIX +# define MOWGLI_OS_THREADS posix +# define MOWGLI_OS_MUTEX_POSIX +# define MOWGLI_OS_MUTEX posix #elif defined __APPLE__ -#define MOWGLI_OS_OSX -#define MOWGLI_OS osx -#define MOWGLI_OS_THREADS_POSIX -#define MOWGLI_OS_THREADS posix -#define MOWGLI_OS_MUTEX_POSIX -#define MOWGLI_OS_MUTEX posix -#define MOWGLI_OS_BSD_TYPE +# define MOWGLI_OS_OSX +# define MOWGLI_OS osx +# define MOWGLI_OS_THREADS_POSIX +# define MOWGLI_OS_THREADS posix +# define MOWGLI_OS_MUTEX_POSIX +# define MOWGLI_OS_MUTEX posix +# define MOWGLI_OS_BSD_TYPE -#ifdef MOWGLI_CPU_POWERPC -#define MOWGLI_CPU_ENDIAN_BIG -#define MOWGLI_CPU_ENDIAN big -#endif +# ifdef MOWGLI_CPU_POWERPC +# define MOWGLI_CPU_ENDIAN_BIG +# define MOWGLI_CPU_ENDIAN big +# endif #elif defined __WINDOWS__ || defined _WIN32 || defined __WIN32__ || defined __TOS_WIN__ -#if defined _WIN64 -#define MOWGLI_OS_WIN64 -#define MOWGLI_OS win64 -#else -#define MOWGLI_OS_WIN32 -#define MOWGLI_OS win32 -#endif -#define MOWGLI_OS_WIN -#define MOWGLI_OS_THREADS_WIN -#define MOWGLI_OS_THREADS win -#define MOWGLI_OS_MUTEX_WIN -#define MOWGLI_OS_MUTEX win +# if defined _WIN64 +# define MOWGLI_OS_WIN64 +# define MOWGLI_OS win64 +# else +# define MOWGLI_OS_WIN32 +# define MOWGLI_OS win32 +# endif +# define MOWGLI_OS_WIN +# define MOWGLI_OS_THREADS_WIN +# define MOWGLI_OS_THREADS win +# define MOWGLI_OS_MUTEX_WIN +# define MOWGLI_OS_MUTEX win -#if defined __CYGWIN__ -#define MOWGLI_OS_WIN_CYGWIN -#elif defined __MINGW32__ -#define MOWGLI_OS_WIN_MINGW -#endif +# if defined __CYGWIN__ +# define MOWGLI_OS_WIN_CYGWIN +# elif defined __MINGW32__ +# define MOWGLI_OS_WIN_MINGW +# endif -#if defined MOWGLI_CPU_POWERPC || defined MOWGLI_CPU_MIPS || defined MOWGLI_CPU_ITANIUM -#define MOWGLI_ENDIAN_CPU_LITTLE -#endif +# if defined MOWGLI_CPU_POWERPC || defined MOWGLI_CPU_MIPS || defined MOWGLI_CPU_ITANIUM +# define MOWGLI_ENDIAN_CPU_LITTLE +# endif #elif defined __NetBSD__ || defined __OpenBSD__ || defined __FreeBSD__ || defined __bsdi__ || defined __DragonFly__ || defined BSD || defined _SYSTYPE_BSD -#define MOWGLI_OS_BSD -#define MOWGLI_OS bsd -#define MOWGLI_OS_THREADS_POSIX -#define MOWGLI_OS_THREADS posix -#define MOWGLI_OS_MUTEX_POSIX -#define MOWGLI_OS_MUTEX posix -#define MOWGLI_OS_BSD_TYPE +# define MOWGLI_OS_BSD +# define MOWGLI_OS bsd +# define MOWGLI_OS_THREADS_POSIX +# define MOWGLI_OS_THREADS posix +# define MOWGLI_OS_MUTEX_POSIX +# define MOWGLI_OS_MUTEX posix +# define MOWGLI_OS_BSD_TYPE #elif defined __GNU__ -#define MOWGLI_OS_HURD -#define MOWGLI_OS hurd -#define MOWGLI_OS_THREADS_POSIX -#define MOWGLI_OS_THREADS posix -#define MOWGLI_OS_MUTEX_POSIX -#define MOWGLI_OS_MUTEX posix +# define MOWGLI_OS_HURD +# define MOWGLI_OS hurd +# define MOWGLI_OS_THREADS_POSIX +# define MOWGLI_OS_THREADS posix +# define MOWGLI_OS_MUTEX_POSIX +# define MOWGLI_OS_MUTEX posix #elif defined sco || defined __sco -#define MOWGLI_OS_SCO -#define MOWGLI_OS sco -#define MOWGLI_OS_THREADS_POSIX -#define MOWGLI_OS_THREADS posix -#define MOWGLI_OS_MUTEX_POSIX -#define MOWGLI_OS_MUTEX posix -#define MOWGLI_OS_UNIX_TYPE +# define MOWGLI_OS_SCO +# define MOWGLI_OS sco +# define MOWGLI_OS_THREADS_POSIX +# define MOWGLI_OS_THREADS posix +# define MOWGLI_OS_MUTEX_POSIX +# define MOWGLI_OS_MUTEX posix +# define MOWGLI_OS_UNIX_TYPE #elif defined sun || defined __sun -#define MOWGLI_OS_SOLARIS -#define MOWGLI_OS solaris -#define MOWGLI_OS_THREADS_POSIX -#define MOWGLI_OS_THREADS posix -#define MOWGLI_OS_MUTEX_POSIX -#define MOWGLI_OS_MUTEX posix -#define MOWGLI_OS_UNIX_TYPE -#if defined MOWGLI_CPU_POWERPC -#define MOWGLI_CPU_ENDIAN_LITTLE -#define MOWGLI_CPU_ENDIAN little -#endif +# define MOWGLI_OS_SOLARIS +# define MOWGLI_OS solaris +# define MOWGLI_OS_THREADS_SOLARIS +# define MOWGLI_OS_THREADS solaris +# define MOWGLI_OS_MUTEX_POSIX +# define MOWGLI_OS_MUTEX posix +# define MOWGLI_OS_UNIX_TYPE +# if defined MOWGLI_CPU_POWERPC +# define MOWGLI_CPU_ENDIAN_LITTLE +# define MOWGLI_CPU_ENDIAN little +# endif #elif defined _hpux || defined hpux || defined __hpux -#define MOWGLI_OS_HPUX -#define MOWGLI_OS hpux -#define MOWGLI_OS_THREADS_POSIX -#define MOWGLI_OS_THREADS posix -#define MOWGLI_OS_MUTEX_POSIX -#define MOWGLI_OS_MUTEX posix -#define MOWGLI_OS_UNIX_TYPE -#if defined MOWGLI_CPU_ITANIUM -#define MOWGLI_CPU_ENDIAN_BIG -#define MOWGLI_CPU_ENDIAN big -#endif +# define MOWGLI_OS_HPUX +# define MOWGLI_OS hpux +# define MOWGLI_OS_THREADS_POSIX +# define MOWGLI_OS_THREADS posix +# define MOWGLI_OS_MUTEX_POSIX +# define MOWGLI_OS_MUTEX posix +# define MOWGLI_OS_UNIX_TYPE +# if defined MOWGLI_CPU_ITANIUM +# define MOWGLI_CPU_ENDIAN_BIG +# define MOWGLI_CPU_ENDIAN big +# endif #elif defined __QNX__ || defined __QNXNTO__ -#define MOWGLI_OS_QNX -#define MOWGLI_OS qnx -#define MOWGLI_OS_THREADS_QNX -#define MOWGLI_OS_THREADS qnx -#define MOWGLI_OS_MUTEX_POSIX -#define MOWGLI_OS_MUTEX posix +# define MOWGLI_OS_QNX +# define MOWGLI_OS qnx +# define MOWGLI_OS_THREADS_QNX +# define MOWGLI_OS_THREADS qnx +# define MOWGLI_OS_MUTEX_POSIX +# define MOWGLI_OS_MUTEX posix #elif defined __vms || defined __VMS -#define MOWGLI_OS_THREADS_POSIX -#define MOWGLI_OS_THREADS posix -#define MOWGLI_OS_MUTEX_POSIX -#define MOWGLI_OS_MUTEX posix -#if defined MOWGLI_CPU_ITANIUM -#define MOWGLI_CPU_ENDIAN_LITTLE -#define MOWGLI_CPU_ENDIAN little -#endif +# define MOWGLI_OS_THREADS_POSIX +# define MOWGLI_OS_THREADS posix +# define MOWGLI_OS_MUTEX_POSIX +# define MOWGLI_OS_MUTEX posix +# if defined MOWGLI_CPU_ITANIUM +# define MOWGLI_CPU_ENDIAN_LITTLE +# define MOWGLI_CPU_ENDIAN little +# endif #endif #ifndef MOWGLI_OS -#if defined __unix__ || __unix || unix -#define MOWGLI_OS_UNIX -#define MOWGLI_OS unix -#define MOWGLI_OS_THREADS_POSIX -#define MOWGLI_OS_THREADS posix -#define MOWGLI_OS_MUTEX_POSIX -#define MOWGLI_OS_MUTEX posix -#define MOWGLI_OS_UNIX_TYPE -#endif -#define MOWGLI_OS_UNKNOWN -#define MOWGLI_OS unknown -#warning OS unsupported/unknown +# if defined __unix__ || __unix || unix +# define MOWGLI_OS_UNIX +# define MOWGLI_OS unix +# define MOWGLI_OS_THREADS_POSIX +# define MOWGLI_OS_THREADS posix +# define MOWGLI_OS_MUTEX_POSIX +# define MOWGLI_OS_MUTEX posix +# define MOWGLI_OS_UNIX_TYPE +# endif +# define MOWGLI_OS_UNKNOWN +# define MOWGLI_OS unknown +# warning OS unsupported/unknown #endif #ifndef MOWGLI_OS_THREADS -#define MOWGLI_OS_THREADS_NULL -#define MOWGLI_OS_THREADS null +# define MOWGLI_OS_THREADS_NULL +# define MOWGLI_OS_THREADS null #endif #ifndef MOWGLI_OS_MUTEX -#define MOWGLI_OS_MUTEX_NULL -#define MOWGLI_OS_MUTEX null +# define MOWGLI_OS_MUTEX_NULL +# define MOWGLI_OS_MUTEX null #endif #ifndef MOWGLI_CPU_ENDIAN -#if defined __BIG_ENDIAN__ || defined __ARMEB__ || defined __THUMBEB__ || defined _MIPSEB || defined __MIPSEB || defined __MIPSEB__ || __BYTE_ORDER == __BIG_ENDIAN -#define MOWGLI_CPU_ENDIAN_BIG -#define MOWGLI_CPU_ENDIAN big -#elif defined __LITTLE_ENDIAN__ || defined __ARMEL__ || defined __THUMBEL__ || defined _MIPSEL || defined __MIPSEL || defined __MIPSEL__ || __BYTE_ORDER == __LITTLE_ENDIAN -#define MOWGLI_CPU_ENDIAN_LITTLE -#define MOWGLI_CPU_ENDIAN little -#else -#warning CPU endianness unknown, some functions of libmowgli will not work -#endif +# if defined __BIG_ENDIAN__ || defined __ARMEB__ || defined __THUMBEB__ || defined _MIPSEB || defined __MIPSEB || defined __MIPSEB__ || __BYTE_ORDER == __BIG_ENDIAN +# define MOWGLI_CPU_ENDIAN_BIG +# define MOWGLI_CPU_ENDIAN big +# elif defined __LITTLE_ENDIAN__ || defined __ARMEL__ || defined __THUMBEL__ || defined _MIPSEL || defined __MIPSEL || defined __MIPSEL__ || __BYTE_ORDER == __LITTLE_ENDIAN +# define MOWGLI_CPU_ENDIAN_LITTLE +# define MOWGLI_CPU_ENDIAN little +# else +# warning CPU endianness unknown, some functions of libmowgli will not work +# endif #endif #endif diff --git a/src/libmowgli/platform/win32/Makefile b/src/libmowgli/platform/win32/Makefile index 653bf2d..73e7c74 100644 --- a/src/libmowgli/platform/win32/Makefile +++ b/src/libmowgli/platform/win32/Makefile @@ -3,7 +3,7 @@ include ../../../../extra.mk STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_PLATFORM_WIN32} STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_PLATFORM_WIN32} -SRCS = fork.c gettimeofday.c inet.c pipe.c socketpair.c setenv.c +SRCS = fork.c inet.c pipe.c socketpair.c setenv.c INCLUDES = win32_stdinc.h diff --git a/src/libmowgli/platform/win32/fork.c b/src/libmowgli/platform/win32/fork.c index c644122..a55d99c 100644 --- a/src/libmowgli/platform/win32/fork.c +++ b/src/libmowgli/platform/win32/fork.c @@ -31,17 +31,18 @@ #ifdef NOTYET -#ifdef _WIN32 +# ifdef _WIN32 -#ifndef _WIN32_WINNT +# ifndef _WIN32_WINNT -int fork(void) +int +fork(void) { -#warning fork is not possible on your platform in any sane way, sorry :( +# warning fork is not possible on your platform in any sane way, sorry :( return -ENOSYS; } -#else +# else extern NTSTATUS NTAPI CsrCallClientServer(void *message, void *userdata, uint32_t opcode, uint32_t size); @@ -50,7 +51,8 @@ extern NTSTATUS NTAPI CsrCallClientServer(void *message, void *userdata, uint32_ * * Not sure what dummy1/dummy2 do, but they're junk as far as I can see. */ -struct csrss_message { +struct csrss_message +{ uint32_t dummy1; uint32_t opcode; uint32_t status; @@ -77,10 +79,8 @@ inherit_handles(void) pid = GetCurrentProcessId(); for (i = 0; i < *p; i++) - { if (info[i].ProcessId == pid) SetHandleInformation((HANDLE) h[i].Handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); - } mowgli_free(p); } @@ -88,27 +88,34 @@ inherit_handles(void) static inline void request_csrss_session(HANDLE proc_handle, HANDLE thread_handle, uint32_t pid, uint32_t tid) { - struct { + struct + { PORT_MESSAGE port_message; struct csrss_message csrss_message; + PROCESS_INFORMATION process_information; CLIENT_ID debugger; uint32_t flags; uint32_t vdminfo[2]; - } csrmsg = {{0}, {0}, {proc_handle, thread_handle, pid, tid}, {0}, 0, {0}}; + } csrmsg = + { + { 0 }, { 0 }, { proc_handle, thread_handle, pid, tid }, { 0 }, 0, { 0 } + }; CsrCallClientServer(&csrmsg, NULL, 0x10000, sizeof csrmsg); } -int child(void) +int +child(void) { typedef BOOL (*CsrpConnectToServer)(PWSTR); - CsrpConnectToServer (0x77F8F65D) (L"\\Windows"); + CsrpConnectToServer(0x77F8F65D) (L"\\Windows"); __asm__("mov eax, 0; mov esp, ebp; pop ebp; ret"); } -int fork(void) +int +fork(void) { HANDLE proc_handle, thread_handle; OBJECT_ATTRIBUTES oa = { sizeof(oa) }; @@ -133,8 +140,8 @@ int fork(void) ZwQueryVirtualMemory(NtCurrentProcess(), (void *) context.Esp, MemoryBasicInformation, &mbi, sizeof mbi, 0); - stack = (USER_STACK){0, 0, ((char *) mbi.BaseAddress) + mbi.RegionSize, - mbi.BaseAddress, mbi.AllocationBase}; + stack = (USER_STACK) { 0, 0, ((char *) mbi.BaseAddress) + mbi.RegionSize, + mbi.BaseAddress, mbi.AllocationBase }; /* now spawn the thread! */ ZwCreateThread(&thread_handle, THREAD_ALL_ACCESS, &oa, proc_handle, &cid, &context, &stack, TRUE); @@ -159,8 +166,8 @@ int fork(void) return (int) cid.UniqueProcess; } -#endif +# endif -#endif +# endif #endif diff --git a/src/libmowgli/platform/win32/gettimeofday.c b/src/libmowgli/platform/win32/gettimeofday.c deleted file mode 100644 index 1e96797..0000000 --- a/src/libmowgli/platform/win32/gettimeofday.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * win32_support.c: Support functions and values for Win32 platform. - * - * Copyright (c) 2009 SystemInPlace, Inc. - * - * 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 is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "mowgli.h" - -#ifdef _MSC_VER -# define EPOCH_TIME_IN_MICROSECS 11644473600000000Ui64 -#else -# define EPOCH_TIME_IN_MICROSECS 11644473600000000ULL -#endif - -#ifdef _WIN32 -int gettimeofday(struct timeval *tv, struct timezone *tz) -{ - FILETIME ft; - ULARGE_INTEGER tmpres; - static mowgli_boolean_t tz_init_done = FALSE; - - if (tv != NULL) - { - GetSystemTimeAsFileTime(&ft); - - tmpres.u.HighPart = ft.dwHighDateTime; - tmpres.u.LowPart = ft.dwLowDateTime; - - tmpres.QuadPart /= 10; - tmpres.QuadPart -= EPOCH_TIME_IN_MICROSECS; - tv->tv_sec = (long) (tmpres.QuadPart / 1000000UL); - tv->tv_usec = (long) (tmpres.QuadPart % 1000000UL); - } - - if (tz != NULL) - { - if (!tz_init_done) - { - _tzset(); - tz_init_done = TRUE; - } - - tz->tz_minuteswest = _timezone / 60; - tz->tz_dsttime = _daylight; - } - - return 0; -} -#endif diff --git a/src/libmowgli/platform/win32/inet.c b/src/libmowgli/platform/win32/inet.c index 051ae7f..eb0b1fc 100644 --- a/src/libmowgli/platform/win32/inet.c +++ b/src/libmowgli/platform/win32/inet.c @@ -22,37 +22,39 @@ #ifdef _WIN32 -int inet_pton(int af, const char *src, void *dst) +int +inet_pton(int af, const char *src, void *dst) { struct sockaddr_storage ss; + int size = sizeof(struct sockaddr_storage); char src_copy[INET6_ADDRSTRLEN + 1]; mowgli_strlcpy(src_copy, src, sizeof src_copy); if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *) &ss, &size) != SOCKET_ERROR) - { switch (af) { case AF_INET: - *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr; + *(struct in_addr *) dst = ((struct sockaddr_in *) &ss)->sin_addr; return 1; case AF_INET6: - *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr; + *(struct in6_addr *) dst = ((struct sockaddr_in6 *) &ss)->sin6_addr; return 1; default: return 0; } - } return -1; } -const char *inet_ntop(int af, const void *addr, char *host, size_t hostlen) +const char * +inet_ntop(int af, const void *addr, char *host, size_t hostlen) { struct sockaddr_storage ss; + int size = sizeof(struct sockaddr_storage); ss.ss_family = af; @@ -60,11 +62,11 @@ const char *inet_ntop(int af, const void *addr, char *host, size_t hostlen) switch (af) { case AF_INET: - memcpy(&(((struct sockaddr_in *) &ss)->sin_addr), (struct in_addr *) addr, sizeof (struct in_addr)); + memcpy(&(((struct sockaddr_in *) &ss)->sin_addr), (struct in_addr *) addr, sizeof(struct in_addr)); break; case AF_INET6: - memcpy(&(((struct sockaddr_in6 *) &ss)->sin6_addr), (struct in6_addr *) addr, sizeof (struct in6_addr)); + memcpy(&(((struct sockaddr_in6 *) &ss)->sin6_addr), (struct in6_addr *) addr, sizeof(struct in6_addr)); break; default: diff --git a/src/libmowgli/platform/win32/pipe.c b/src/libmowgli/platform/win32/pipe.c index 5da3dd2..38d3d16 100644 --- a/src/libmowgli/platform/win32/pipe.c +++ b/src/libmowgli/platform/win32/pipe.c @@ -24,8 +24,10 @@ #include "mowgli.h" #ifdef _WIN32 -int pipe(int pipefd[2]) +int +pipe(int pipefd[2]) { return socketpair(AF_INET, SOCK_STREAM, 0, pipefd); } + #endif diff --git a/src/libmowgli/platform/win32/setenv.c b/src/libmowgli/platform/win32/setenv.c index f80a574..2854ddf 100644 --- a/src/libmowgli/platform/win32/setenv.c +++ b/src/libmowgli/platform/win32/setenv.c @@ -24,8 +24,10 @@ #include "mowgli.h" #ifdef _WIN32 -int setenv(const char *name, const char *value, int overwrite) +int +setenv(const char *name, const char *value, int overwrite) { return !SetEnvironmentVariable(name, value); } + #endif diff --git a/src/libmowgli/platform/win32/socketpair.c b/src/libmowgli/platform/win32/socketpair.c index 6ede51e..b641838 100644 --- a/src/libmowgli/platform/win32/socketpair.c +++ b/src/libmowgli/platform/win32/socketpair.c @@ -1,11 +1,11 @@ /* socketpair.c * Copyright 2007, 2010 by Nathan C. Myers - * This code is Free Software. It may be copied freely, in original or + * This code is Free Software. It may be copied freely, in original or * modified form, subject only to the restrictions that (1) the author is * relieved from all responsibilities for any use for any purpose, and (2) * this copyright notice must be retained, unchanged, in its entirety. If * for any reason the author might be held responsible for any consequences - * of copying or use, license is withheld. + * of copying or use, license is withheld. */ /* Changes: @@ -13,8 +13,8 @@ * set addr to 127.0.0.1 because win32 getsockname does not always set it. * 2010-02-25: * set SO_REUSEADDR option to avoid leaking some windows resource. - * Windows System Error 10049, "Event ID 4226 TCP/IP has reached - * the security limit imposed on the number of concurrent TCP connect + * Windows System Error 10049, "Event ID 4226 TCP/IP has reached + * the security limit imposed on the number of concurrent TCP connect * attempts." Bleah. * 2007-04-25: * preserve value of WSAGetLastError() on all error returns. @@ -32,78 +32,91 @@ /* dumb_socketpair: * If make_overlapped is nonzero, both sockets created will be usable for * "overlapped" operations via WSASend etc. If make_overlapped is zero, - * socks[0] (only) will be usable with regular ReadFile etc., and thus + * socks[0] (only) will be usable with regular ReadFile etc., and thus * suitable for use as stdin or stdout of a child process. Note that the * sockets must be closed with closesocket() regardless. */ -int socketpair(int domain, int type, int protocol, int socks[2]) +int +socketpair(int domain, int type, int protocol, int socks[2]) { - union { - struct sockaddr_in inaddr; - struct sockaddr addr; - } a; - SOCKET listener; - int e; - socklen_t addrlen = sizeof(a.inaddr); - int make_overlapped = 0; - DWORD flags = (make_overlapped ? WSA_FLAG_OVERLAPPED : 0); - int reuse = 1; - - if (socks == NULL) { - WSASetLastError(WSAEINVAL); - return SOCKET_ERROR; - } - - listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (listener == INVALID_SOCKET) - return SOCKET_ERROR; - - memset(&a, 0, sizeof(a)); - a.inaddr.sin_family = AF_INET; - a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - a.inaddr.sin_port = 0; - - socks[0] = socks[1] = INVALID_SOCKET; - do { - if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, - (char*) &reuse, (socklen_t) sizeof(reuse)) == -1) - break; - if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) - break; - - memset(&a, 0, sizeof(a)); - if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR) - break; - // win32 getsockname may only set the port number, p=0.0005. - // ( http://msdn.microsoft.com/library/ms738543.aspx ): - a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - a.inaddr.sin_family = AF_INET; - - if (listen(listener, 1) == SOCKET_ERROR) - break; - - socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags); - if (socks[0] == (int) INVALID_SOCKET) - break; - if (connect(socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) - break; - - socks[1] = accept(listener, NULL, NULL); - if (socks[1] == (int) INVALID_SOCKET) - break; - - closesocket(listener); - return 0; - - } while (0); - - e = WSAGetLastError(); - closesocket(listener); - closesocket(socks[0]); - closesocket(socks[1]); - WSASetLastError(e); - return SOCKET_ERROR; + union + { + struct sockaddr_in inaddr; + + struct sockaddr addr; + } a; + + SOCKET listener; + int e; + socklen_t addrlen = sizeof(a.inaddr); + int make_overlapped = 0; + DWORD flags = (make_overlapped ? WSA_FLAG_OVERLAPPED : 0); + int reuse = 1; + + if (socks == NULL) + { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + + listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (listener == INVALID_SOCKET) + return SOCKET_ERROR; + + memset(&a, 0, sizeof(a)); + a.inaddr.sin_family = AF_INET; + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_port = 0; + + socks[0] = socks[1] = INVALID_SOCKET; + + do + { + if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, + (char *) &reuse, (socklen_t) sizeof(reuse)) == -1) + break; + + if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) + break; + + memset(&a, 0, sizeof(a)); + + if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR) + break; + + // win32 getsockname may only set the port number, p=0.0005. + // ( http://msdn.microsoft.com/library/ms738543.aspx ): + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_family = AF_INET; + + if (listen(listener, 1) == SOCKET_ERROR) + break; + + socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags); + + if (socks[0] == (int) INVALID_SOCKET) + break; + + if (connect(socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) + break; + + socks[1] = accept(listener, NULL, NULL); + + if (socks[1] == (int) INVALID_SOCKET) + break; + + closesocket(listener); + return 0; + } while (0); + + e = WSAGetLastError(); + closesocket(listener); + closesocket(socks[0]); + closesocket(socks[1]); + WSASetLastError(e); + return SOCKET_ERROR; } #endif diff --git a/src/libmowgli/platform/win32/win32_stdinc.h b/src/libmowgli/platform/win32/win32_stdinc.h index 1360a4a..e4e1d05 100644 --- a/src/libmowgli/platform/win32/win32_stdinc.h +++ b/src/libmowgli/platform/win32/win32_stdinc.h @@ -26,24 +26,18 @@ #ifdef _WIN32 -#include -#include -#include - -#define strcasecmp _stricmp -#define strdup _strdup -#define usleep(_usecs) Sleep((_usecs)/1000L) -#ifdef _MSC_VER -# define snprintf _snprintf -#endif +# include +# include +# include -struct timezone { - int tz_minuteswest; - int tz_dsttime; -}; +# define strcasecmp _stricmp +# define strdup _strdup +# ifdef _MSC_VER +# define snprintf _snprintf +# endif -extern int gettimeofday(struct timeval *tv, struct timezone *tz); extern int setenv(const char *name, const char *value, int overwrite); + extern int pipe(int pipefd[2]); extern int socketpair(int domain, int type, int protocol, int pipefd[2]); extern int fork(void); @@ -51,11 +45,11 @@ extern int inet_pton(int af, const char *src, void *dst); extern const char *inet_ntop(int af, const void *addr, char *host, size_t hostlen); /* MSYS autoconf is fucko. */ -#ifndef HAVE_WINSOCK2_H -#define HAVE_WINSOCK2_H -#endif +# ifndef HAVE_WINSOCK2_H +# define HAVE_WINSOCK2_H +# endif -#define HAVE_SELECT +# define HAVE_SELECT #endif diff --git a/src/libmowgli/thread/mutex.c b/src/libmowgli/thread/mutex.c index 1d5d480..c60902a 100644 --- a/src/libmowgli/thread/mutex.c +++ b/src/libmowgli/thread/mutex.c @@ -25,8 +25,6 @@ #if defined(_WIN32) extern const mowgli_mutex_ops_t _mowgli_win32_mutex_ops; -#elif defined(_sun) || defined(_sco) -extern const mowgli_mutex_ops_t _mowgli_sun_mutex_ops; #else extern const mowgli_mutex_ops_t _mowgli_posix_mutex_ops; #endif @@ -35,7 +33,8 @@ extern const mowgli_mutex_ops_t _mowgli_null_mutex_ops; static const mowgli_mutex_ops_t *_mowgli_mutex_ops = NULL; -static inline const mowgli_mutex_ops_t *get_mutex_platform(void) +static inline const mowgli_mutex_ops_t * +get_mutex_platform(void) { /* allow for threading policy to set custom mutex ops */ if (_mowgli_mutex_ops != NULL) @@ -45,10 +44,6 @@ static inline const mowgli_mutex_ops_t *get_mutex_platform(void) return &_mowgli_win32_mutex_ops; #endif -#if defined(_sun) || defined(_sco) - return &_mowgli_sun_mutex_ops; -#endif - #if !defined(MOWGLI_FEATURE_HAVE_NATIVE_MUTEXES) return &_mowgli_posix_mutex_ops; #endif @@ -56,14 +51,17 @@ static inline const mowgli_mutex_ops_t *get_mutex_platform(void) return &_mowgli_null_mutex_ops; } -mowgli_mutex_t *mowgli_mutex_create(void) +mowgli_mutex_t * +mowgli_mutex_create(void) { mowgli_mutex_t *mutex = mowgli_alloc(sizeof(mowgli_mutex_t)); return_val_if_fail(mutex != NULL, NULL); if (mowgli_mutex_init(mutex)) + { return mutex; + } else { mowgli_free(mutex); @@ -71,7 +69,8 @@ mowgli_mutex_t *mowgli_mutex_create(void) } } -int mowgli_mutex_init(mowgli_mutex_t *mutex) +int +mowgli_mutex_init(mowgli_mutex_t *mutex) { return_val_if_fail(mutex != NULL, -1); @@ -80,7 +79,8 @@ int mowgli_mutex_init(mowgli_mutex_t *mutex) return mutex->ops->mutex_create(mutex); } -int mowgli_mutex_lock(mowgli_mutex_t *mutex) +int +mowgli_mutex_lock(mowgli_mutex_t *mutex) { return_val_if_fail(mutex != NULL, -1); return_val_if_fail(mutex->ops != NULL, -1); @@ -88,7 +88,8 @@ int mowgli_mutex_lock(mowgli_mutex_t *mutex) return mutex->ops->mutex_lock(mutex); } -int mowgli_mutex_trylock(mowgli_mutex_t *mutex) +int +mowgli_mutex_trylock(mowgli_mutex_t *mutex) { return_val_if_fail(mutex != NULL, -1); return_val_if_fail(mutex->ops != NULL, -1); @@ -96,7 +97,8 @@ int mowgli_mutex_trylock(mowgli_mutex_t *mutex) return mutex->ops->mutex_trylock(mutex); } -int mowgli_mutex_unlock(mowgli_mutex_t *mutex) +int +mowgli_mutex_unlock(mowgli_mutex_t *mutex) { return_val_if_fail(mutex != NULL, -1); return_val_if_fail(mutex->ops != NULL, -1); @@ -104,7 +106,8 @@ int mowgli_mutex_unlock(mowgli_mutex_t *mutex) return mutex->ops->mutex_unlock(mutex); } -int mowgli_mutex_uninit(mowgli_mutex_t *mutex) +int +mowgli_mutex_uninit(mowgli_mutex_t *mutex) { return_val_if_fail(mutex != NULL, -1); return_val_if_fail(mutex->ops != NULL, -1); @@ -112,7 +115,8 @@ int mowgli_mutex_uninit(mowgli_mutex_t *mutex) return mutex->ops->mutex_destroy(mutex); } -void mowgli_mutex_destroy(mowgli_mutex_t *mutex) +void +mowgli_mutex_destroy(mowgli_mutex_t *mutex) { return_if_fail(mutex != NULL); @@ -120,7 +124,8 @@ void mowgli_mutex_destroy(mowgli_mutex_t *mutex) mowgli_free(mutex); } -void mowgli_mutex_set_policy(mowgli_thread_policy_t policy) +void +mowgli_mutex_set_policy(mowgli_thread_policy_t policy) { switch (policy) { diff --git a/src/libmowgli/thread/mutex.h b/src/libmowgli/thread/mutex.h index f08013d..94ead78 100644 --- a/src/libmowgli/thread/mutex.h +++ b/src/libmowgli/thread/mutex.h @@ -28,17 +28,18 @@ # include # include # define MOWGLI_FEATURE_HAVE_NATIVE_MUTEXES -# define MOWGLI_NATIVE_MUTEX_DECL(name) mutex_t (name) +# define MOWGLI_NATIVE_MUTEX_DECL(name) mutex_t(name) #elif defined MOWGLI_OS_WIN # define MOWGLI_FEATURE_HAVE_NATIVE_MUTEXES -# define MOWGLI_NATIVE_MUTEX_DECL(name) HANDLE (name) +# define MOWGLI_NATIVE_MUTEX_DECL(name) HANDLE(name) #else # include #endif typedef struct mowgli_mutex_ mowgli_mutex_t; -typedef struct { +typedef struct +{ int (*mutex_create)(mowgli_mutex_t *mutex); int (*mutex_lock)(mowgli_mutex_t *mutex); int (*mutex_trylock)(mowgli_mutex_t *mutex); @@ -46,7 +47,8 @@ typedef struct { int (*mutex_destroy)(mowgli_mutex_t *mutex); } mowgli_mutex_ops_t; -struct mowgli_mutex_ { +struct mowgli_mutex_ +{ #ifdef MOWGLI_FEATURE_HAVE_NATIVE_MUTEXES MOWGLI_NATIVE_MUTEX_DECL(mutex); #else @@ -60,7 +62,7 @@ struct mowgli_mutex_ { #endif mowgli_mutex_t *mowgli_mutex_create(void); -int mowgli_mutex_init(mowgli_mutex_t* mutex); +int mowgli_mutex_init(mowgli_mutex_t *mutex); int mowgli_mutex_lock(mowgli_mutex_t *mutex); int mowgli_mutex_trylock(mowgli_mutex_t *mutex); int mowgli_mutex_unlock(mowgli_mutex_t *mutex); @@ -70,10 +72,10 @@ void mowgli_mutex_destroy(mowgli_mutex_t *mutex); void mowgli_mutex_set_policy(mowgli_thread_policy_t policy); /* simple dispatch function to set the ops up for the various subsystems. */ -static inline void mowgli_thread_set_policy(mowgli_thread_policy_t policy) +static inline void +mowgli_thread_set_policy(mowgli_thread_policy_t policy) { mowgli_mutex_set_policy(policy); } #endif - diff --git a/src/libmowgli/thread/null_mutexops.c b/src/libmowgli/thread/null_mutexops.c index 2750add..7a84c01 100644 --- a/src/libmowgli/thread/null_mutexops.c +++ b/src/libmowgli/thread/null_mutexops.c @@ -23,32 +23,38 @@ #include "mowgli.h" -static int mowgli_null_mutex_create(mowgli_mutex_t *mutex) +static int +mowgli_null_mutex_create(mowgli_mutex_t *mutex) { return 0; } -static int mowgli_null_mutex_lock(mowgli_mutex_t *mutex) +static int +mowgli_null_mutex_lock(mowgli_mutex_t *mutex) { return 0; } -static int mowgli_null_mutex_trylock(mowgli_mutex_t *mutex) +static int +mowgli_null_mutex_trylock(mowgli_mutex_t *mutex) { return 0; } -static int mowgli_null_mutex_unlock(mowgli_mutex_t *mutex) +static int +mowgli_null_mutex_unlock(mowgli_mutex_t *mutex) { return 0; } -static int mowgli_null_mutex_destroy(mowgli_mutex_t *mutex) +static int +mowgli_null_mutex_destroy(mowgli_mutex_t *mutex) { return 0; } -const mowgli_mutex_ops_t _mowgli_null_mutex_ops = { +const mowgli_mutex_ops_t _mowgli_null_mutex_ops = +{ .mutex_create = mowgli_null_mutex_create, .mutex_lock = mowgli_null_mutex_lock, .mutex_trylock = mowgli_null_mutex_trylock, diff --git a/src/libmowgli/thread/posix_mutexops.c b/src/libmowgli/thread/posix_mutexops.c index 5fb64e9..dbb7be2 100644 --- a/src/libmowgli/thread/posix_mutexops.c +++ b/src/libmowgli/thread/posix_mutexops.c @@ -26,83 +26,48 @@ #ifndef _WIN32 /************* - * This implements native Sun/UnixWare threads. Some other SVR4-based - * environments attempted to make work-alikes, but those aren't guaranteed - * to be supported. This should work on SunOS 5.2 and UnixWare 7, and - * anything later. - *************/ -#if defined(__sun) || defined(__sco) - -static int mowgli_sun_mutex_create(mowgli_mutex_t *mutex) -{ - return mutex_init(&mutex->mutex, USYNC_THREAD, NULL); -} - -static int mowgli_sun_mutex_lock(mowgli_mutex_t *mutex) -{ - return mutex_lock(&mutex->mutex); -} - -static int mowgli_sun_mutex_trylock(mowgli_mutex_t *mutex) -{ - return mutex_trylock(&mutex->mutex); -} - -static int mowgli_sun_mutex_unlock(mowgli_mutex_t *mutex) -{ - return mutex_unlock(&mutex->mutex); -} - -static int mowgli_sun_mutex_destroy(mowgli_mutex_t *mutex) -{ - return mutex_destroy(&mutex->mutex); -} - -const mowgli_mutex_ops_t _mowgli_sun_mutex_ops = { - .mutex_create = mowgli_sun_mutex_create, - .mutex_lock = mowgli_sun_mutex_lock, - .mutex_trylock = mowgli_sun_mutex_trylock, - .mutex_unlock = mowgli_sun_mutex_unlock, - .mutex_destroy = mowgli_sun_mutex_destroy, -}; - -/************* - * This "default" implementation uses pthreads. Care has been taken to - * ensure it runs on POSIX 1003.4a (draft 4, aka DECthreads, aka what OSF/1, - * Tru64, Ultrix, CMU Mach, and HP-UX use) as well as POSIX 1003.1c-1995. - * As long as you don't try playing with the pthread_attr module or the - * scheduler routines (which are non-standard and broken anyway, IMO) then - * it should be relatively easy to maintian d4 compatibility without - * sacrificing any functionality. - *************/ -#elif !defined(MOWGLI_FEATURE_HAVE_NATIVE_MUTEXES) - -static int mowgli_posix_mutex_create(mowgli_mutex_t *mutex) +* This "default" implementation uses pthreads. Care has been taken to +* ensure it runs on POSIX 1003.4a (draft 4, aka DECthreads, aka what OSF/1, +* Tru64, Ultrix, CMU Mach, and HP-UX use) as well as POSIX 1003.1c-1995. +* As long as you don't try playing with the pthread_attr module or the +* scheduler routines (which are non-standard and broken anyway, IMO) then +* it should be relatively easy to maintian d4 compatibility without +* sacrificing any functionality. +*************/ +# if !defined(MOWGLI_FEATURE_HAVE_NATIVE_MUTEXES) + +static int +mowgli_posix_mutex_create(mowgli_mutex_t *mutex) { return pthread_mutex_init(&mutex->mutex, NULL); } -static int mowgli_posix_mutex_lock(mowgli_mutex_t *mutex) +static int +mowgli_posix_mutex_lock(mowgli_mutex_t *mutex) { return pthread_mutex_lock(&mutex->mutex); } -static int mowgli_posix_mutex_trylock(mowgli_mutex_t *mutex) +static int +mowgli_posix_mutex_trylock(mowgli_mutex_t *mutex) { return pthread_mutex_trylock(&mutex->mutex); } -static int mowgli_posix_mutex_unlock(mowgli_mutex_t *mutex) +static int +mowgli_posix_mutex_unlock(mowgli_mutex_t *mutex) { return pthread_mutex_unlock(&mutex->mutex); } -static int mowgli_posix_mutex_destroy(mowgli_mutex_t *mutex) +static int +mowgli_posix_mutex_destroy(mowgli_mutex_t *mutex) { return pthread_mutex_destroy(&mutex->mutex); } -const mowgli_mutex_ops_t _mowgli_posix_mutex_ops = { +const mowgli_mutex_ops_t _mowgli_posix_mutex_ops = +{ .mutex_create = mowgli_posix_mutex_create, .mutex_lock = mowgli_posix_mutex_lock, .mutex_trylock = mowgli_posix_mutex_trylock, @@ -110,6 +75,6 @@ const mowgli_mutex_ops_t _mowgli_posix_mutex_ops = { .mutex_destroy = mowgli_posix_mutex_destroy, }; -#endif +# endif #endif diff --git a/src/libmowgli/thread/thread.h b/src/libmowgli/thread/thread.h index f063217..88939eb 100644 --- a/src/libmowgli/thread/thread.h +++ b/src/libmowgli/thread/thread.h @@ -28,15 +28,20 @@ #ifdef MOWGLI_OS_UNIX_TYPE # include # define MOWGLI_FEATURE_HAVE_NATIVE_THREADS -# define MOWGLI_NATIVE_THREAD_DECL(name) thread_t (name) +# ifdef MOWGLI_OS_THREADS_SOLARIS +# define MOWGLI_NATIVE_THREAD_DECL(name) pthread_t(name) +# else +# define MOWGLI_NATIVE_THREAD_DECL(name) thread_t(name) +# endif #elif defined MOWGLI_OS_WIN # define MOWGLI_FEATURE_HAVE_NATIVE_THREADS -# define MOWGLI_NATIVE_THREAD_DECL(name) HANDLE (name) +# define MOWGLI_NATIVE_THREAD_DECL(name) HANDLE(name) #else # include #endif -typedef struct { +typedef struct +{ #ifdef MOWGLI_FEATURE_HAVE_NATIVE_THREADS MOWGLI_NATIVE_THREAD_DECL(thread); #else @@ -55,10 +60,11 @@ typedef void *(*mowgli_thread_start_fn_t)(mowgli_thread_t *thread, void *userdat * portability. Creating, ending, killing and cleanup functions are presently implemented, * and cover approximately 99.999% of uses of thread APIs. --nenolod */ -typedef struct { +typedef struct +{ int (*thread_create)(mowgli_thread_t *thread, mowgli_thread_start_fn_t start_fn, void *userdata); void (*thread_exit)(mowgli_thread_t *thread); - void *(*thread_join)(mowgli_thread_t *thread); + void *(*thread_join)(mowgli_thread_t * thread); void (*thread_kill)(mowgli_thread_t *thread); void (*thread_destroy)(mowgli_thread_t *thread); } mowgli_thread_ops_t; @@ -69,10 +75,10 @@ void *mowgli_thread_join(mowgli_thread_t *thread); void mowgli_thread_kill(mowgli_thread_t *thread); void mowgli_thread_destroy(mowgli_thread_t *thread); -typedef enum { +typedef enum +{ MOWGLI_THREAD_POLICY_DEFAULT, MOWGLI_THREAD_POLICY_DISABLED, } mowgli_thread_policy_t; #endif - diff --git a/src/libmowgli/thread/win32_mutexops.c b/src/libmowgli/thread/win32_mutexops.c index 486992f..1e1bf5f 100644 --- a/src/libmowgli/thread/win32_mutexops.c +++ b/src/libmowgli/thread/win32_mutexops.c @@ -23,47 +23,53 @@ #include "mowgli.h" - /************* - * This Windows implementation is guaranteed to work on Windows 95, - * Windows NT 4, and anything later. - *************/ +* This Windows implementation is guaranteed to work on Windows 95, +* Windows NT 4, and anything later. +*************/ #if defined(_WIN32) -static int mowgli_win32_mutex_create(mowgli_mutex_t *mutex) +static int +mowgli_win32_mutex_create(mowgli_mutex_t *mutex) { mutex->mutex = CreateMutex(NULL, FALSE, NULL); - if(mutex->mutex == NULL) + + if (mutex->mutex == NULL) return GetLastError(); return 0; } -static int mowgli_win32_mutex_lock(mowgli_mutex_t *mutex) +static int +mowgli_win32_mutex_lock(mowgli_mutex_t *mutex) { return WaitForSingleObject(mutex->mutex, INFINITE); } -static int mowgli_win32_mutex_trylock(mowgli_mutex_t *mutex) +static int +mowgli_win32_mutex_trylock(mowgli_mutex_t *mutex) { return WaitForSingleObject(mutex->mutex, 0); } -static int mowgli_win32_mutex_unlock(mowgli_mutex_t *mutex) +static int +mowgli_win32_mutex_unlock(mowgli_mutex_t *mutex) { - if(ReleaseMutex(mutex->mutex) != 0) + if (ReleaseMutex(mutex->mutex) != 0) return 0; return GetLastError(); } -static int mowgli_win32_mutex_destroy(mowgli_mutex_t *mutex) +static int +mowgli_win32_mutex_destroy(mowgli_mutex_t *mutex) { CloseHandle(mutex->mutex); return 0; } -const mowgli_mutex_ops_t _mowgli_win32_mutex_ops = { +const mowgli_mutex_ops_t _mowgli_win32_mutex_ops = +{ .mutex_create = mowgli_win32_mutex_create, .mutex_lock = mowgli_win32_mutex_lock, .mutex_trylock = mowgli_win32_mutex_trylock, diff --git a/src/libmowgli/vio/vio.c b/src/libmowgli/vio/vio.c index ef4fb90..2570e22 100644 --- a/src/libmowgli/vio/vio.c +++ b/src/libmowgli/vio/vio.c @@ -36,11 +36,13 @@ static mowgli_heap_t *vio_heap = NULL; /* Change these to suit your needs for new VIO objects */ -mowgli_vio_ops_t mowgli_vio_default_ops = { +mowgli_vio_ops_t mowgli_vio_default_ops = +{ .socket = mowgli_vio_default_socket, .bind = mowgli_vio_default_bind, .listen = mowgli_vio_default_listen, .accept = mowgli_vio_default_accept, + .reuseaddr = mowgli_vio_default_reuseaddr, .connect = mowgli_vio_default_connect, .read = mowgli_vio_default_read, .write = mowgli_vio_default_write, @@ -52,7 +54,20 @@ mowgli_vio_ops_t mowgli_vio_default_ops = { .tell = mowgli_vio_default_tell, }; -mowgli_vio_t * mowgli_vio_create(void *userdata) +/* Null ops */ +mowgli_vio_evops_t mowgli_vio_default_evops = +{ + .read_cb = NULL, + .write_cb = NULL +}; + +/* mowgli_vio_create - create a VIO object on the heap + * + * inputs - userdata for the VIO object + * outputs - a VIO object + */ +mowgli_vio_t * +mowgli_vio_create(void *userdata) { mowgli_vio_t *vio; @@ -68,59 +83,138 @@ mowgli_vio_t * mowgli_vio_create(void *userdata) return vio; } -void mowgli_vio_init(mowgli_vio_t *vio, void *userdata) +/* mowgli_vio_init - initalise a VIO object previously allocated + * only use this if you know what you're doing, otherwise use mowgli_vio_create + * + * inputs - VIO object, userdata + * outputs - None + */ +void +mowgli_vio_init(mowgli_vio_t *vio, void *userdata) { - vio->fd = -1; + return_if_fail(vio); + + vio->io.fd = -1; vio->flags = 0; /* Default ops */ - vio->ops = mowgli_vio_default_ops; + vio->ops = &mowgli_vio_default_ops; vio->userdata = userdata; } -void mowgli_vio_eventloop_attach(mowgli_vio_t *vio, mowgli_eventloop_t *eventloop) +/* mowgli_vio_eventloop_attach - attach a VIO object to an eventloop + * + * inputs - VIO object, eventloop, ops to use for the eventloop (optional but recommended) + * outputs - None + */ +void +mowgli_vio_eventloop_attach(mowgli_vio_t *vio, mowgli_eventloop_t *eventloop, mowgli_vio_evops_t *evops) { - vio->io = mowgli_pollable_create(eventloop, vio->fd, vio->userdata); - if (vio->io != NULL) + return_if_fail(vio); + return_if_fail(eventloop); + + const int fd = vio->io.fd; + + /* Check for previous attachment */ + if (vio->eventloop) + { + mowgli_log("VIO object [%p] is already attached to eventloop [%p]; attempted to attach new eventloop [%p]", (void *) vio, (void *) vio->eventloop, (void *) eventloop); + return; + } + + if ((vio->io.e = mowgli_pollable_create(eventloop, fd, vio->userdata)) != NULL) { vio->eventloop = eventloop; + /* You're probably going to want this */ - mowgli_pollable_set_nonblocking(vio->io, true); + mowgli_pollable_set_nonblocking(vio->io.e, true); + + if (evops) + vio->evops = evops; + else + /* Default NULL ops */ + vio->evops = &mowgli_vio_default_evops; } else - mowgli_log("Unable to create pollable with VIO object [%p], expect problems.", vio); + { + mowgli_log("Unable to create pollable with VIO object [%p], expect problems.", (void *) vio); + vio->io.fd = fd;/* May have been clobbered */ + } } -void mowgli_vio_eventloop_detach(mowgli_vio_t *vio) +/* mowgli_vio_eventloop_detach - detach VIO object from eventloop + * + * inputs - VIO object + * output - None + */ +void +mowgli_vio_eventloop_detach(mowgli_vio_t *vio) { - return_if_fail(vio->io != NULL); + const int fd = mowgli_vio_getfd(vio); + + return_if_fail(fd != -1); + + return_if_fail(vio != NULL); + return_if_fail(vio->io.e != NULL); return_if_fail(vio->eventloop != NULL); - mowgli_pollable_destroy(vio->eventloop, vio->io); + mowgli_pollable_destroy(vio->eventloop, vio->io.e); + + vio->eventloop = NULL; + vio->io.fd = fd; } -void mowgli_vio_destroy(mowgli_vio_t *vio) +/* mowgli_vio_destroy - eliminate a VIO object + * + * inputs - VIO object + * output - None + */ +void +mowgli_vio_destroy(mowgli_vio_t *vio) { - mowgli_vio_eventloop_detach(vio); + return_if_fail(vio); + + if (vio->eventloop != NULL) + mowgli_vio_eventloop_detach(vio); + + if (!MOWGLI_VIO_IS_CLOSED(vio)) + mowgli_vio_close(vio); if (mowgli_vio_hasflag(vio, MOWGLI_VIO_FLAGS_ISONHEAP)) mowgli_heap_free(vio_heap, vio); } -int mowgli_vio_err_errcode(mowgli_vio_t *vio, char *(*int_to_error)(int), int errcode) +/* mowgli_vio_err_errcode - Signal an error using the specified char *foo(int err) callback + * Usually the callback can be strerror, but it can use anything else that fits the mould. + * + * inputs - VIO object, callback, error code. + * outputs - Error code from mowgli_vio_error function, any output to terminal/log files/etc. + */ +int +mowgli_vio_err_errcode(mowgli_vio_t *vio, char *(*int_to_error)(int), int errcode) { + return_val_if_fail(vio, -255); + vio->error.type = MOWGLI_VIO_ERR_ERRCODE; vio->error.code = errcode; mowgli_strlcpy(vio->error.string, int_to_error(errcode), sizeof(vio->error.string)); return mowgli_vio_error(vio); } +/* mowgli_vio_err_sslerrcode - Signal an SSL error + * + * inputs - VIO object, error code + * outputs - Error code from mowgli_vio_error function, any output to terminal/log files/etc. + */ #ifdef HAVE_OPENSSL -int mowgli_vio_err_sslerrcode(mowgli_vio_t *vio, int errcode) +int +mowgli_vio_err_sslerrcode(mowgli_vio_t *vio, unsigned long int errcode) { + return_val_if_fail(vio, -255); + vio->error.type = MOWGLI_VIO_ERR_ERRCODE; vio->error.code = errcode; ERR_error_string_n(errcode, vio->error.string, sizeof(vio->error.string)); @@ -129,8 +223,11 @@ int mowgli_vio_err_sslerrcode(mowgli_vio_t *vio, int errcode) #else -int mowgli_vio_err_sslerrcode(mowgli_vio_t *vio, int errcode) +int +mowgli_vio_err_sslerrcode(mowgli_vio_t *vio, unsigned long int errcode) { + return_if_fail(vio); + vio->error.type = MOWGLI_VIO_ERR_ERRCODE; vio->error.code = errcode; mowgli_strlcpy(vio->error.string, "Unknown SSL error", sizeof(vio->error.string)); diff --git a/src/libmowgli/vio/vio.h b/src/libmowgli/vio/vio.h index 37b5c37..aafab2a 100644 --- a/src/libmowgli/vio/vio.h +++ b/src/libmowgli/vio/vio.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Elizabeth J. Myers. All rights reserved. + * Copyright (c) 2012 Elizabeth J. Myers. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -22,19 +22,25 @@ /* Types and structs */ typedef struct _mowgli_vio mowgli_vio_t; -typedef enum { - MOWGLI_VIO_ERR_NONE, - MOWGLI_VIO_ERR_REMOTE_HANGUP, - MOWGLI_VIO_ERR_ERRCODE, - MOWGLI_VIO_ERR_API, - MOWGLI_VIO_ERR_CUSTOM, +/* Error type */ +typedef enum +{ + MOWGLI_VIO_ERR_NONE = 0,/* Wat, no error. */ + MOWGLI_VIO_ERR_REMOTE_HANGUP, /* Remote end hung up on us, how rude */ + MOWGLI_VIO_ERR_ERRCODE, /* An errno error or something like that */ + MOWGLI_VIO_ERR_API, /* Programmer was a dumbass */ + MOWGLI_VIO_ERR_CUSTOM, /* Use this for custom errors */ } mowgli_vio_error_type_t; -typedef enum { - MOWGLI_VIO_ERR_OP_NONE, +/* Errors with specific functions correspondng to the VIO op it's named + * after */ +typedef enum +{ + MOWGLI_VIO_ERR_OP_NONE = 0, /* Wat. */ MOWGLI_VIO_ERR_OP_SOCKET, MOWGLI_VIO_ERR_OP_LISTEN, MOWGLI_VIO_ERR_OP_ACCEPT, + MOWGLI_VIO_ERR_OP_REUSEADDR, MOWGLI_VIO_ERR_OP_CONNECT, MOWGLI_VIO_ERR_OP_READ, MOWGLI_VIO_ERR_OP_WRITE, @@ -44,41 +50,59 @@ typedef enum { MOWGLI_VIO_ERR_OP_OTHER, } mowgli_vio_error_op_t; -typedef struct _mowgli_vio_error { +typedef struct _mowgli_vio_error +{ mowgli_vio_error_op_t op; mowgli_vio_error_type_t type; - int code; - char string[128]; + unsigned long code; /* Unsigned long for OpenSSL fuckery */ + char string[128]; /* Friendly name for error */ } mowgli_vio_error_t; -typedef struct _mowgli_vio_sockaddr { +/* Custom sockaddr member to have a uniform sockaddr as opposed to the + * bullshit in the Berkeley sockets API with struct sockaddr/struct + * sockaddr_storage/struct sockaddr_in/struct sockaddr_in6 and associated + * API inconsistency and braindamage + */ +typedef struct _mowgli_vio_sockaddr +{ struct sockaddr_storage addr; + socklen_t addrlen; } mowgli_vio_sockaddr_t; -typedef struct _mowgli_vio_sockdata { - char host[39]; /* max length of IPv6 address */ +#ifndef INET6_ADDRSTRLEN +# define INET6_ADDRSTRLEN 46 /* Good enough I tell you */ +#endif + +/* Socket data */ +typedef struct _mowgli_vio_sockdata +{ + char host[INET6_ADDRSTRLEN]; /* max length of IPv6 address */ uint16_t port; } mowgli_vio_sockdata_t; -typedef int mowgli_vio_func_t(mowgli_vio_t *); -typedef int mowgli_vio_bind_connect_func_t(mowgli_vio_t *, mowgli_vio_sockaddr_t *); -typedef int mowgli_vio_read_func_t(mowgli_vio_t *, void *, size_t); -typedef int mowgli_vio_write_func_t(mowgli_vio_t *, const void *, size_t); -typedef int mowgli_vio_sendto_func_t(mowgli_vio_t *, const void *, size_t, mowgli_vio_sockaddr_t *); -typedef int mowgli_vio_recvfrom_func_t(mowgli_vio_t *, void *, size_t, mowgli_vio_sockaddr_t *); -typedef int mowgli_vio_connect_func_t(mowgli_vio_t *); -typedef int mowgli_vio_accept_func_t(mowgli_vio_t *, mowgli_vio_t *); -typedef int mowgli_vio_listen_func_t(mowgli_vio_t *, int); -typedef int mowgli_vio_socket_func_t(mowgli_vio_t *, int, int, int); -typedef int mowgli_vio_seek_func_t(mowgli_vio_t *, long, int); - -typedef struct { +/* Various typedefs bleh */ +typedef int mowgli_vio_func_t (mowgli_vio_t *); +typedef int mowgli_vio_bind_connect_func_t (mowgli_vio_t *, mowgli_vio_sockaddr_t *); +typedef int mowgli_vio_read_func_t (mowgli_vio_t *, void *, size_t); +typedef int mowgli_vio_write_func_t (mowgli_vio_t *, const void *, size_t); +typedef int mowgli_vio_sendto_func_t (mowgli_vio_t *, const void *, size_t, mowgli_vio_sockaddr_t *); +typedef int mowgli_vio_recvfrom_func_t (mowgli_vio_t *, void *, size_t, mowgli_vio_sockaddr_t *); +typedef int mowgli_vio_connect_func_t (mowgli_vio_t *); +typedef int mowgli_vio_accept_func_t (mowgli_vio_t *, mowgli_vio_t *); +typedef int mowgli_vio_listen_func_t (mowgli_vio_t *, int); +typedef int mowgli_vio_socket_func_t (mowgli_vio_t *, int, int, int); +typedef int mowgli_vio_seek_func_t (mowgli_vio_t *, long, int); + +/* These are workalikes vis-a-vis the Berkeley sockets API */ +typedef struct +{ mowgli_vio_socket_func_t *socket; mowgli_vio_bind_connect_func_t *bind; mowgli_vio_bind_connect_func_t *connect; mowgli_vio_listen_func_t *listen; mowgli_vio_accept_func_t *accept; + mowgli_vio_func_t *reuseaddr; mowgli_vio_read_func_t *read; mowgli_vio_write_func_t *write; mowgli_vio_sendto_func_t *sendto; @@ -89,61 +113,89 @@ typedef struct { mowgli_vio_func_t *tell; } mowgli_vio_ops_t; -struct _mowgli_vio { - mowgli_vio_ops_t ops; - - mowgli_eventloop_io_t *io; - mowgli_descriptor_t fd; +/* Callbacks for eventloop stuff */ +typedef struct +{ + mowgli_eventloop_io_cb_t *read_cb; + mowgli_eventloop_io_cb_t *write_cb; +} mowgli_vio_evops_t; +struct _mowgli_vio +{ + mowgli_vio_ops_t *ops; /* VIO operations */ + mowgli_vio_evops_t *evops; /* Eventloop operations */ + + /* eventloop IO object or descriptor + * If the eventloop member is non-null use io + * else use fd + */ + union + { + mowgli_eventloop_io_t *e; + mowgli_descriptor_t fd; + } io; + + /* Eventloop object we're attached to */ mowgli_eventloop_t *eventloop; + /* struct sockaddr portable workalike -- usage is + * context specific. + * + * For accept()'ed VIO objects, this is the client's + * struct sockaddr stuff, for connect()'ed objects it + * is the remote end's sockaddr (even with previous call + * to bind, for bind()'ed objects it is the sockaddr passed + * to bind + */ mowgli_vio_sockaddr_t addr; - mowgli_vio_error_t error; + mowgli_vio_error_t error; /* Error information lives here */ - int flags; + unsigned int flags; /* Connection flags */ - void *userdata; - void *privdata; + void *userdata; /* User data for VIO object */ + void *privdata; /* Private data for stuff like SSL */ }; -typedef struct _mowgli_vio_ssl_settings { - char cert_path[FILENAME_MAX]; - char privatekey_path[FILENAME_MAX]; +/* SSL settings... members subject to change */ +typedef struct _mowgli_vio_ssl_settings +{ + const char *cert_path; + const char *privatekey_path; int ssl_version; int (*password_func)(char *, int, int, void *); int (*verify_func)(int, void *); } mowgli_vio_ssl_settings_t; - /* Flags */ -#define MOWGLI_VIO_FLAGS_ISCONNECTING 0x00001 -#define MOWGLI_VIO_FLAGS_ISSSLCONNECTING 0x00002 -#define MOWGLI_VIO_FLAGS_ISCLOSED 0x00004 +#define MOWGLI_VIO_FLAGS_ISCONNECTING 0x00001 +#define MOWGLI_VIO_FLAGS_ISSSLCONNECTING 0x00002 +#define MOWGLI_VIO_FLAGS_ISCLOSED 0x00004 -#define MOWGLI_VIO_FLAGS_ISCLIENT 0x00008 -#define MOWGLI_VIO_FLAGS_ISSERVER 0x00010 +#define MOWGLI_VIO_FLAGS_ISCLIENT 0x00008 +#define MOWGLI_VIO_FLAGS_ISSERVER 0x00010 -#define MOWGLI_VIO_FLAGS_ISONHEAP 0x00020 +#define MOWGLI_VIO_FLAGS_ISONHEAP 0x00020 -#define MOWGLI_VIO_FLAGS_NEEDREAD 0x00040 -#define MOWGLI_VIO_FLAGS_NEEDWRITE 0x00080 +#define MOWGLI_VIO_FLAGS_NEEDREAD 0x00040 +#define MOWGLI_VIO_FLAGS_NEEDWRITE 0x00080 /* SSL flags */ -#define MOWGLI_VIO_SSLFLAGS_SSLV2 0x00001 -#define MOWGLI_VIO_SSLFLAGS_SSLV3 0x00002 -#define MOWGLI_VIO_SSLFLAGS_TLSV10 0x00004 -#define MOWGLI_VIO_SSLFLAGS_TLSV11 0x00008 -#define MOWGLI_VIO_SSLFLAGS_TLSV12 0x00010 - +#define MOWGLI_VIO_SSLFLAGS_SSLV2 0x00001 +#define MOWGLI_VIO_SSLFLAGS_SSLV3 0x00002 +#define MOWGLI_VIO_SSLFLAGS_TLSV10 0x00004 +#define MOWGLI_VIO_SSLFLAGS_TLSV11 0x00008 +#define MOWGLI_VIO_SSLFLAGS_TLSV12 0x00010 /* Flag setting/getting */ -static inline bool mowgli_vio_hasflag(mowgli_vio_t *vio, int flag) +static inline bool +mowgli_vio_hasflag(mowgli_vio_t *vio, int flag) { return (vio->flags & flag) != 0 ? true : false; } -static inline void mowgli_vio_setflag(mowgli_vio_t *vio, int flag, bool setting) +static inline void +mowgli_vio_setflag(mowgli_vio_t *vio, int flag, bool setting) { if (setting) vio->flags |= flag; @@ -151,32 +203,68 @@ static inline void mowgli_vio_setflag(mowgli_vio_t *vio, int flag, bool setting) vio->flags &= ~flag; } +/* Get file descriptor */ +static inline mowgli_descriptor_t +mowgli_vio_getfd(mowgli_vio_t *vio) +{ + return_val_if_fail(vio, -1); + + if (vio->eventloop) + { + mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(vio->io.e); + + if (pollable) + return pollable->fd; + } + + return vio->io.fd; +} /* Macros */ -#define MOWGLI_VIO_SET_CLOSED(v) \ - mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_ISCONNECTING, false); \ - mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_ISCLOSED, true); \ +#define MOWGLI_VIO_SET_CLOSED(v) \ + mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_ISCONNECTING, false); \ + mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_ISCLOSED, true); \ mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_ISSSLCONNECTING, false); \ - mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_NEEDREAD, false); \ - mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_NEEDWRITE, false); + mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_NEEDREAD, false); \ + mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_NEEDWRITE, false) +#define MOWGLI_VIO_IS_CLOSED(v) mowgli_vio_hasflag(v, MOWGLI_VIO_FLAGS_ISCLOSED) + +#define MOWGLI_VIO_SETREAD(vio) \ + if (vio->eventloop && vio->io.e && vio->evops && vio->evops->read_cb) \ + { \ + mowgli_pollable_setselect(vio->eventloop, vio->io.e, MOWGLI_EVENTLOOP_IO_READ, vio->evops->read_cb); \ + } + +#define MOWGLI_VIO_SETWRITE(vio) \ + if (vio->eventloop && vio->io.e && vio->evops && vio->evops->write_cb) \ + { \ + mowgli_pollable_setselect(vio->eventloop, vio->io.e, MOWGLI_EVENTLOOP_IO_WRITE, vio->evops->write_cb); \ + } + +#define MOWGLI_VIO_UNSETWRITE(vio) \ + if (vio->eventloop && vio->io.e) \ + { \ + mowgli_pollable_setselect(vio->eventloop, vio->io.e, MOWGLI_EVENTLOOP_IO_WRITE, NULL); \ + } /* Decls */ -extern mowgli_vio_t * mowgli_vio_create(void *userdata); +extern mowgli_vio_t *mowgli_vio_create(void *userdata); extern void mowgli_vio_init(mowgli_vio_t *vio, void *userdata); extern void mowgli_vio_destroy(mowgli_vio_t *vio); -extern void mowgli_vio_eventloop_attach(mowgli_vio_t *vio, mowgli_eventloop_t *eventloop); +extern void mowgli_vio_eventloop_attach(mowgli_vio_t *vio, mowgli_eventloop_t *eventloop, mowgli_vio_evops_t *evops); extern void mowgli_vio_eventloop_detach(mowgli_vio_t *vio); -extern mowgli_vio_sockaddr_t * mowgli_vio_sockaddr_create(mowgli_vio_sockaddr_t *naddr, int proto, const char *addr, int port); -extern mowgli_vio_sockaddr_t * mowgli_vio_sockaddr_from_struct(mowgli_vio_sockaddr_t *naddr, const void *addr, socklen_t size); +extern mowgli_vio_sockaddr_t *mowgli_vio_sockaddr_create(mowgli_vio_sockaddr_t *naddr, int proto, const char *addr, int port); +extern mowgli_vio_sockaddr_t *mowgli_vio_sockaddr_from_struct(mowgli_vio_sockaddr_t *naddr, const void *addr, socklen_t size); extern int mowgli_vio_sockaddr_info(const mowgli_vio_sockaddr_t *addr, mowgli_vio_sockdata_t *data); extern int mowgli_vio_default_socket(mowgli_vio_t *vio, int family, int type, int proto); extern int mowgli_vio_default_bind(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr); extern int mowgli_vio_default_listen(mowgli_vio_t *vio, int backlog); extern int mowgli_vio_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio); +extern int mowgli_vio_default_reuseaddr(mowgli_vio_t *vio); extern int mowgli_vio_default_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr); extern int mowgli_vio_default_read(mowgli_vio_t *vio, void *buffer, size_t len); extern int mowgli_vio_default_write(mowgli_vio_t *vio, const void *buffer, size_t len); @@ -188,32 +276,55 @@ extern int mowgli_vio_default_seek(mowgli_vio_t *vio, long offset, int whence); extern int mowgli_vio_default_tell(mowgli_vio_t *vio); extern int mowgli_vio_err_errcode(mowgli_vio_t *vio, char *(*int_to_error)(int), int errcode); -extern int mowgli_vio_err_sslerrcode(mowgli_vio_t *vio, int errcode); +extern int mowgli_vio_err_sslerrcode(mowgli_vio_t *vio, unsigned long int errcode); + +extern int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings, mowgli_vio_ops_t *ops); -extern int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings); /* These are void ptr's so they can be null ops if SSL isn't available */ -extern void * mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio); -extern void * mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio); +extern void *mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio); +extern void *mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio); + +#ifdef HAVE_OPENSSL +extern int mowgli_vio_openssl_default_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr); +extern int mowgli_vio_openssl_default_listen(mowgli_vio_t *vio, int backlog); +extern int mowgli_vio_openssl_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio); +extern int mowgli_vio_openssl_default_read(mowgli_vio_t *vio, void *buffer, size_t len); +extern int mowgli_vio_openssl_default_write(mowgli_vio_t *vio, const void *buffer, size_t len); +extern int mowgli_vio_openssl_default_close(mowgli_vio_t *vio); + +#else +# define NOSSLSUPPORT { mowgli_log("Attempting to use default OpenSSL op with no SSL support; this will not work!"); return -255; } +static inline int mowgli_vio_openssl_default_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) NOSSLSUPPORT +static inline int mowgli_vio_openssl_default_listen(mowgli_vio_t *vio, int backlog) NOSSLSUPPORT +static inline int mowgli_vio_openssl_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) NOSSLSUPPORT +static inline int mowgli_vio_openssl_default_read(mowgli_vio_t *vio, void *buffer, size_t len) NOSSLSUPPORT +static inline int mowgli_vio_openssl_default_write(mowgli_vio_t *vio, const void *buffer, size_t len) NOSSLSUPPORT +static inline int mowgli_vio_openssl_default_close(mowgli_vio_t *vio) NOSSLSUPPORT +#endif +/* Default ops -- change these if you want something besides the default */ extern mowgli_vio_ops_t mowgli_vio_default_ops; +/* Default evops -- they do nothing unless you change them */ +extern mowgli_vio_evops_t mowgli_vio_default_evops; /* Sundry operations on vio functables */ -#define mowgli_vio_set_op(vio, op, func) vio->ops.op = func; - -#define mowgli_vio_socket(vio, ...) vio->ops.socket(vio, __VA_ARGS__) -#define mowgli_vio_listen(vio, ...) vio->ops.listen(vio, __VA_ARGS__) -#define mowgli_vio_bind(vio, ...) vio->ops.bind(vio, __VA_ARGS__) -#define mowgli_vio_accept(vio, ...) vio->ops.accept(vio, __VA_ARGS__) -#define mowgli_vio_connect(vio, ...) vio->ops.connect(vio, __VA_ARGS__) -#define mowgli_vio_read(vio, ...) vio->ops.read(vio, __VA_ARGS__) -#define mowgli_vio_write(vio, ...) vio->ops.write(vio, __VA_ARGS__) -#define mowgli_vio_sendto(vio, ...) vio->ops.sendto(vio, __VA_ARGS__) -#define mowgli_vio_recvfrom(vio, ...) vio->ops.recvfrom(vio, __VA_ARGS__) -#define mowgli_vio_error(vio) vio->ops.error(vio); -#define mowgli_vio_close(vio) vio->ops.close(vio); -#define mowgli_vio_seek(vio, ...) vio->ops.seek(vio, __VA_ARGS__) -#define mowgli_vio_tell(vio) vio->ops.tell(vio) +#define mowgli_vio_ops_set_op(ops, op, func) ops->op = func + +/* Wrappers for the VIO ops */ +#define mowgli_vio_socket(vio, ...) vio->ops->socket(vio, __VA_ARGS__) +#define mowgli_vio_listen(vio, ...) vio->ops->listen(vio, __VA_ARGS__) +#define mowgli_vio_bind(vio, ...) vio->ops->bind(vio, __VA_ARGS__) +#define mowgli_vio_accept(vio, ...) vio->ops->accept(vio, __VA_ARGS__) +#define mowgli_vio_reuseaddr(vio) vio->ops->reuseaddr(vio) +#define mowgli_vio_connect(vio, ...) vio->ops->connect(vio, __VA_ARGS__) +#define mowgli_vio_read(vio, ...) vio->ops->read(vio, __VA_ARGS__) +#define mowgli_vio_write(vio, ...) vio->ops->write(vio, __VA_ARGS__) +#define mowgli_vio_sendto(vio, ...) vio->ops->sendto(vio, __VA_ARGS__) +#define mowgli_vio_recvfrom(vio, ...) vio->ops->recvfrom(vio, __VA_ARGS__) +#define mowgli_vio_error(vio) vio->ops->error(vio) +#define mowgli_vio_close(vio) vio->ops->close(vio) +#define mowgli_vio_seek(vio, ...) vio->ops->seek(vio, __VA_ARGS__) +#define mowgli_vio_tell(vio) vio->ops->tell(vio) #endif - diff --git a/src/libmowgli/vio/vio_openssl.c b/src/libmowgli/vio/vio_openssl.c index 75c83e4..d492c9f 100644 --- a/src/libmowgli/vio/vio_openssl.c +++ b/src/libmowgli/vio/vio_openssl.c @@ -30,28 +30,28 @@ #ifdef HAVE_OPENSSL -typedef struct { +typedef struct +{ SSL *ssl_handle; SSL_CTX *ssl_context; mowgli_vio_ssl_settings_t settings; } mowgli_ssl_connection_t; -static int mowgli_vio_openssl_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr); -static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog); -static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio); static int mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_connection_t *connection); -static int mowgli_vio_openssl_read(mowgli_vio_t *vio, void *buffer, size_t len); -static int mowgli_vio_openssl_write(mowgli_vio_t *vio, const void *buffer, size_t len); static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *readbuf, const void *writebuf, size_t len); -static int mowgli_vio_openssl_close(mowgli_vio_t *vio); static mowgli_heap_t *ssl_heap = NULL; static bool openssl_init = false; -int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings) +static mowgli_vio_ops_t *openssl_ops = NULL; + +int +mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings, mowgli_vio_ops_t *ops) { - mowgli_ssl_connection_t *connection; + mowgli_ssl_connection_t *connection; + + return_val_if_fail(vio, -255); if (!ssl_heap) ssl_heap = mowgli_heap_create(sizeof(mowgli_ssl_connection_t), 64, BH_NOW); @@ -65,13 +65,28 @@ int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *sett /* Greatest compat without being terribly insecure */ connection->settings.ssl_version = MOWGLI_VIO_SSLFLAGS_SSLV3; + if (ops == NULL) + { + if (!openssl_ops) + { + openssl_ops = mowgli_alloc(sizeof(mowgli_vio_ops_t)); + memcpy(openssl_ops, &mowgli_vio_default_ops, sizeof(mowgli_vio_ops_t)); + } + + vio->ops = openssl_ops; + } + else + { + vio->ops = ops; + } + /* Change ops */ - mowgli_vio_set_op(vio, connect, mowgli_vio_openssl_connect); - mowgli_vio_set_op(vio, read, mowgli_vio_openssl_read); - mowgli_vio_set_op(vio, write, mowgli_vio_openssl_write); - mowgli_vio_set_op(vio, close, mowgli_vio_openssl_close); - mowgli_vio_set_op(vio, accept, mowgli_vio_openssl_accept); - mowgli_vio_set_op(vio, listen, mowgli_vio_openssl_listen); + mowgli_vio_ops_set_op(vio->ops, connect, mowgli_vio_openssl_default_connect); + mowgli_vio_ops_set_op(vio->ops, read, mowgli_vio_openssl_default_read); + mowgli_vio_ops_set_op(vio->ops, write, mowgli_vio_openssl_default_write); + mowgli_vio_ops_set_op(vio->ops, close, mowgli_vio_openssl_default_close); + mowgli_vio_ops_set_op(vio->ops, accept, mowgli_vio_openssl_default_accept); + mowgli_vio_ops_set_op(vio->ops, listen, mowgli_vio_openssl_default_listen); /* SSL setup */ if (!openssl_init) @@ -87,27 +102,39 @@ int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *sett } /* Returns void so they can be stubs */ -void * mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio) +void * +mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio) { + return_val_if_fail(vio, NULL); mowgli_ssl_connection_t *connection = vio->privdata; return connection->ssl_handle; } -void * mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio) +void * +mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio) { + return_val_if_fail(vio, NULL); mowgli_ssl_connection_t *connection = vio->privdata; return connection->ssl_context; } -static int mowgli_vio_openssl_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) +int +mowgli_vio_openssl_default_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) { - vio->error.op = MOWGLI_VIO_ERR_OP_CONNECT; + const int fd = mowgli_vio_getfd(vio); + + return_val_if_fail(fd != -1, -255); + mowgli_ssl_connection_t *connection = vio->privdata; - if (connect(vio->fd, (struct sockaddr *)&addr->addr, addr->addrlen) < 0) + vio->error.op = MOWGLI_VIO_ERR_OP_CONNECT; + + if (connect(fd, (struct sockaddr *) &addr->addr, addr->addrlen) < 0) { if (!mowgli_eventloop_ignore_errno(errno)) + { return mowgli_vio_err_errcode(vio, strerror, errno); + } else { mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, true); @@ -128,11 +155,16 @@ static int mowgli_vio_openssl_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t * return mowgli_vio_openssl_client_handshake(vio, connection); } -static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog) +int +mowgli_vio_openssl_default_listen(mowgli_vio_t *vio, int backlog) { - vio->error.op = MOWGLI_VIO_ERR_OP_LISTEN; + return_val_if_fail(vio, -255); + mowgli_ssl_connection_t *connection = vio->privdata; const SSL_METHOD *method; + const int fd = mowgli_vio_getfd(vio); + + vio->error.op = MOWGLI_VIO_ERR_OP_LISTEN; switch (connection->settings.ssl_version) { @@ -148,21 +180,24 @@ static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog) method = TLSv1_server_method(); break; default: + /* Compat method */ method = SSLv23_server_method(); } - - connection->ssl_context = SSL_CTX_new((SSL_METHOD *)method); + + connection->ssl_context = SSL_CTX_new((SSL_METHOD *) method); + if (connection->ssl_context == NULL) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); connection->ssl_handle = SSL_new(connection->ssl_context); + if (connection->ssl_handle == NULL) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); SSL_set_accept_state(connection->ssl_handle); SSL_CTX_set_options(connection->ssl_context, SSL_OP_SINGLE_DH_USE); - + if (connection->settings.password_func) { SSL_CTX_set_default_passwd_cb(connection->ssl_context, connection->settings.password_func); @@ -175,10 +210,10 @@ static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog) if (SSL_CTX_use_PrivateKey_file(connection->ssl_context, connection->settings.privatekey_path, SSL_FILETYPE_PEM) != 1) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); - if (listen(vio->fd, backlog) != 0) + if (listen(fd, backlog) != 0) return mowgli_vio_err_errcode(vio, strerror, errno); - if (!SSL_set_fd(connection->ssl_handle, vio->fd)) + if (!SSL_set_fd(connection->ssl_handle, fd)) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSERVER, true); @@ -187,10 +222,15 @@ static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog) return 0; } -static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) +int +mowgli_vio_openssl_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) { - int fd; + const int fd = mowgli_vio_getfd(vio); + int afd; int ret; + + return_val_if_fail(fd != -1, -255); + mowgli_ssl_connection_t *connection = vio->privdata; mowgli_ssl_connection_t *newconnection; @@ -204,7 +244,7 @@ static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) return mowgli_vio_error(vio); } - if ((fd = accept(vio->fd, (struct sockaddr *)&newvio->addr.addr, &(newvio->addr.addrlen))) < 0) + if ((afd = accept(fd, (struct sockaddr *) &newvio->addr.addr, &(newvio->addr.addrlen))) < 0) { if (!mowgli_eventloop_ignore_errno(errno)) return mowgli_vio_err_errcode(vio, strerror, errno); @@ -212,14 +252,14 @@ static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) return 0; } - newvio->fd = fd; + newvio->io.fd = afd; - mowgli_vio_openssl_setssl(newvio, &connection->settings); + mowgli_vio_openssl_setssl(newvio, &connection->settings, vio->ops); newconnection = newvio->privdata; newconnection->ssl_context = connection->ssl_context; newconnection->ssl_handle = SSL_new(newconnection->ssl_context); - - if (!SSL_set_fd(newconnection->ssl_handle, fd)) + + if (!SSL_set_fd(newconnection->ssl_handle, afd)) return mowgli_vio_err_sslerrcode(newvio, ERR_get_error()); if ((ret = SSL_accept(newconnection->ssl_handle)) != 1) @@ -230,9 +270,11 @@ static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) { case SSL_ERROR_WANT_READ: mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, true); + MOWGLI_VIO_SETREAD(vio) return 0; case SSL_ERROR_WANT_WRITE: mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + MOWGLI_VIO_SETWRITE(vio) return 0; case SSL_ERROR_ZERO_RETURN: return 0; @@ -243,7 +285,7 @@ static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) break; } - if(err > 0) + if (err > 0) { errno = EIO; return mowgli_vio_err_errcode(vio, strerror, errno); @@ -259,8 +301,10 @@ static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) return 0; } -static int mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_connection_t *connection) +static int +mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_connection_t *connection) { + const int fd = mowgli_vio_getfd(vio); int ret; const SSL_METHOD *method; @@ -280,41 +324,56 @@ static int mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_con method = TLSv1_client_method(); break; default: + /* Compat method */ method = SSLv23_client_method(); } /* Cast is to eliminate an excessively bogus warning on old OpenSSL --Elizacat */ - connection->ssl_context = SSL_CTX_new((SSL_METHOD *)method); + connection->ssl_context = SSL_CTX_new((SSL_METHOD *) method); + if (connection->ssl_context == NULL) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); connection->ssl_handle = SSL_new(connection->ssl_context); + if (connection->ssl_handle == NULL) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); - + SSL_set_connect_state(connection->ssl_handle); - - if (!SSL_set_fd(connection->ssl_handle, vio->fd)) + + if (!SSL_set_fd(connection->ssl_handle, fd)) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); - /* XXX not what we want for blocking sockets if they're in use! */ - SSL_CTX_set_mode(connection->ssl_context, SSL_MODE_ENABLE_PARTIAL_WRITE); + if (vio->eventloop) + SSL_CTX_set_mode(connection->ssl_context, SSL_MODE_ENABLE_PARTIAL_WRITE); if ((ret = SSL_connect(connection->ssl_handle)) != 1) { - int err = SSL_get_error(connection->ssl_handle, ret); + unsigned long err = SSL_get_error(connection->ssl_handle, ret); + if (err == SSL_ERROR_WANT_READ) + { mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, true); + MOWGLI_VIO_SETREAD(vio) + } else if (err == SSL_ERROR_WANT_WRITE) + { mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + MOWGLI_VIO_SETWRITE(vio) + } else if (err == SSL_ERROR_WANT_CONNECT) { mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, true); return 0; } else + { return mowgli_vio_err_sslerrcode(vio, err); + } + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSSLCONNECTING, false); + return 0; } /* Connected */ @@ -324,22 +383,25 @@ static int mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_con return 0; } -#define MOWGLI_VIO_SSL_DOREAD true -#define MOWGLI_VIO_SSL_DOWRITE false +# define MOWGLI_VIO_SSL_DOREAD true +# define MOWGLI_VIO_SSL_DOWRITE false -static int mowgli_vio_openssl_read(mowgli_vio_t *vio, void *buffer, size_t len) +int +mowgli_vio_openssl_default_read(mowgli_vio_t *vio, void *buffer, size_t len) { vio->error.op = MOWGLI_VIO_ERR_OP_READ; return mowgli_openssl_read_or_write(MOWGLI_VIO_SSL_DOREAD, vio, buffer, NULL, len); } -static int mowgli_vio_openssl_write(mowgli_vio_t *vio, const void *buffer, size_t len) +int +mowgli_vio_openssl_default_write(mowgli_vio_t *vio, const void *buffer, size_t len) { vio->error.op = MOWGLI_VIO_ERR_OP_WRITE; return mowgli_openssl_read_or_write(MOWGLI_VIO_SSL_DOWRITE, vio, NULL, buffer, len); } -static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *readbuf, const void *writebuf, size_t len) +static int +mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *readbuf, const void *writebuf, size_t len) { mowgli_ssl_connection_t *connection = vio->privdata; int ret; @@ -353,10 +415,15 @@ static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *read return_val_if_fail(connection->ssl_handle != NULL, -1); - if(read) - ret = (int)SSL_read(connection->ssl_handle, readbuf, len); + if (read) + { + ret = (int) SSL_read(connection->ssl_handle, readbuf, len); + } else - ret = (int)SSL_write(connection->ssl_handle, writebuf, len); + { + ret = (int) SSL_write(connection->ssl_handle, writebuf, len); + MOWGLI_VIO_UNSETWRITE(vio) + } if (ret < 0) { @@ -364,32 +431,34 @@ static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *read { case SSL_ERROR_WANT_READ: mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, true); + MOWGLI_VIO_SETREAD(vio) return 0; case SSL_ERROR_WANT_WRITE: mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + MOWGLI_VIO_SETWRITE(vio) return 0; case SSL_ERROR_ZERO_RETURN: return 0; case SSL_ERROR_SYSCALL: - if((err = ERR_get_error()) == 0) + + if ((err = ERR_get_error()) == 0) { vio->error.type = MOWGLI_VIO_ERR_REMOTE_HANGUP; mowgli_strlcpy(vio->error.string, "Remote host closed the socket", sizeof(vio->error.string)); - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLOSED, true); - + MOWGLI_VIO_SET_CLOSED(vio); + return mowgli_vio_error(vio); } break; - + default: err = ERR_get_error(); break; } - if(err > 0) + if (err > 0) { errno = EIO; return mowgli_vio_err_errcode(vio, strerror, errno); @@ -405,8 +474,10 @@ static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *read return ret; } -static int mowgli_vio_openssl_close(mowgli_vio_t *vio) +int +mowgli_vio_openssl_default_close(mowgli_vio_t *vio) { + const int fd = mowgli_vio_getfd(vio); mowgli_ssl_connection_t *connection = vio->privdata; return_val_if_fail(connection->ssl_handle != NULL, -1); @@ -419,29 +490,32 @@ static int mowgli_vio_openssl_close(mowgli_vio_t *vio) MOWGLI_VIO_SET_CLOSED(vio); - close(vio->fd); + /* FIXME - doesn't verify a proper SSL shutdown! */ + close(fd); return 0; } #else -int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings) +int +mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings, mowgli_vio_ops_t *ops) { mowgli_log("OpenSSL requested on a VIO object, but mowgli was built without OpenSSL support..."); return -1; } -void * mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio) +void * +mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio) { mowgli_log("Cannot get VIO SSL handle as libmowgli was built without OpenSSL support"); return NULL; } -void * mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio) +void * +mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio) { mowgli_log("Cannot get VIO SSL context as libmowgli was built without OpenSSL support"); return NULL; } #endif - diff --git a/src/libmowgli/vio/vio_sockets.c b/src/libmowgli/vio/vio_sockets.c index e36080b..b741113 100644 --- a/src/libmowgli/vio/vio_sockets.c +++ b/src/libmowgli/vio/vio_sockets.c @@ -23,10 +23,13 @@ #include "mowgli.h" -int mowgli_vio_default_socket(mowgli_vio_t *vio, int family, int type, int proto) +int +mowgli_vio_default_socket(mowgli_vio_t *vio, int family, int type, int proto) { int fd; + return_val_if_fail(vio, -255); + vio->error.op = MOWGLI_VIO_ERR_OP_SOCKET; /* We can't call socket with AF_UNSPEC on most platforms >_> */ @@ -36,9 +39,9 @@ int mowgli_vio_default_socket(mowgli_vio_t *vio, int family, int type, int proto if ((fd = socket(family, type, proto)) == -1) return mowgli_vio_err_errcode(vio, strerror, errno); - vio->fd = fd; + vio->io.fd = fd; - if (family == SOCK_STREAM) + if (type == SOCK_STREAM) { mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLOSED, false); @@ -48,11 +51,16 @@ int mowgli_vio_default_socket(mowgli_vio_t *vio, int family, int type, int proto return 0; } -int mowgli_vio_default_bind(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) +int +mowgli_vio_default_bind(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) { + const int fd = mowgli_vio_getfd(vio); + + return_val_if_fail(fd != -1, -255); + vio->error.op = MOWGLI_VIO_ERR_OP_BIND; - if (bind(vio->fd, (struct sockaddr *)&addr->addr, addr->addrlen) != 0) + if (bind(fd, (struct sockaddr *) &addr->addr, addr->addrlen) != 0) return mowgli_vio_err_errcode(vio, strerror, errno); memcpy(&vio->addr.addr, &addr->addr, sizeof(struct sockaddr_storage)); @@ -61,11 +69,16 @@ int mowgli_vio_default_bind(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) return 0; } -int mowgli_vio_default_listen(mowgli_vio_t *vio, int backlog) +int +mowgli_vio_default_listen(mowgli_vio_t *vio, int backlog) { + const int fd = mowgli_vio_getfd(vio); + + return_val_if_fail(fd != -1, -255); + vio->error.op = MOWGLI_VIO_ERR_OP_LISTEN; - if (listen(vio->fd, backlog) < 0) + if (listen(fd, backlog) < 0) return mowgli_vio_err_errcode(vio, strerror, errno); mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSERVER, true); @@ -76,9 +89,13 @@ int mowgli_vio_default_listen(mowgli_vio_t *vio, int backlog) return 0; } -int mowgli_vio_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) +int +mowgli_vio_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) { - int fd; + const int fd = mowgli_vio_getfd(vio); + int afd; + + return_val_if_fail(fd != -1, -255); vio->error.op = MOWGLI_VIO_ERR_OP_ACCEPT; @@ -90,7 +107,7 @@ int mowgli_vio_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) return mowgli_vio_error(vio); } - if ((fd = accept(vio->fd, (struct sockaddr *)&newvio->addr.addr, &(newvio->addr.addrlen))) < 0) + if ((afd = accept(fd, (struct sockaddr *) &newvio->addr.addr, &(newvio->addr.addrlen))) < 0) { if (!mowgli_eventloop_ignore_errno(errno)) return mowgli_vio_err_errcode(vio, strerror, errno); @@ -98,7 +115,7 @@ int mowgli_vio_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) return 0; } - newvio->fd = fd; + newvio->io.fd = afd; /* The new VIO object is most certainly not a server */ mowgli_vio_setflag(newvio, MOWGLI_VIO_FLAGS_ISCLIENT, true); @@ -108,11 +125,33 @@ int mowgli_vio_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) return 0; } -int mowgli_vio_default_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) +int +mowgli_vio_default_reuseaddr(mowgli_vio_t *vio) +{ + int fd = mowgli_vio_getfd(vio); + int reuse = 1; + + return_val_if_fail(fd != -1, -255); + + vio->error.op = MOWGLI_VIO_ERR_OP_REUSEADDR; + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) + return mowgli_vio_err_errcode(vio, strerror, errno); + + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return 0; +} + +int +mowgli_vio_default_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) { + const int fd = mowgli_vio_getfd(vio); + + return_val_if_fail(fd != -1, -255); + vio->error.op = MOWGLI_VIO_ERR_OP_CONNECT; - if (connect(vio->fd, (struct sockaddr *)&addr->addr, addr->addrlen) < 0) + if (connect(fd, (struct sockaddr *) &addr->addr, addr->addrlen) < 0) { if (!mowgli_eventloop_ignore_errno(errno)) return mowgli_vio_err_errcode(vio, strerror, errno); @@ -134,29 +173,31 @@ int mowgli_vio_default_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) return 0; } -int mowgli_vio_default_read(mowgli_vio_t *vio, void *buffer, size_t len) +int +mowgli_vio_default_read(mowgli_vio_t *vio, void *buffer, size_t len) { + const int fd = mowgli_vio_getfd(vio); int ret; + return_val_if_fail(fd != -1, -255); + vio->error.op = MOWGLI_VIO_ERR_OP_READ; mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); - if ((ret = (int)recv(vio->fd, buffer, len, 0)) < 0) + if ((ret = (int) recv(fd, buffer, len, 0)) <= 0) { - if (!mowgli_eventloop_ignore_errno(errno)) - { - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, false); - return mowgli_vio_err_errcode(vio, strerror, errno); - } - else if (errno != 0) + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, false); + + if (ret < 0) { - /* Further reads unnecessary */ - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, false); - return 0; + if (!mowgli_eventloop_ignore_errno(errno)) + return mowgli_vio_err_errcode(vio, strerror, errno); + else if (errno != 0) + /* Further reads unnecessary */ + return 0; } - - if (ret == 0) + else { vio->error.type = MOWGLI_VIO_ERR_REMOTE_HANGUP; mowgli_strlcpy(vio->error.string, "Remote host closed the socket", sizeof(vio->error.string)); @@ -174,94 +215,105 @@ int mowgli_vio_default_read(mowgli_vio_t *vio, void *buffer, size_t len) return ret; } -int mowgli_vio_default_write(mowgli_vio_t *vio, const void *buffer, size_t len) +int +mowgli_vio_default_write(mowgli_vio_t *vio, const void *buffer, size_t len) { + const int fd = mowgli_vio_getfd(vio); int ret; + return_val_if_fail(fd != -1, -255); + vio->error.op = MOWGLI_VIO_ERR_OP_WRITE; mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); - if ((ret = (int)send(vio->fd, buffer, len, 0)) == -1) + if ((ret = (int) send(fd, buffer, len, 0)) == -1) { + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, false); + MOWGLI_VIO_UNSETWRITE(vio) + if (!mowgli_eventloop_ignore_errno(errno)) - { - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, false); return mowgli_vio_err_errcode(vio, strerror, errno); - } else - { /* Further writes unnecessary */ - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, false); return 0; - } } /* Set this for edge-triggered interfaces */ - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + if (ret < (int) len) + { + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + MOWGLI_VIO_SETWRITE(vio) + } vio->error.op = MOWGLI_VIO_ERR_OP_NONE; return ret; } -int mowgli_vio_default_sendto(mowgli_vio_t *vio, const void *buffer, size_t len, mowgli_vio_sockaddr_t *addr) +int +mowgli_vio_default_sendto(mowgli_vio_t *vio, const void *buffer, size_t len, mowgli_vio_sockaddr_t *addr) { + const int fd = mowgli_vio_getfd(vio); int ret; + return_val_if_fail(fd != -1, -255); + vio->error.op = MOWGLI_VIO_ERR_OP_WRITE; mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); - if ((ret = (int)sendto(vio->fd, buffer, len, 0, (struct sockaddr *)&addr->addr, addr->addrlen)) == -1) + if ((ret = (int) sendto(fd, buffer, len, 0, (struct sockaddr *) &addr->addr, addr->addrlen)) == -1) { + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, false); + MOWGLI_VIO_UNSETWRITE(vio) + if (!mowgli_eventloop_ignore_errno(errno)) - { - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, false); return mowgli_vio_err_errcode(vio, strerror, errno); - } else - { /* Further writes unnecessary */ - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, false); return 0; - } } - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + if (ret < (int) len) + { + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + MOWGLI_VIO_SETWRITE(vio) + } vio->error.op = MOWGLI_VIO_ERR_OP_NONE; return ret; } -int mowgli_vio_default_recvfrom(mowgli_vio_t *vio, void *buffer, size_t len, mowgli_vio_sockaddr_t *addr) +int +mowgli_vio_default_recvfrom(mowgli_vio_t *vio, void *buffer, size_t len, mowgli_vio_sockaddr_t *addr) { + const int fd = mowgli_vio_getfd(vio); int ret; + return_val_if_fail(fd != -1, -255); + vio->error.op = MOWGLI_VIO_ERR_OP_READ; mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); - if ((ret = (int)recvfrom(vio->fd, buffer, len, 0, (struct sockaddr *)&addr->addr, &addr->addrlen)) < 0) + if ((ret = (int) recvfrom(fd, buffer, len, 0, (struct sockaddr *) &addr->addr, &addr->addrlen)) < 0) { - if (!mowgli_eventloop_ignore_errno(errno)) - { - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, false); - return mowgli_vio_err_errcode(vio, strerror, errno); - } - else if (errno != 0) + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, false); + + if (ret < 0) { - /* Further reads unnecessary */ - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, false); - return 0; + if (!mowgli_eventloop_ignore_errno(errno)) + return mowgli_vio_err_errcode(vio, strerror, errno); + else if (errno != 0) + /* Further reads unnecessary */ + return 0; } - - if (ret == 0) + else { vio->error.type = MOWGLI_VIO_ERR_REMOTE_HANGUP; mowgli_strlcpy(vio->error.string, "Remote host closed the socket", sizeof(vio->error.string)); - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLOSED, true); + MOWGLI_VIO_SET_CLOSED(vio); return mowgli_vio_error(vio); } @@ -273,7 +325,8 @@ int mowgli_vio_default_recvfrom(mowgli_vio_t *vio, void *buffer, size_t len, mow return ret; } -int mowgli_vio_default_error(mowgli_vio_t *vio) +int +mowgli_vio_default_error(mowgli_vio_t *vio) { const char *errtype; @@ -312,76 +365,90 @@ int mowgli_vio_default_error(mowgli_vio_t *vio) return -1; } -int mowgli_vio_default_close(mowgli_vio_t *vio) +int +mowgli_vio_default_close(mowgli_vio_t *vio) { + const int fd = mowgli_vio_getfd(vio); + + return_val_if_fail(fd != -1, -255); + MOWGLI_VIO_SET_CLOSED(vio); #ifndef _WIN32 - close(vio->fd); + close(fd); #else - closesocket(vio->fd); + closesocket(fd); #endif return 0; } -int mowgli_vio_default_seek(mowgli_vio_t *vio, long offset, int whence) +int +mowgli_vio_default_seek(mowgli_vio_t *vio, long offset, int whence) { + return_val_if_fail(vio, -255); vio->error.op = MOWGLI_VIO_ERR_OP_SEEK; errno = ENOSYS; return mowgli_vio_err_errcode(vio, strerror, errno); } -int mowgli_vio_default_tell(mowgli_vio_t *vio) +int +mowgli_vio_default_tell(mowgli_vio_t *vio) { + return_val_if_fail(vio, -255); vio->error.op = MOWGLI_VIO_ERR_OP_TELL; errno = ENOSYS; return mowgli_vio_err_errcode(vio, strerror, errno); } /* Generate a mowgli_sockaddr_t struct */ -mowgli_vio_sockaddr_t * mowgli_vio_sockaddr_create(mowgli_vio_sockaddr_t *naddr, int proto, const char *addr, int port) +mowgli_vio_sockaddr_t * +mowgli_vio_sockaddr_create(mowgli_vio_sockaddr_t *naddr, int proto, const char *addr, int port) { struct sockaddr_storage saddr; + return_val_if_fail(naddr, NULL); + return_val_if_fail(addr, NULL); + if (naddr == NULL) naddr = mowgli_alloc(sizeof(mowgli_vio_sockaddr_t)); if (proto == AF_INET) { - struct sockaddr_in *addr_in = (struct sockaddr_in *)&saddr; + struct sockaddr_in *addr_in = (struct sockaddr_in *) &saddr; addr_in->sin_family = proto; addr_in->sin_port = htons(port); + if (addr != NULL) - { if (inet_pton(proto, addr, &addr_in->sin_addr) != 1) mowgli_log("Error with inet_pton!"); - } memcpy(&naddr->addr, &saddr, sizeof(struct sockaddr_in)); naddr->addrlen = sizeof(struct sockaddr_in); } else if (proto == AF_INET6) { - struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&saddr; + struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *) &saddr; addr_in6->sin6_family = proto; addr_in6->sin6_port = htons(port); + if (addr != NULL) - { if (inet_pton(proto, addr, &addr_in6->sin6_addr) != 1) mowgli_log("Error with inet_pton!"); - } memcpy(&naddr->addr, &saddr, sizeof(struct sockaddr_in6)); naddr->addrlen = sizeof(struct sockaddr_in6); } else + { naddr = NULL; + } return naddr; } -mowgli_vio_sockaddr_t * mowgli_vio_sockaddr_from_struct(mowgli_vio_sockaddr_t *naddr, const void *addr, socklen_t size) +mowgli_vio_sockaddr_t * +mowgli_vio_sockaddr_from_struct(mowgli_vio_sockaddr_t *naddr, const void *addr, socklen_t size) { const struct sockaddr_storage *saddr = addr; @@ -390,31 +457,39 @@ mowgli_vio_sockaddr_t * mowgli_vio_sockaddr_from_struct(mowgli_vio_sockaddr_t *n if (naddr == NULL) naddr = mowgli_alloc(sizeof(mowgli_vio_sockaddr_t)); + memcpy(&naddr->addr, saddr, size); naddr->addrlen = size; return naddr; } -int mowgli_vio_sockaddr_info(const mowgli_vio_sockaddr_t *addr, mowgli_vio_sockdata_t *data) +int +mowgli_vio_sockaddr_info(const mowgli_vio_sockaddr_t *addr, mowgli_vio_sockdata_t *data) { const void *sockptr; - const struct sockaddr *saddr = (const struct sockaddr *)&addr->addr; + + return_val_if_fail(addr, -255); + return_val_if_fail(data, -255); + + const struct sockaddr *saddr = (const struct sockaddr *) &addr->addr; if (saddr->sa_family == AF_INET) { - const struct sockaddr_in *saddr = (const struct sockaddr_in *)&addr->addr; + const struct sockaddr_in *saddr = (const struct sockaddr_in *) &addr->addr; data->port = ntohs(saddr->sin_port); sockptr = &saddr->sin_addr; } else if (saddr->sa_family == AF_INET6) { - const struct sockaddr_in6 *saddr = (const struct sockaddr_in6 *)&addr->addr; + const struct sockaddr_in6 *saddr = (const struct sockaddr_in6 *) &addr->addr; data->port = ntohs(saddr->sin6_port); sockptr = &saddr->sin6_addr; } else + { return -1; + } if (inet_ntop(saddr->sa_family, sockptr, data->host, sizeof(data->host)) == NULL) return -1; diff --git a/uncrustify.cfg b/uncrustify.cfg new file mode 100644 index 0000000..74b1d3c --- /dev/null +++ b/uncrustify.cfg @@ -0,0 +1,1578 @@ +# Uncrustify 0.60 + +# +# General options +# + +# The type of line endings +newlines = lf # auto/lf/crlf/cr + +# The original size of tabs in the input +input_tab_size = 8 # number + +# The size of tabs in the output (only used if align_with_tabs=true) +output_tab_size = 8 # number + +# The ASCII value of the string escape char, usually 92 (\) or 94 (^). (Pawn) +string_escape_char = 92 # number + +# Alternate string escape char for Pawn. Only works right before the quote char. +string_escape_char2 = 0 # number + +# Allow interpreting '>=' and '>>=' as part of a template in 'void f(list>=val);'. +# If true (default), 'assert(x<0 && y>=3)' will be broken. +# Improvements to template detection may make this option obsolete. +tok_split_gte = false # false/true + +# Control what to do with the UTF-8 BOM (recommend 'remove') +utf8_bom = remove # ignore/add/remove/force + +# If the file contains bytes with values between 128 and 255, but is not UTF-8, then output as UTF-8 +utf8_byte = true # false/true + +# Force the output encoding to UTF-8 +utf8_force = false # false/true + +# +# Indenting +# + +# The number of columns to indent per level.\Uffffffff +# Usually 2, 3, 4, or 8. +indent_columns = 8 # number + +# The continuation indent. If non-zero, this overrides the indent of '(' and '=' continuation indents. +# For FreeBSD, this is set to 4. Negative value is absolute and not increased for each ( level +indent_continue = 0 # number + +# How to use tabs when indenting code +# 0=spaces only +# 1=indent with tabs to brace level, align with spaces +# 2=indent and align with tabs, using spaces when not on a tabstop +indent_with_tabs = 2 # number + +# Comments that are not a brace level are indented with tabs on a tabstop. +# Requires indent_with_tabs=2. If false, will use spaces. +indent_cmt_with_tabs = true # false/true + +# Whether to indent strings broken by '\' so that they line up +indent_align_string = false # false/true + +# The number of spaces to indent multi-line XML strings. +# Requires indent_align_string=True +indent_xml_string = 0 # number + +# Spaces to indent '{' from level +indent_brace = 0 # number + +# Whether braces are indented to the body level +indent_braces = false # false/true + +# Disabled indenting function braces if indent_braces is true +indent_braces_no_func = false # false/true + +# Disabled indenting class braces if indent_braces is true +indent_braces_no_class = false # false/true + +# Disabled indenting struct braces if indent_braces is true +indent_braces_no_struct = false # false/true + +# Indent based on the size of the brace parent, i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. +indent_brace_parent = false # false/true + +# Whether the 'namespace' body is indented +indent_namespace = false # false/true + +# The number of spaces to indent a namespace block +indent_namespace_level = 0 # number + +# If the body of the namespace is longer than this number, it won't be indented. +# Requires indent_namespace=true. Default=0 (no limit) +indent_namespace_limit = 0 # number + +# Whether the 'extern "C"' body is indented +indent_extern = false # false/true + +# Whether the 'class' body is indented +indent_class = false # false/true + +# Whether to indent the stuff after a leading class colon +indent_class_colon = false # false/true + +# Virtual indent from the ':' for member initializers. Default is 2 +indent_ctor_init_leading = 2 # number + +# Additional indenting for constructor initializer list +indent_ctor_init = 0 # number + +# False=treat 'else\nif' as 'else if' for indenting purposes +# True=indent the 'if' one level +indent_else_if = false # false/true + +# Amount to indent variable declarations after a open brace. neg=relative, pos=absolute +indent_var_def_blk = 0 # number + +# Indent continued variable declarations instead of aligning. +indent_var_def_cont = false # false/true + +# True: force indentation of function definition to start in column 1 +# False: use the default behavior +indent_func_def_force_col1 = false # false/true + +# True: indent continued function call parameters one indent level +# False: align parameters under the open paren +indent_func_call_param = false # false/true + +# Same as indent_func_call_param, but for function defs +indent_func_def_param = false # false/true + +# Same as indent_func_call_param, but for function protos +indent_func_proto_param = false # false/true + +# Same as indent_func_call_param, but for class declarations +indent_func_class_param = false # false/true + +# Same as indent_func_call_param, but for class variable constructors +indent_func_ctor_var_param = false # false/true + +# Same as indent_func_call_param, but for templates +indent_template_param = false # false/true + +# Double the indent for indent_func_xxx_param options +indent_func_param_double = false # false/true + +# Indentation column for standalone 'const' function decl/proto qualifier +indent_func_const = 0 # number + +# Indentation column for standalone 'throw' function decl/proto qualifier +indent_func_throw = 0 # number + +# The number of spaces to indent a continued '->' or '.' +# Usually set to 0, 1, or indent_columns. +indent_member = 0 # number + +# Spaces to indent single line ('//') comments on lines before code +indent_sing_line_comments = 0 # number + +# If set, will indent trailing single line ('//') comments relative +# to the code instead of trying to keep the same absolute column +indent_relative_single_line_comments = false # false/true + +# Spaces to indent 'case' from 'switch' +# Usually 0 or indent_columns. +indent_switch_case = 0 # number + +# Spaces to shift the 'case' line, without affecting any other lines +# Usually 0. +indent_case_shift = 0 # number + +# Spaces to indent '{' from 'case'. +# By default, the brace will appear under the 'c' in case. +# Usually set to 0 or indent_columns. +indent_case_brace = 0 # number + +# Whether to indent comments found in first column +indent_col1_comment = false # false/true + +# How to indent goto labels +# >0 : absolute column where 1 is the leftmost column +# <=0 : subtract from brace indent +indent_label = 1 # number + +# Same as indent_label, but for access specifiers that are followed by a colon +indent_access_spec = 1 # number + +# Indent the code after an access specifier by one level. +# If set, this option forces 'indent_access_spec=0' +indent_access_spec_body = false # false/true + +# If an open paren is followed by a newline, indent the next line so that it lines up after the open paren (not recommended) +indent_paren_nl = false # false/true + +# Controls the indent of a close paren after a newline. +# 0: Indent to body level +# 1: Align under the open paren +# 2: Indent to the brace level +indent_paren_close = 0 # number + +# Controls the indent of a comma when inside a paren.If TRUE, aligns under the open paren +indent_comma_paren = false # false/true + +# Controls the indent of a BOOL operator when inside a paren.If TRUE, aligns under the open paren +indent_bool_paren = false # false/true + +# If 'indent_bool_paren' is true, controls the indent of the first expression. If TRUE, aligns the first expression to the following ones +indent_first_bool_expr = false # false/true + +# If an open square is followed by a newline, indent the next line so that it lines up after the open square (not recommended) +indent_square_nl = false # false/true + +# Don't change the relative indent of ESQL/C 'EXEC SQL' bodies +indent_preserve_sql = false # false/true + +# Align continued statements at the '='. Default=True +# If FALSE or the '=' is followed by a newline, the next line is indent one tab. +indent_align_assign = true # false/true + +# Indent OC blocks at brace level instead of usual rules. +indent_oc_block = false # false/true + +# Indent OC blocks in a message relative to the parameter name. +# 0=use indent_oc_block rules, 1+=spaces to indent +indent_oc_block_msg = 0 # number + +# Minimum indent for subsequent parameters +indent_oc_msg_colon = 0 # number + +# +# Spacing options +# + +# Add or remove space around arithmetic operator '+', '-', '/', '*', etc +sp_arith = force # ignore/add/remove/force + +# Add or remove space around assignment operator '=', '+=', etc +sp_assign = force # ignore/add/remove/force + +# Add or remove space around '=' in C++11 lambda capture specifications. Overrides sp_assign +sp_cpp_lambda_assign = ignore # ignore/add/remove/force + +# Add or remove space after the capture specification in C++11 lambda. +sp_cpp_lambda_paren = ignore # ignore/add/remove/force + +# Add or remove space around assignment operator '=' in a prototype +sp_assign_default = force # ignore/add/remove/force + +# Add or remove space before assignment operator '=', '+=', etc. Overrides sp_assign. +sp_before_assign = force # ignore/add/remove/force + +# Add or remove space after assignment operator '=', '+=', etc. Overrides sp_assign. +sp_after_assign = force # ignore/add/remove/force + +# Add or remove space around assignment '=' in enum +sp_enum_assign = force # ignore/add/remove/force + +# Add or remove space before assignment '=' in enum. Overrides sp_enum_assign. +sp_enum_before_assign = force # ignore/add/remove/force + +# Add or remove space after assignment '=' in enum. Overrides sp_enum_assign. +sp_enum_after_assign = force # ignore/add/remove/force + +# Add or remove space around preprocessor '##' concatenation operator. Default=Add +sp_pp_concat = remove # ignore/add/remove/force + +# Add or remove space after preprocessor '#' stringify operator. Also affects the '#@' charizing operator. +sp_pp_stringify = remove # ignore/add/remove/force + +# Add or remove space before preprocessor '#' stringify operator as in '#define x(y) L#y'. +sp_before_pp_stringify = remove # ignore/add/remove/force + +# Add or remove space around boolean operators '&&' and '||' +sp_bool = force # ignore/add/remove/force + +# Add or remove space around compare operator '<', '>', '==', etc +sp_compare = force # ignore/add/remove/force + +# Add or remove space inside '(' and ')' +sp_inside_paren = remove # ignore/add/remove/force + +# Add or remove space between nested parens +sp_paren_paren = remove # ignore/add/remove/force + +# Whether to balance spaces inside nested parens +sp_balance_nested_parens = false # false/true + +# Add or remove space between ')' and '{' +sp_paren_brace = force # ignore/add/remove/force + +# Add or remove space before pointer star '*' +sp_before_ptr_star = force # ignore/add/remove/force + +# Add or remove space before pointer star '*' that isn't followed by a variable name +# If set to 'ignore', sp_before_ptr_star is used instead. +sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force + +# Add or remove space between pointer stars '*' +sp_between_ptr_star = remove # ignore/add/remove/force + +# Add or remove space after pointer star '*', if followed by a word. +sp_after_ptr_star = remove # ignore/add/remove/force + +# Add or remove space after a pointer star '*', if followed by a func proto/def. +sp_after_ptr_star_func = remove # ignore/add/remove/force + +# Add or remove space after a pointer star '*', if followed by an open paren (function types). +sp_ptr_star_paren = remove # ignore/add/remove/force + +# Add or remove space before a pointer star '*', if followed by a func proto/def. +sp_before_ptr_star_func = add # ignore/add/remove/force + +# Add or remove space before a reference sign '&' +sp_before_byref = add # ignore/add/remove/force + +# Add or remove space before a reference sign '&' that isn't followed by a variable name +# If set to 'ignore', sp_before_byref is used instead. +sp_before_unnamed_byref = ignore # ignore/add/remove/force + +# Add or remove space after reference sign '&', if followed by a word. +sp_after_byref = remove # ignore/add/remove/force + +# Add or remove space after a reference sign '&', if followed by a func proto/def. +sp_after_byref_func = remove # ignore/add/remove/force + +# Add or remove space before a reference sign '&', if followed by a func proto/def. +sp_before_byref_func = remove # ignore/add/remove/force + +# Add or remove space between type and word. Default=Force +sp_after_type = force # ignore/add/remove/force + +# Add or remove space before the paren in the D constructs 'template Foo(' and 'class Foo('. +sp_before_template_paren = remove # ignore/add/remove/force + +# Add or remove space in 'template <' vs 'template<'. +# If set to ignore, sp_before_angle is used. +sp_template_angle = remove # ignore/add/remove/force + +# Add or remove space before '<>' +sp_before_angle = remove # ignore/add/remove/force + +# Add or remove space inside '<' and '>' +sp_inside_angle = remove # ignore/add/remove/force + +# Add or remove space after '<>' +sp_after_angle = remove # ignore/add/remove/force + +# Add or remove space between '<>' and '(' as found in 'new List();' +sp_angle_paren = remove # ignore/add/remove/force + +# Add or remove space between '<>' and a word as in 'List m;' +sp_angle_word = force # ignore/add/remove/force + +# Add or remove space between '>' and '>' in '>>' (template stuff C++/C# only). Default=Add +sp_angle_shift = force # ignore/add/remove/force + +# Permit removal of the space between '>>' in 'foo >' (C++11 only). Default=False +# sp_angle_shift cannot remove the space without this option. +sp_permit_cpp11_shift = false # false/true + +# Add or remove space before '(' of 'if', 'for', 'switch', and 'while' +sp_before_sparen = force # ignore/add/remove/force + +# Add or remove space inside if-condition '(' and ')' +sp_inside_sparen = remove # ignore/add/remove/force + +# Add or remove space before if-condition ')'. Overrides sp_inside_sparen. +sp_inside_sparen_close = remove # ignore/add/remove/force + +# Add or remove space before if-condition '('. Overrides sp_inside_sparen. +sp_inside_sparen_open = remove # ignore/add/remove/force + +# Add or remove space after ')' of 'if', 'for', 'switch', and 'while' +sp_after_sparen = remove # ignore/add/remove/force + +# Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while' +sp_sparen_brace = force # ignore/add/remove/force + +# Add or remove space between 'invariant' and '(' in the D language. +sp_invariant_paren = remove # ignore/add/remove/force + +# Add or remove space after the ')' in 'invariant (C) c' in the D language. +sp_after_invariant_paren = remove # ignore/add/remove/force + +# Add or remove space before empty statement ';' on 'if', 'for' and 'while' +sp_special_semi = remove # ignore/add/remove/force + +# Add or remove space before ';'. Default=Remove +sp_before_semi = remove # ignore/add/remove/force + +# Add or remove space before ';' in non-empty 'for' statements +sp_before_semi_for = remove # ignore/add/remove/force + +# Add or remove space before a semicolon of an empty part of a for statement. +sp_before_semi_for_empty = ignore # ignore/add/remove/force + +# Add or remove space after ';', except when followed by a comment. Default=Add +sp_after_semi = force # ignore/add/remove/force + +# Add or remove space after ';' in non-empty 'for' statements. Default=Force +sp_after_semi_for = force # ignore/add/remove/force + +# Add or remove space after the final semicolon of an empty part of a for statement: for ( ; ; ). +sp_after_semi_for_empty = remove # ignore/add/remove/force + +# Add or remove space before '[' (except '[]') +sp_before_square = remove # ignore/add/remove/force + +# Add or remove space before '[]' +sp_before_squares = remove # ignore/add/remove/force + +# Add or remove space inside a non-empty '[' and ']' +sp_inside_square = remove # ignore/add/remove/force + +# Add or remove space after ',' +sp_after_comma = force # ignore/add/remove/force + +# Add or remove space before ',' +sp_before_comma = remove # ignore/add/remove/force + +# Add or remove space between an open paren and comma: '(,' vs '( ,' +sp_paren_comma = remove # ignore/add/remove/force + +# Add or remove space before the variadic '...' when preceded by a non-punctuator +sp_before_ellipsis = ignore # ignore/add/remove/force + +# Add or remove space after class ':' +sp_after_class_colon = remove # ignore/add/remove/force + +# Add or remove space before class ':' +sp_before_class_colon = remove # ignore/add/remove/force + +# Add or remove space before case ':'. Default=Remove +sp_before_case_colon = remove # ignore/add/remove/force + +# Add or remove space between 'operator' and operator sign +sp_after_operator = force # ignore/add/remove/force + +# Add or remove space between the operator symbol and the open paren, as in 'operator ++(' +sp_after_operator_sym = remove # ignore/add/remove/force + +# Add or remove space after C/D cast, i.e. 'cast(int)a' vs 'cast(int) a' or '(int)a' vs '(int) a' +sp_after_cast = force # ignore/add/remove/force + +# Add or remove spaces inside cast parens +sp_inside_paren_cast = remove # ignore/add/remove/force + +# Add or remove space between the type and open paren in a C++ cast, i.e. 'int(exp)' vs 'int (exp)' +sp_cpp_cast_paren = remove # ignore/add/remove/force + +# Add or remove space between 'sizeof' and '(' +sp_sizeof_paren = remove # ignore/add/remove/force + +# Add or remove space after the tag keyword (Pawn) +sp_after_tag = ignore # ignore/add/remove/force + +# Add or remove space inside enum '{' and '}' +sp_inside_braces_enum = remove # ignore/add/remove/force + +# Add or remove space inside struct/union '{' and '}' +sp_inside_braces_struct = remove # ignore/add/remove/force + +# Add or remove space inside '{' and '}' +sp_inside_braces = force # ignore/add/remove/force + +# Add or remove space inside '{}' +sp_inside_braces_empty = force # ignore/add/remove/force + +# Add or remove space between return type and function name +# A minimum of 1 is forced except for pointer return types. +sp_type_func = force # ignore/add/remove/force + +# Add or remove space between function name and '(' on function declaration +sp_func_proto_paren = remove # ignore/add/remove/force + +# Add or remove space between function name and '(' on function definition +sp_func_def_paren = remove # ignore/add/remove/force + +# Add or remove space inside empty function '()' +sp_inside_fparens = remove # ignore/add/remove/force + +# Add or remove space inside function '(' and ')' +sp_inside_fparen = remove # ignore/add/remove/force + +# Add or remove space inside the first parens in the function type: 'void (*x)(...)' +sp_inside_tparen = remove # ignore/add/remove/force + +# Add or remove between the parens in the function type: 'void (*x)(...)' +sp_after_tparen_close = remove # ignore/add/remove/force + +# Add or remove space between ']' and '(' when part of a function call. +sp_square_fparen = remove # ignore/add/remove/force + +# Add or remove space between ')' and '{' of function +sp_fparen_brace = force # ignore/add/remove/force + +# Add or remove space between function name and '(' on function calls +sp_func_call_paren = remove # ignore/add/remove/force + +# Add or remove space between function name and '()' on function calls without parameters. +# If set to 'ignore' (the default), sp_func_call_paren is used. +sp_func_call_paren_empty = remove # ignore/add/remove/force + +# Add or remove space between the user function name and '(' on function calls +# You need to set a keyword to be a user function, like this: 'set func_call_user _' in the config file. +sp_func_call_user_paren = ignore # ignore/add/remove/force + +# Add or remove space between a constructor/destructor and the open paren +sp_func_class_paren = remove # ignore/add/remove/force + +# Add or remove space between 'return' and '(' +sp_return_paren = force # ignore/add/remove/force + +# Add or remove space between '__attribute__' and '(' +sp_attribute_paren = remove # ignore/add/remove/force + +# Add or remove space between 'defined' and '(' in '#if defined (FOO)' +sp_defined_paren = remove # ignore/add/remove/force + +# Add or remove space between 'throw' and '(' in 'throw (something)' +sp_throw_paren = remove # ignore/add/remove/force + +# Add or remove space between 'throw' and anything other than '(' as in '@throw [...];' +sp_after_throw = remove # ignore/add/remove/force + +# Add or remove space between 'catch' and '(' in 'catch (something) { }' +# If set to ignore, sp_before_sparen is used. +sp_catch_paren = remove # ignore/add/remove/force + +# Add or remove space between 'version' and '(' in 'version (something) { }' (D language) +# If set to ignore, sp_before_sparen is used. +sp_version_paren = remove # ignore/add/remove/force + +# Add or remove space between 'scope' and '(' in 'scope (something) { }' (D language) +# If set to ignore, sp_before_sparen is used. +sp_scope_paren = remove # ignore/add/remove/force + +# Add or remove space between macro and value +sp_macro = remove # ignore/add/remove/force + +# Add or remove space between macro function ')' and value +sp_macro_func = remove # ignore/add/remove/force + +# Add or remove space between 'else' and '{' if on the same line +sp_else_brace = force # ignore/add/remove/force + +# Add or remove space between '}' and 'else' if on the same line +sp_brace_else = force # ignore/add/remove/force + +# Add or remove space between '}' and the name of a typedef on the same line +sp_brace_typedef = force # ignore/add/remove/force + +# Add or remove space between 'catch' and '{' if on the same line +sp_catch_brace = force # ignore/add/remove/force + +# Add or remove space between '}' and 'catch' if on the same line +sp_brace_catch = force # ignore/add/remove/force + +# Add or remove space between 'finally' and '{' if on the same line +sp_finally_brace = force # ignore/add/remove/force + +# Add or remove space between '}' and 'finally' if on the same line +sp_brace_finally = force # ignore/add/remove/force + +# Add or remove space between 'try' and '{' if on the same line +sp_try_brace = force # ignore/add/remove/force + +# Add or remove space between get/set and '{' if on the same line +sp_getset_brace = force # ignore/add/remove/force + +# Add or remove space before the '::' operator +sp_before_dc = remove # ignore/add/remove/force + +# Add or remove space after the '::' operator +sp_after_dc = remove # ignore/add/remove/force + +# Add or remove around the D named array initializer ':' operator +sp_d_array_colon = ignore # ignore/add/remove/force + +# Add or remove space after the '!' (not) operator. Default=Remove +sp_not = remove # ignore/add/remove/force + +# Add or remove space after the '~' (invert) operator. Default=Remove +sp_inv = remove # ignore/add/remove/force + +# Add or remove space after the '&' (address-of) operator. Default=Remove +# This does not affect the spacing after a '&' that is part of a type. +sp_addr = remove # ignore/add/remove/force + +# Add or remove space around the '.' or '->' operators. Default=Remove +sp_member = remove # ignore/add/remove/force + +# Add or remove space after the '*' (dereference) operator. Default=Remove +# This does not affect the spacing after a '*' that is part of a type. +sp_deref = remove # ignore/add/remove/force + +# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. Default=Remove +sp_sign = remove # ignore/add/remove/force + +# Add or remove space before or after '++' and '--', as in '(--x)' or 'y++;'. Default=Remove +sp_incdec = remove # ignore/add/remove/force + +# Add or remove space before a backslash-newline at the end of a line. Default=Add +sp_before_nl_cont = force # ignore/add/remove/force + +# Add or remove space after the scope '+' oo '-', as in '-(void) foo;' or '+(int) bar;' +sp_after_oc_scope = remove # ignore/add/remove/force + +# Add or remove space after the colon in message specs +# '-(int) f:(int) x;' vs '-(int) f: (int) x;' +sp_after_oc_colon = force # ignore/add/remove/force + +# Add or remove space before the colon in message specs +# '-(int) f: (int) x;' vs '-(int) f : (int) x;' +sp_before_oc_colon = force # ignore/add/remove/force + +# Add or remove space after the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};' +sp_after_oc_dict_colon = force # ignore/add/remove/force + +# Add or remove space before the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};' +sp_before_oc_dict_colon = force # ignore/add/remove/force + +# Add or remove space after the colon in message specs +# '[object setValue:1];' vs '[object setValue: 1];' +sp_after_send_oc_colon = force # ignore/add/remove/force + +# Add or remove space before the colon in message specs +# '[object setValue:1];' vs '[object setValue :1];' +sp_before_send_oc_colon = force # ignore/add/remove/force + +# Add or remove space after the (type) in message specs +# '-(int)f: (int) x;' vs '-(int)f: (int)x;' +sp_after_oc_type = remove # ignore/add/remove/force + +# Add or remove space after the first (type) in message specs +# '-(int) f:(int)x;' vs '-(int)f:(int)x;' +sp_after_oc_return_type = force # ignore/add/remove/force + +# Add or remove space between '@selector' and '(' +# '@selector(msgName)' vs '@selector (msgName)' +# Also applies to @protocol() constructs +sp_after_oc_at_sel = remove # ignore/add/remove/force + +# Add or remove space between '@selector(x)' and the following word +# '@selector(foo) a:' vs '@selector(foo)a:' +sp_after_oc_at_sel_parens = force # ignore/add/remove/force + +# Add or remove space inside '@selector' parens +# '@selector(foo)' vs '@selector( foo )' +# Also applies to @protocol() constructs +sp_inside_oc_at_sel_parens = remove # ignore/add/remove/force + +# Add or remove space before a block pointer caret +# '^int (int arg){...}' vs. ' ^int (int arg){...}' +sp_before_oc_block_caret = remove # ignore/add/remove/force + +# Add or remove space after a block pointer caret +# '^int (int arg){...}' vs. '^ int (int arg){...}' +sp_after_oc_block_caret = remove # ignore/add/remove/force + +# Add or remove space between the receiver and selector in a message. +# '[receiver selector ...]' +sp_after_oc_msg_receiver = force # ignore/add/remove/force + +# Add or remove space after @property. +sp_after_oc_property = remove # ignore/add/remove/force + +# Add or remove space around the ':' in 'b ? t : f' +sp_cond_colon = force # ignore/add/remove/force + +# Add or remove space around the '?' in 'b ? t : f' +sp_cond_question = force # ignore/add/remove/force + +# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make sense here. +sp_case_label = force # ignore/add/remove/force + +# Control the space around the D '..' operator. +sp_range = force # ignore/add/remove/force + +# Control the spacing after ':' in 'for (TYPE VAR : EXPR)' (Java) +sp_after_for_colon = force # ignore/add/remove/force + +# Control the spacing before ':' in 'for (TYPE VAR : EXPR)' (Java) +sp_before_for_colon = force # ignore/add/remove/force + +# Control the spacing in 'extern (C)' (D) +sp_extern_paren = remove # ignore/add/remove/force + +# Control the space after the opening of a C++ comment '// A' vs '//A' +sp_cmt_cpp_start = force # ignore/add/remove/force + +# Controls the spaces between #else or #endif and a trailing comment +sp_endif_cmt = force # ignore/add/remove/force + +# Controls the spaces after 'new', 'delete', and 'delete[]' +sp_after_new = force # ignore/add/remove/force + +# Controls the spaces before a trailing or embedded comment +sp_before_tr_emb_cmt = force # ignore/add/remove/force + +# Number of spaces before a trailing or embedded comment +sp_num_before_tr_emb_cmt = 1 # number + +# Control space between a Java annotation and the open paren. +sp_annotation_paren = remove # ignore/add/remove/force + +# +# Code alignment (not left column spaces/tabs) +# + +# Whether to keep non-indenting tabs +align_keep_tabs = false # false/true + +# Whether to use tabs for aligning +align_with_tabs = true # false/true + +# Whether to bump out to the next tab when aligning +align_on_tabstop = true # false/true + +# Whether to left-align numbers +align_number_left = false # false/true + +# Align variable definitions in prototypes and functions +align_func_params = false # false/true + +# Align parameters in single-line functions that have the same name. +# The function names must already be aligned with each other. +align_same_func_call_params = false # false/true + +# The span for aligning variable definitions (0=don't align) +align_var_def_span = 0 # number + +# How to align the star in variable definitions. +# 0=Part of the type 'void * foo;' +# 1=Part of the variable 'void *foo;' +# 2=Dangling 'void *foo;' +align_var_def_star_style = 2 # number + +# How to align the '&' in variable definitions. +# 0=Part of the type +# 1=Part of the variable +# 2=Dangling +align_var_def_amp_style = 2 # number + +# The threshold for aligning variable definitions (0=no limit) +align_var_def_thresh = 0 # number + +# The gap for aligning variable definitions +align_var_def_gap = 0 # number + +# Whether to align the colon in struct bit fields +align_var_def_colon = false # false/true + +# Whether to align any attribute after the variable name +align_var_def_attribute = false # false/true + +# Whether to align inline struct/enum/union variable definitions +align_var_def_inline = false # false/true + +# The span for forceing on '=' in assignments (0=don't align) +align_assign_span = 0 # number + +# The threshold for aligning on '=' in assignments (0=no limit) +align_assign_thresh = 0 # number + +# The span for aligning on '=' in enums (0=don't align) +align_enum_equ_span = 0 # number + +# The threshold for aligning on '=' in enums (0=no limit) +align_enum_equ_thresh = 0 # number + +# The span for aligning struct/union (0=don't align) +align_var_struct_span = 0 # number + +# The threshold for aligning struct/union member definitions (0=no limit) +align_var_struct_thresh = 0 # number + +# The gap for aligning struct/union member definitions +align_var_struct_gap = 0 # number + +# The span for aligning struct initializer values (0=don't align) +align_struct_init_span = 0 # number + +# The minimum space between the type and the synonym of a typedef +align_typedef_gap = 0 # number + +# The span for aligning single-line typedefs (0=don't align) +align_typedef_span = 0 # number + +# How to align typedef'd functions with other typedefs +# 0: Don't mix them at all +# 1: align the open paren with the types +# 2: align the function type name with the other type names +align_typedef_func = 0 # number + +# Controls the positioning of the '*' in typedefs. Just try it. +# 0: Align on typedef type, ignore '*' +# 1: The '*' is part of type name: typedef int *pint; +# 2: The '*' is part of the type, but dangling: typedef int *pint; +align_typedef_star_style = 0 # number + +# Controls the positioning of the '&' in typedefs. Just try it. +# 0: Align on typedef type, ignore '&' +# 1: The '&' is part of type name: typedef int &pint; +# 2: The '&' is part of the type, but dangling: typedef int &pint; +align_typedef_amp_style = 0 # number + +# The span for aligning comments that end lines (0=don't align) +align_right_cmt_span = 0 # number + +# If aligning comments, mix with comments after '}' and #endif with less than 3 spaces before the comment +align_right_cmt_mix = false # false/true + +# If a trailing comment is more than this number of columns away from the text it follows, +# it will qualify for being aligned. This has to be > 0 to do anything. +align_right_cmt_gap = 0 # number + +# Align trailing comment at or beyond column N; 'pulls in' comments as a bonus side effect (0=ignore) +align_right_cmt_at_col = 0 # number + +# The span for aligning function prototypes (0=don't align) +align_func_proto_span = 0 # number + +# Minimum gap between the return type and the function name. +align_func_proto_gap = 0 # number + +# Align function protos on the 'operator' keyword instead of what follows +align_on_operator = false # false/true + +# Whether to mix aligning prototype and variable declarations. +# If true, align_var_def_XXX options are used instead of align_func_proto_XXX options. +align_mix_var_proto = false # false/true + +# Align single-line functions with function prototypes, uses align_func_proto_span +align_single_line_func = false # false/true + +# Aligning the open brace of single-line functions. +# Requires align_single_line_func=true, uses align_func_proto_span +align_single_line_brace = false # false/true + +# Gap for align_single_line_brace. +align_single_line_brace_gap = 0 # number + +# The span for aligning ObjC msg spec (0=don't align) +align_oc_msg_spec_span = 0 # number + +# Whether to align macros wrapped with a backslash and a newline. +# This will not work right if the macro contains a multi-line comment. +align_nl_cont = false # false/true + +# # Align macro functions and variables together +align_pp_define_together = false # false/true + +# The minimum space between label and value of a preprocessor define +align_pp_define_gap = 0 # number + +# The span for aligning on '#define' bodies (0=don't align) +align_pp_define_span = 0 # number + +# Align lines that start with '<<' with previous '<<'. Default=true +align_left_shift = true # false/true + +# Span for aligning parameters in an Obj-C message call on the ':' (0=don't align) +align_oc_msg_colon_span = 0 # number + +# If true, always align with the first parameter, even if it is too short. +align_oc_msg_colon_first = false # false/true + +# Aligning parameters in an Obj-C '+' or '-' declaration on the ':' +align_oc_decl_colon = false # false/true + +# +# Newline adding and removing options +# + +# Whether to collapse empty blocks between '{' and '}' +nl_collapse_empty_body = true # false/true + +# Don't split one-line braced assignments - 'foo_t f = { 1, 2 };' +nl_assign_leave_one_liners = true # false/true + +# Don't split one-line braced statements inside a class xx { } body +nl_class_leave_one_liners = true # false/true + +# Don't split one-line enums: 'enum foo { BAR = 15 };' +nl_enum_leave_one_liners = true # false/true + +# Don't split one-line get or set functions +nl_getset_leave_one_liners = true # false/true + +# Don't split one-line function definitions - 'int foo() { return 0; }' +nl_func_leave_one_liners = true # false/true + +# Don't split one-line if/else statements - 'if(a) b++;' +nl_if_leave_one_liners = false # false/true + +# Don't split one-line OC messages +nl_oc_msg_leave_one_liner = false # false/true + +# Add or remove newlines at the start of the file +nl_start_of_file = remove # ignore/add/remove/force + +# The number of newlines at the start of the file (only used if nl_start_of_file is 'add' or 'force' +nl_start_of_file_min = 0 # number + +# Add or remove newline at the end of the file +nl_end_of_file = force # ignore/add/remove/force + +# The number of newlines at the end of the file (only used if nl_end_of_file is 'add' or 'force') +nl_end_of_file_min = 1 # number + +# Add or remove newline between '=' and '{' +nl_assign_brace = force # ignore/add/remove/force + +# Add or remove newline between '=' and '[' (D only) +nl_assign_square = force # ignore/add/remove/force + +# Add or remove newline after '= [' (D only). Will also affect the newline before the ']' +nl_after_square_assign = ignore # ignore/add/remove/force + +# The number of blank lines after a block of variable definitions at the top of a function body +# 0 = No change (default) +nl_func_var_def_blk = 2 # number + +# The number of newlines before a block of typedefs +# 0 = No change (default) +nl_typedef_blk_start = 0 # number + +# The number of newlines after a block of typedefs +# 0 = No change (default) +nl_typedef_blk_end = 2 # number + +# The maximum consecutive newlines within a block of typedefs +# 0 = No change (default) +nl_typedef_blk_in = 0 # number + +# The number of newlines before a block of variable definitions not at the top of a function body +# 0 = No change (default) +nl_var_def_blk_start = 2 # number + +# The number of newlines after a block of variable definitions not at the top of a function body +# 0 = No change (default) +nl_var_def_blk_end = 2 # number + +# The maximum consecutive newlines within a block of variable definitions +# 0 = No change (default) +nl_var_def_blk_in = 0 # number + +# Add or remove newline between a function call's ')' and '{', as in: +# list_for_each(item, &list) { } +nl_fcall_brace = force # ignore/add/remove/force + +# Add or remove newline between 'enum' and '{' +nl_enum_brace = force # ignore/add/remove/force + +# Add or remove newline between 'struct and '{' +nl_struct_brace = force # ignore/add/remove/force + +# Add or remove newline between 'union' and '{' +nl_union_brace = force # ignore/add/remove/force + +# Add or remove newline between 'if' and '{' +nl_if_brace = force # ignore/add/remove/force + +# Add or remove newline between '}' and 'else' +nl_brace_else = force # ignore/add/remove/force + +# Add or remove newline between 'else if' and '{' +# If set to ignore, nl_if_brace is used instead +nl_elseif_brace = force # ignore/add/remove/force + +# Add or remove newline between 'else' and '{' +nl_else_brace = force # ignore/add/remove/force + +# Add or remove newline between 'else' and 'if' +nl_else_if = remove # ignore/add/remove/force + +# Add or remove newline between '}' and 'finally' +nl_brace_finally = force # ignore/add/remove/force + +# Add or remove newline between 'finally' and '{' +nl_finally_brace = force # ignore/add/remove/force + +# Add or remove newline between 'try' and '{' +nl_try_brace = force # ignore/add/remove/force + +# Add or remove newline between get/set and '{' +nl_getset_brace = force # ignore/add/remove/force + +# Add or remove newline between 'for' and '{' +nl_for_brace = force # ignore/add/remove/force + +# Add or remove newline between 'catch' and '{' +nl_catch_brace = force # ignore/add/remove/force + +# Add or remove newline between '}' and 'catch' +nl_brace_catch = force # ignore/add/remove/force + +# Add or remove newline between 'while' and '{' +nl_while_brace = force # ignore/add/remove/force + +# Add or remove newline between 'scope (x)' and '{' (D) +nl_scope_brace = force # ignore/add/remove/force + +# Add or remove newline between 'unittest' and '{' (D) +nl_unittest_brace = force # ignore/add/remove/force + +# Add or remove newline between 'version (x)' and '{' (D) +nl_version_brace = force # ignore/add/remove/force + +# Add or remove newline between 'using' and '{' +nl_using_brace = force # ignore/add/remove/force + +# Add or remove newline between two open or close braces. +# Due to general newline/brace handling, REMOVE may not work. +nl_brace_brace = force # ignore/add/remove/force + +# Add or remove newline between 'do' and '{' +nl_do_brace = force # ignore/add/remove/force + +# Add or remove newline between '}' and 'while' of 'do' statement +nl_brace_while = remove # ignore/add/remove/force + +# Add or remove newline between 'switch' and '{' +nl_switch_brace = add # ignore/add/remove/force + +# Add a newline between ')' and '{' if the ')' is on a different line than the if/for/etc. +# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch, and nl_catch_brace. +nl_multi_line_cond = false # false/true + +# Force a newline in a define after the macro name for multi-line defines. +nl_multi_line_define = false # false/true + +# Whether to put a newline before 'case' statement +nl_before_case = false # false/true + +# Add or remove newline between ')' and 'throw' +nl_before_throw = remove # ignore/add/remove/force + +# Whether to put a newline after 'case' statement +nl_after_case = false # false/true + +# Add or remove a newline between a case ':' and '{'. Overrides nl_after_case. +nl_case_colon_brace = force # ignore/add/remove/force + +# Newline between namespace and { +nl_namespace_brace = force # ignore/add/remove/force + +# Add or remove newline between 'template<>' and whatever follows. +nl_template_class = remove # ignore/add/remove/force + +# Add or remove newline between 'class' and '{' +nl_class_brace = force # ignore/add/remove/force + +# Add or remove newline after each ',' in the constructor member initialization +nl_class_init_args = remove # ignore/add/remove/force + +# Add or remove newline between return type and function name in a function definition +nl_func_type_name = force # ignore/add/remove/force + +# Add or remove newline between return type and function name inside a class {} +# Uses nl_func_type_name or nl_func_proto_type_name if set to ignore. +nl_func_type_name_class = force # ignore/add/remove/force + +# Add or remove newline between function scope and name in a definition +# Controls the newline after '::' in 'void A::f() { }' +nl_func_scope_name = force # ignore/add/remove/force + +# Add or remove newline between return type and function name in a prototype +nl_func_proto_type_name = remove # ignore/add/remove/force + +# Add or remove newline between a function name and the opening '(' +nl_func_paren = remove # ignore/add/remove/force + +# Add or remove newline between a function name and the opening '(' in the definition +nl_func_def_paren = remove # ignore/add/remove/force + +# Add or remove newline after '(' in a function declaration +nl_func_decl_start = remove # ignore/add/remove/force + +# Add or remove newline after '(' in a function definition +nl_func_def_start = remove # ignore/add/remove/force + +# Overrides nl_func_decl_start when there is only one parameter. +nl_func_decl_start_single = remove # ignore/add/remove/force + +# Overrides nl_func_def_start when there is only one parameter. +nl_func_def_start_single = remove # ignore/add/remove/force + +# Add or remove newline after each ',' in a function declaration +nl_func_decl_args = remove # ignore/add/remove/force + +# Add or remove newline after each ',' in a function definition +nl_func_def_args = remove # ignore/add/remove/force + +# Add or remove newline before the ')' in a function declaration +nl_func_decl_end = remove # ignore/add/remove/force + +# Add or remove newline before the ')' in a function definition +nl_func_def_end = remove # ignore/add/remove/force + +# Overrides nl_func_decl_end when there is only one parameter. +nl_func_decl_end_single = remove # ignore/add/remove/force + +# Overrides nl_func_def_end when there is only one parameter. +nl_func_def_end_single = remove # ignore/add/remove/force + +# Add or remove newline between '()' in a function declaration. +nl_func_decl_empty = remove # ignore/add/remove/force + +# Add or remove newline between '()' in a function definition. +nl_func_def_empty = remove # ignore/add/remove/force + +# Whether to put each OC message parameter on a separate line +# See nl_oc_msg_leave_one_liner +nl_oc_msg_args = false # false/true + +# Add or remove newline between function signature and '{' +nl_fdef_brace = force # ignore/add/remove/force + +# Add or remove a newline between the return keyword and return expression. +nl_return_expr = remove # ignore/add/remove/force + +# Whether to put a newline after semicolons, except in 'for' statements +nl_after_semicolon = false # false/true + +# Whether to put a newline after brace open. +# This also adds a newline before the matching brace close. +nl_after_brace_open = false # false/true + +# If nl_after_brace_open and nl_after_brace_open_cmt are true, a newline is +# placed between the open brace and a trailing single-line comment. +nl_after_brace_open_cmt = false # false/true + +# Whether to put a newline after a virtual brace open with a non-empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open = false # false/true + +# Whether to put a newline after a virtual brace open with an empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open_empty = false # false/true + +# Whether to put a newline after a brace close. +# Does not apply if followed by a necessary ';'. +nl_after_brace_close = false # false/true + +# Whether to put a newline after a virtual brace close. +# Would add a newline before return in: 'if (foo) a++; return;' +nl_after_vbrace_close = true # false/true + +# Control the newline between the close brace and 'b' in: 'struct { int a; } b;' +# Affects enums, unions, and structures. If set to ignore, uses nl_after_brace_close +nl_brace_struct_var = remove # ignore/add/remove/force + +# Whether to alter newlines in '#define' macros +nl_define_macro = true # false/true + +# Whether to not put blanks after '#ifxx', '#elxx', or before '#endif' +nl_squeeze_ifdef = false # false/true + +# Add or remove blank line before 'if' +nl_before_if = force # ignore/add/remove/force + +# Add or remove blank line after 'if' statement +nl_after_if = force # ignore/add/remove/force + +# Add or remove blank line before 'for' +nl_before_for = force # ignore/add/remove/force + +# Add or remove blank line after 'for' statement +nl_after_for = force # ignore/add/remove/force + +# Add or remove blank line before 'while' +nl_before_while = force # ignore/add/remove/force + +# Add or remove blank line after 'while' statement +nl_after_while = force # ignore/add/remove/force + +# Add or remove blank line before 'switch' +nl_before_switch = force # ignore/add/remove/force + +# Add or remove blank line after 'switch' statement +nl_after_switch = force # ignore/add/remove/force + +# Add or remove blank line before 'do' +nl_before_do = force # ignore/add/remove/force + +# Add or remove blank line after 'do/while' statement +nl_after_do = force # ignore/add/remove/force + +# Whether to double-space commented-entries in struct/enum +nl_ds_struct_enum_cmt = false # false/true + +# Whether to double-space before the close brace of a struct/union/enum +# (lower priority than 'eat_blanks_before_close_brace') +nl_ds_struct_enum_close_brace = false # false/true + +# Add or remove a newline around a class colon. +# Related to pos_class_colon, nl_class_init_args, and pos_comma. +nl_class_colon = ignore # ignore/add/remove/force + +# Change simple unbraced if statements into a one-liner +# 'if(b)\n i++;' => 'if(b) i++;' +nl_create_if_one_liner = false # false/true + +# Change simple unbraced for statements into a one-liner +# 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);' +nl_create_for_one_liner = false # false/true + +# Change simple unbraced while statements into a one-liner +# 'while (i<5)\n foo(i++);' => 'while (i<5) foo(i++);' +nl_create_while_one_liner = false # false/true + +# +# Positioning options +# + +# The position of arithmetic operators in wrapped expressions +pos_arith = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of assignment in wrapped expressions. +# Do not affect '=' followed by '{' +pos_assign = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of boolean operators in wrapped expressions +pos_bool = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of comparison operators in wrapped expressions +pos_compare = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of conditional (b ? t : f) operators in wrapped expressions +pos_conditional = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of the comma in wrapped expressions +pos_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of the comma in the constructor initialization list +pos_class_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# The position of colons between constructor and member initialization +pos_class_colon = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force + +# +# Line Splitting options +# + +# Try to limit code width to N number of columns +code_width = 0 # number + +# Whether to fully split long 'for' statements at semi-colons +ls_for_split_full = false # false/true + +# Whether to fully split long function protos/calls at commas +ls_func_split_full = false # false/true + +# Whether to split lines as close to code_width as possible and ignore some groupings +ls_code_width = false # false/true + +# +# Blank line options +# + +# The maximum consecutive newlines +nl_max = 2 # number + +# The number of newlines after a function prototype, if followed by another function prototype +nl_after_func_proto = 1 # number + +# The number of newlines after a function prototype, if not followed by another function prototype +nl_after_func_proto_group = 2 # number + +# The number of newlines after '}' of a multi-line function body +nl_after_func_body = 2 # number + +# The number of newlines after '}' of a multi-line function body in a class declaration +nl_after_func_body_class = 2 # number + +# The number of newlines after '}' of a single line function body +nl_after_func_body_one_liner = 2 # number + +# The minimum number of newlines before a multi-line comment. +# Doesn't apply if after a brace open or another multi-line comment. +nl_before_block_comment = 2 # number + +# The minimum number of newlines before a single-line C comment. +# Doesn't apply if after a brace open or other single-line C comments. +nl_before_c_comment = 2 # number + +# The minimum number of newlines before a CPP comment. +# Doesn't apply if after a brace open or other CPP comments. +nl_before_cpp_comment = 2 # number + +# Whether to force a newline after a multi-line comment. +nl_after_multiline_comment = true # false/true + +# The number of newlines after '}' or ';' of a struct/enum/union definition +nl_after_struct = 2 # number + +# The number of newlines after '}' or ';' of a class definition +nl_after_class = 2 # number + +# The number of newlines before a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. +# Will not change the newline count if after a brace open. +# 0 = No change. +nl_before_access_spec = 1 # number + +# The number of newlines after a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. +# 0 = No change. +nl_after_access_spec = 2 # number + +# The number of newlines between a function def and the function comment. +# 0 = No change. +nl_comment_func_def = 0 # number + +# The number of newlines after a try-catch-finally block that isn't followed by a brace close. +# 0 = No change. +nl_after_try_catch_finally = 2 # number + +# The number of newlines before and after a property, indexer or event decl. +# 0 = No change. +nl_around_cs_property = 0 # number + +# The number of newlines between the get/set/add/remove handlers in C#. +# 0 = No change. +nl_between_get_set = 0 # number + +# Add or remove newline between C# property and the '{' +nl_property_brace = force # ignore/add/remove/force + +# Whether to remove blank lines after '{' +eat_blanks_after_open_brace = true # false/true + +# Whether to remove blank lines before '}' +eat_blanks_before_close_brace = true # false/true + +# How aggressively to remove extra newlines not in preproc. +# 0: No change +# 1: Remove most newlines not handled by other config +# 2: Remove all newlines and reformat completely by config +nl_remove_extra_newlines = 2 # number + +# Whether to put a blank line before 'return' statements, unless after an open brace. +nl_before_return = true # false/true + +# Whether to put a blank line after 'return' statements, unless followed by a close brace. +nl_after_return = false # false/true + +# Whether to put a newline after a Java annotation statement. +# Only affects annotations that are after a newline. +nl_after_annotation = remove # ignore/add/remove/force + +# Controls the newline between two annotations. +nl_between_annotation = ignore # ignore/add/remove/force + +# +# Code modifying options (non-whitespace) +# + +# Add or remove braces on single-line 'do' statement +mod_full_brace_do = remove # ignore/add/remove/force + +# Add or remove braces on single-line 'for' statement +mod_full_brace_for = remove # ignore/add/remove/force + +# Add or remove braces on single-line function definitions. (Pawn) +mod_full_brace_function = force # ignore/add/remove/force + +# Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'. +mod_full_brace_if = remove # ignore/add/remove/force + +# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if. +# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed. +mod_full_brace_if_chain = true # false/true + +# Don't remove braces around statements that span N newlines +mod_full_brace_nl = 0 # number + +# Add or remove braces on single-line 'while' statement +mod_full_brace_while = force # ignore/add/remove/force + +# Add or remove braces on single-line 'using ()' statement +mod_full_brace_using = remove # ignore/add/remove/force + +# Add or remove unnecessary paren on 'return' statement +mod_paren_on_return = remove # ignore/add/remove/force + +# Whether to change optional semicolons to real semicolons +mod_pawn_semicolon = false # false/true + +# Add parens on 'while' and 'if' statement around bools +mod_full_paren_if_bool = true # false/true + +# Whether to remove superfluous semicolons +mod_remove_extra_semicolon = true # false/true + +# If a function body exceeds the specified number of newlines and doesn't have a comment after +# the close brace, a comment will be added. +mod_add_long_function_closebrace_comment = 0 # number + +# If a switch body exceeds the specified number of newlines and doesn't have a comment after +# the close brace, a comment will be added. +mod_add_long_switch_closebrace_comment = 0 # number + +# If an #ifdef body exceeds the specified number of newlines and doesn't have a comment after +# the #endif, a comment will be added. +mod_add_long_ifdef_endif_comment = 0 # number + +# If an #ifdef or #else body exceeds the specified number of newlines and doesn't have a comment after +# the #else, a comment will be added. +mod_add_long_ifdef_else_comment = 0 # number + +# If TRUE, will sort consecutive single-line 'import' statements [Java, D] +mod_sort_import = true # false/true + +# If TRUE, will sort consecutive single-line 'using' statements [C#] +mod_sort_using = true # false/true + +# If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C] +# This is generally a bad idea, as it may break your code. +mod_sort_include = false # false/true + +# If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace. +mod_move_case_break = true # false/true + +# Will add or remove the braces around a fully braced case statement. +# Will only remove the braces if there are no variable declarations in the block. +mod_case_brace = remove # ignore/add/remove/force + +# If TRUE, it will remove a void 'return;' that appears as the last statement in a function. +mod_remove_empty_return = false # false/true + +# +# Comment modifications +# + +# Try to wrap comments at cmt_width columns +cmt_width = 0 # number + +# Set the comment reflow mode (default: 0) +# 0: no reflowing (apart from the line wrapping due to cmt_width) +# 1: no touching at all +# 2: full reflow +cmt_reflow_mode = 0 # number + +# If false, disable all multi-line comment changes, including cmt_width. keyword substitution, and leading chars. +# Default is true. +cmt_indent_multi = true # false/true + +# Whether to group c-comments that look like they are in a block +cmt_c_group = false # false/true + +# Whether to put an empty '/*' on the first line of the combined c-comment +cmt_c_nl_start = false # false/true + +# Whether to put a newline before the closing '*/' of the combined c-comment +cmt_c_nl_end = false # false/true + +# Whether to group cpp-comments that look like they are in a block +cmt_cpp_group = false # false/true + +# Whether to put an empty '/*' on the first line of the combined cpp-comment +cmt_cpp_nl_start = false # false/true + +# Whether to put a newline before the closing '*/' of the combined cpp-comment +cmt_cpp_nl_end = false # false/true + +# Whether to change cpp-comments into c-comments +cmt_cpp_to_c = false # false/true + +# Whether to put a star on subsequent comment lines +cmt_star_cont = false # false/true + +# The number of spaces to insert at the start of subsequent comment lines +cmt_sp_before_star_cont = 0 # number + +# The number of spaces to insert after the star on subsequent comment lines +cmt_sp_after_star_cont = 1 # number + +# For multi-line comments with a '*' lead, remove leading spaces if the first and last lines of +# the comment are the same length. Default=True +cmt_multi_check_last = true # false/true + +# The filename that contains text to insert at the head of a file if the file doesn't start with a C/C++ comment. +# Will substitute $(filename) with the current file's name. +cmt_insert_file_header = "" # string + +# The filename that contains text to insert at the end of a file if the file doesn't end with a C/C++ comment. +# Will substitute $(filename) with the current file's name. +cmt_insert_file_footer = "" # string + +# The filename that contains text to insert before a function implementation if the function isn't preceded with a C/C++ comment. +# Will substitute $(function) with the function name and $(javaparam) with the javadoc @param and @return stuff. +# Will also substitute $(fclass) with the class name: void CFoo::Bar() { ... } +cmt_insert_func_header = "" # string + +# The filename that contains text to insert before a class if the class isn't preceded with a C/C++ comment. +# Will substitute $(class) with the class name. +cmt_insert_class_header = "" # string + +# The filename that contains text to insert before a Obj-C message specification if the method isn't preceeded with a C/C++ comment. +# Will substitute $(message) with the function name and $(javaparam) with the javadoc @param and @return stuff. +cmt_insert_oc_msg_header = "" # string + +# If a preprocessor is encountered when stepping backwards from a function name, then +# this option decides whether the comment should be inserted. +# Affects cmt_insert_oc_msg_header, cmt_insert_func_header and cmt_insert_class_header. +cmt_insert_before_preproc = false # false/true + +# +# Preprocessor options +# + +# Control indent of preprocessors inside #if blocks at brace level 0 +pp_indent = remove # ignore/add/remove/force + +# Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false) +pp_indent_at_level = false # false/true + +# If pp_indent_at_level=false, specifies the number of columns to indent per level. Default=1. +pp_indent_count = 1 # number + +# Add or remove space after # based on pp_level of #if blocks +pp_space = force # ignore/add/remove/force + +# Sets the number of spaces added with pp_space +pp_space_count = 1 # number + +# The indent for #region and #endregion in C# and '#pragma region' in C/C++ +pp_indent_region = 0 # number + +# Whether to indent the code between #region and #endregion +pp_region_indent_code = false # false/true + +# If pp_indent_at_level=true, sets the indent for #if, #else, and #endif when not at file-level +pp_indent_if = 0 # number + +# Control whether to indent the code between #if, #else and #endif when not at file-level +pp_if_indent_code = false # false/true + +# Whether to indent '#define' at the brace level (true) or from column 1 (false) +pp_define_at_level = false # false/true + +# You can force a token to be a type with the 'type' option. +# Example: +# type myfoo1 myfoo2 +# +# You can create custom macro-based indentation using macro-open, +# macro-else and macro-close. +# Example: +# macro-open BEGIN_TEMPLATE_MESSAGE_MAP +# macro-open BEGIN_MESSAGE_MAP +# macro-close END_MESSAGE_MAP +# +# You can assign any keyword to any type with the set option. +# set func_call_user _ N_ +# +# The full syntax description of all custom definition config entries +# is shown below: +# +# define custom tokens as: +# - embed whitespace in token using '' escape character, or +# put token in quotes +# - these: ' " and ` are recognized as quote delimiters +# +# type token1 token2 token3 ... +# ^ optionally specify multiple tokens on a single line +# define def_token output_token +# ^ output_token is optional, then NULL is assumed +# macro-open token +# macro-close token +# macro-else token +# set id token1 token2 ... +# ^ optionally specify multiple tokens on a single line +# ^ id is one of the names in token_enum.h sans the CT_ prefix, +# e.g. PP_PRAGMA +# +# all tokens are separated by any mix of ',' commas, '=' equal signs +# and whitespace (space, tab) +# -- cgit v1.2.3