diff --git a/COPYING b/COPYING index 223ede7de3ec74eb86253f9ce9ed7ba3c5aa9130..18a090cc7bc01c186a0d6897ceb41a0497685e05 100644 --- a/COPYING +++ b/COPYING @@ -1,3 +1,10 @@ + Most of liboop is covered under the Lesser GPL (below). + +** However, the contents of the "foreign" directory may have their own +** license agreements. See foreign/README for details. + +------------------------------------------------------------------------------- + GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 diff --git a/Makefile.am b/Makefile.am index 098c87b5a74a61e961bf3d3b5dad9049c3f57d33..0d08d8e9d8a2a8bf8672f3f6ab61a11466cbe513 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,22 +7,33 @@ # See the file COPYING for details. AUTOMAKE_OPTIONS = foreign 1.2 -lib_LTLIBRARIES = liboop.la liboop-adns.la -noinst_PROGRAMS = test-oop test-adns +lib_LTLIBRARIES = liboop.la liboop-adns.la liboop-glib.la liboop-www.la +INCLUDES = $(GLIB_INCLUDES) $(WWW_INCLUDES) -I$(top_srcdir)/foreign -INCLUDES = -I$(srcdir)/foreign +# versions updated as of 0.4 -liboop_la_LDFLAGS = -version-info 1:0:1 # version:revision:age -liboop_la_SOURCES = sys.c select.c alloc.c +liboop_la_LDFLAGS = -version-info 2:0:0 # version:revision:age +liboop_la_SOURCES = sys.c select.c signal.c alloc.c -liboop_adns_la_LDFLAGS = -version-info 0:0:0 # version:revision:age +liboop_adns_la_LDFLAGS = -version-info 1:0:1 liboop_adns_la_SOURCES = adns.c -include_HEADERS = oop.h oop-adns.h +liboop_glib_la_LDFLAGS = -version-info 0:0:0 +liboop_glib_la_SOURCES = glib.c + +liboop_www_la_LDFLAGS = -version-info 0:0:0 +liboop_www_la_SOURCES = www.c + +include_HEADERS = oop.h oop-adns.h oop-glib.h oop-www.h + +noinst_PROGRAMS = test-oop -LDADD = liboop-adns.la liboop.la -ladns test_oop_SOURCES = test-oop.c -test_adns_SOURCES = test-adns.c +test_oop_LDADD = $(ADNS_LIBS) $(GLIB_LIBS) $(WWW_LIBS) liboop.la + +dist-hook: + mkdir $(distdir)/foreign + cp -p $(srcdir)/foreign/README $(srcdir)/foreign/*.h $(distdir)/foreign release: dist gzip -dc $(PACKAGE)-$(VERSION).tar.gz | bzip2 -9 \ diff --git a/Makefile.in b/Makefile.in index 8f10a9b4f64a34c9eccb5a64f7777ac4b9319bcd..b3a858cc96cfc15218afb8b643e88fae3086fbc0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -65,9 +65,12 @@ PRE_UNINSTALL = : POST_UNINSTALL = : host_alias = @host_alias@ host_triplet = @host@ +ADNS_LIBS = @ADNS_LIBS@ AS = @AS@ CC = @CC@ DLLTOOL = @DLLTOOL@ +GLIB_INCLUDES = @GLIB_INCLUDES@ +GLIB_LIBS = @GLIB_LIBS@ LD = @LD@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ @@ -75,27 +78,37 @@ MAKEINFO = @MAKEINFO@ NM = @NM@ OBJDUMP = @OBJDUMP@ PACKAGE = @PACKAGE@ +PROG_GLIB_CONFIG = @PROG_GLIB_CONFIG@ PROG_LDCONFIG = @PROG_LDCONFIG@ RANLIB = @RANLIB@ VERSION = @VERSION@ +WWW_INCLUDES = @WWW_INCLUDES@ +WWW_LIBS = @WWW_LIBS@ AUTOMAKE_OPTIONS = foreign 1.2 -lib_LTLIBRARIES = liboop.la liboop-adns.la -noinst_PROGRAMS = test-oop test-adns +lib_LTLIBRARIES = liboop.la liboop-adns.la liboop-glib.la liboop-www.la +INCLUDES = $(GLIB_INCLUDES) $(WWW_INCLUDES) -I$(top_srcdir)/foreign -INCLUDES = -I$(srcdir)/foreign +# versions updated as of 0.4 -liboop_la_LDFLAGS = -version-info 1:0:1 # version:revision:age -liboop_la_SOURCES = sys.c select.c alloc.c +liboop_la_LDFLAGS = -version-info 2:0:0 # version:revision:age +liboop_la_SOURCES = sys.c select.c signal.c alloc.c -liboop_adns_la_LDFLAGS = -version-info 0:0:0 # version:revision:age +liboop_adns_la_LDFLAGS = -version-info 1:0:1 liboop_adns_la_SOURCES = adns.c -include_HEADERS = oop.h oop-adns.h +liboop_glib_la_LDFLAGS = -version-info 0:0:0 +liboop_glib_la_SOURCES = glib.c + +liboop_www_la_LDFLAGS = -version-info 0:0:0 +liboop_www_la_SOURCES = www.c + +include_HEADERS = oop.h oop-adns.h oop-glib.h oop-www.h + +noinst_PROGRAMS = test-oop -LDADD = liboop-adns.la liboop.la -ladns test_oop_SOURCES = test-oop.c -test_adns_SOURCES = test-adns.c +test_oop_LDADD = $(ADNS_LIBS) $(GLIB_LIBS) $(WWW_LIBS) liboop.la ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = @@ -107,19 +120,18 @@ CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ liboop_la_LIBADD = -liboop_la_OBJECTS = sys.lo select.lo alloc.lo +liboop_la_OBJECTS = sys.lo select.lo signal.lo alloc.lo liboop_adns_la_LIBADD = liboop_adns_la_OBJECTS = adns.lo +liboop_glib_la_LIBADD = +liboop_glib_la_OBJECTS = glib.lo +liboop_www_la_LIBADD = +liboop_www_la_OBJECTS = www.lo PROGRAMS = $(noinst_PROGRAMS) test_oop_OBJECTS = test-oop.o -test_oop_LDADD = $(LDADD) -test_oop_DEPENDENCIES = liboop-adns.la liboop.la +test_oop_DEPENDENCIES = liboop.la test_oop_LDFLAGS = -test_adns_OBJECTS = test-adns.o -test_adns_LDADD = $(LDADD) -test_adns_DEPENDENCIES = liboop-adns.la liboop.la -test_adns_LDFLAGS = CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) @@ -136,10 +148,10 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP_ENV = --best -DEP_FILES = .deps/adns.P .deps/alloc.P .deps/select.P .deps/sys.P \ -.deps/test-adns.P .deps/test-oop.P -SOURCES = $(liboop_la_SOURCES) $(liboop_adns_la_SOURCES) $(test_oop_SOURCES) $(test_adns_SOURCES) -OBJECTS = $(liboop_la_OBJECTS) $(liboop_adns_la_OBJECTS) $(test_oop_OBJECTS) $(test_adns_OBJECTS) +DEP_FILES = .deps/adns.P .deps/alloc.P .deps/glib.P .deps/select.P \ +.deps/signal.P .deps/sys.P .deps/test-oop.P .deps/www.P +SOURCES = $(liboop_la_SOURCES) $(liboop_adns_la_SOURCES) $(liboop_glib_la_SOURCES) $(liboop_www_la_SOURCES) $(test_oop_SOURCES) +OBJECTS = $(liboop_la_OBJECTS) $(liboop_adns_la_OBJECTS) $(liboop_glib_la_OBJECTS) $(liboop_www_la_OBJECTS) $(test_oop_OBJECTS) all: all-redirect .SUFFIXES: @@ -222,6 +234,12 @@ liboop.la: $(liboop_la_OBJECTS) $(liboop_la_DEPENDENCIES) liboop-adns.la: $(liboop_adns_la_OBJECTS) $(liboop_adns_la_DEPENDENCIES) $(LINK) -rpath $(libdir) $(liboop_adns_la_LDFLAGS) $(liboop_adns_la_OBJECTS) $(liboop_adns_la_LIBADD) $(LIBS) +liboop-glib.la: $(liboop_glib_la_OBJECTS) $(liboop_glib_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(liboop_glib_la_LDFLAGS) $(liboop_glib_la_OBJECTS) $(liboop_glib_la_LIBADD) $(LIBS) + +liboop-www.la: $(liboop_www_la_OBJECTS) $(liboop_www_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(liboop_www_la_LDFLAGS) $(liboop_www_la_OBJECTS) $(liboop_www_la_LIBADD) $(LIBS) + mostlyclean-noinstPROGRAMS: clean-noinstPROGRAMS: @@ -235,10 +253,6 @@ test-oop: $(test_oop_OBJECTS) $(test_oop_DEPENDENCIES) @rm -f test-oop $(LINK) $(test_oop_LDFLAGS) $(test_oop_OBJECTS) $(test_oop_LDADD) $(LIBS) -test-adns: $(test_adns_OBJECTS) $(test_adns_DEPENDENCIES) - @rm -f test-adns - $(LINK) $(test_adns_LDFLAGS) $(test_adns_OBJECTS) $(test_adns_LDADD) $(LIBS) - install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) $(mkinstalldirs) $(DESTDIR)$(includedir) @@ -336,6 +350,7 @@ distdir: $(DISTFILES) || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done + $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) @@ -454,6 +469,10 @@ mostlyclean-generic distclean-generic clean-generic \ maintainer-clean-generic clean mostlyclean distclean maintainer-clean +dist-hook: + mkdir $(distdir)/foreign + cp -p $(srcdir)/foreign/README $(srcdir)/foreign/*.h $(distdir)/foreign + release: dist gzip -dc $(PACKAGE)-$(VERSION).tar.gz | bzip2 -9 \ > $(PACKAGE)-$(VERSION).tar.bz2 diff --git a/adns.c b/adns.c index 1dd7ff6c1062f71eebcafdaa76d5c8f6ca606510..69ec6aef2dcc5df15c246a2c3a14543101ae0df7 100644 --- a/adns.c +++ b/adns.c @@ -54,6 +54,7 @@ void oop_adns_delete(oop_adapter_adns *a) { assert(0 == a->count && "deleting oop_adapter_adns with outstanding queries"); a->source->cancel_time(a->source,OOP_TIME_NOW,on_process,a); + oop_select_delete(a->select); adns_finish(a->state); oop_free(a); } @@ -81,8 +82,8 @@ oop_adns_query *oop_adns_submit( void oop_adns_cancel(oop_adns_query *q) { adns_cancel(q->query); --q->a->count; - oop_free(q); set_select(q->a); + oop_free(q); } static void set_select(oop_adapter_adns *a) { diff --git a/configure b/configure index c95a465c4fdb7999d6f50ad98831b097d068d1bb..efd8ef58e7cdffbea5dcc0e93b6c20a23c4e26ec 100755 --- a/configure +++ b/configure @@ -701,7 +701,7 @@ fi PACKAGE=liboop -VERSION=0.2 +VERSION=0.4 if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } @@ -1787,6 +1787,270 @@ fi ;; esac +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1792: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 1807 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1813: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 1824 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1830: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext <<EOF +#line 1841 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1847: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +for ac_hdr in poll.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1875: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1880 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1885: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +echo $ac_n "checking for adns_init in -ladns""... $ac_c" 1>&6 +echo "configure:1913: checking for adns_init in -ladns" >&5 +ac_lib_var=`echo adns'_'adns_init | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ladns $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1921 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char adns_init(); + +int main() { +adns_init() +; return 0; } +EOF +if { (eval echo configure:1932: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + + cat >> confdefs.h <<\EOF +#define HAVE_ADNS 1 +EOF + + ADNS_LIBS="liboop-adns.la -ladns" + +else + echo "$ac_t""no" 1>&6 +fi + + +# Extract the first word of "glib-config", so it can be a program name with args. +set dummy glib-config; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1962: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_PROG_GLIB_CONFIG'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$PROG_GLIB_CONFIG"; then + ac_cv_prog_PROG_GLIB_CONFIG="$PROG_GLIB_CONFIG" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_PROG_GLIB_CONFIG="glib-config" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +PROG_GLIB_CONFIG="$ac_cv_prog_PROG_GLIB_CONFIG" +if test -n "$PROG_GLIB_CONFIG"; then + echo "$ac_t""$PROG_GLIB_CONFIG" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -n "$PROG_GLIB_CONFIG" ; then + GLIB_INCLUDES="`glib-config --cflags`" + GLIB_LIBS="liboop-glib.la `glib-config --libs`" + cat >> confdefs.h <<\EOF +#define HAVE_GLIB 1 +EOF + +fi + +# the libwww RPM puts headers here: +echo $ac_n "checking for HTEvent_setRegisterCallback in -lwwwcore""... $ac_c" 1>&6 +echo "configure:1999: checking for HTEvent_setRegisterCallback in -lwwwcore" >&5 +ac_lib_var=`echo wwwcore'_'HTEvent_setRegisterCallback | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lwwwcore -lwwwutils $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2007 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char HTEvent_setRegisterCallback(); + +int main() { +HTEvent_setRegisterCallback() +; return 0; } +EOF +if { (eval echo configure:2018: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + + cat >> confdefs.h <<\EOF +#define HAVE_WWW 1 +EOF + + # This is just a little unpleasant. + WWW_LIBS="liboop-www.la \ + -lwwwapp -lwwwcache -lwwwcore -lwwwdir -lwwwfile -lwwwftp -lwwwgopher \ + -lwwwhtml -lwwwhttp -lwwwinit -lwwwmime -lwwwmux -lwwwnews -lwwwstream \ + -lwwwtelnet -lwwwtrans -lwwwutils -lwwwxml -lwwwzip -lxmlparse -lxmltok -lmd5" + WWW_INCLUDES="-I/usr/include/w3c-libwww" + +else + echo "$ac_t""no" 1>&6 +fi + + + + + + + trap '' 1 2 15 cat > confcache <<\EOF @@ -1961,6 +2225,13 @@ s%@NM@%$NM%g s%@LN_S@%$LN_S%g s%@LIBTOOL@%$LIBTOOL%g s%@PROG_LDCONFIG@%$PROG_LDCONFIG%g +s%@CPP@%$CPP%g +s%@PROG_GLIB_CONFIG@%$PROG_GLIB_CONFIG%g +s%@GLIB_INCLUDES@%$GLIB_INCLUDES%g +s%@GLIB_LIBS@%$GLIB_LIBS%g +s%@ADNS_LIBS@%$ADNS_LIBS%g +s%@WWW_INCLUDES@%$WWW_INCLUDES%g +s%@WWW_LIBS@%$WWW_LIBS%g CEOF EOF diff --git a/configure.in b/configure.in index a6058e181c151e65dd5c054acd845dd7f25403ed..6dc3b7922239ce0104f72efbce3eafec6eaf6a67 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(INSTALL) -AM_INIT_AUTOMAKE(liboop,0.2) +AM_INIT_AUTOMAKE(liboop,0.4) AC_CANONICAL_HOST dnl Use libtool for shared libraries @@ -18,5 +18,35 @@ case "$host" in ;; esac +AC_CHECK_HEADERS(poll.h) + +AC_CHECK_LIB(adns,adns_init,[ + AC_DEFINE(HAVE_ADNS) + ADNS_LIBS="liboop-adns.la -ladns" +]) + +AC_CHECK_PROG(PROG_GLIB_CONFIG,glib-config,glib-config) +if test -n "$PROG_GLIB_CONFIG" ; then + GLIB_INCLUDES="`glib-config --cflags`" + GLIB_LIBS="liboop-glib.la `glib-config --libs`" + AC_DEFINE(HAVE_GLIB) +fi + +# the libwww RPM puts headers here: +AC_CHECK_LIB(wwwcore,HTEvent_setRegisterCallback,[ + AC_DEFINE(HAVE_WWW) + # This is just a little unpleasant. + WWW_LIBS="liboop-www.la \ + -lwwwapp -lwwwcache -lwwwcore -lwwwdir -lwwwfile -lwwwftp -lwwwgopher \ + -lwwwhtml -lwwwhttp -lwwwinit -lwwwmime -lwwwmux -lwwwnews -lwwwstream \ + -lwwwtelnet -lwwwtrans -lwwwutils -lwwwxml -lwwwzip -lxmlparse -lxmltok -lmd5" + WWW_INCLUDES="-I/usr/include/w3c-libwww" +],,-lwwwutils) + AC_SUBST(PROG_LDCONFIG) +AC_SUBST(GLIB_INCLUDES) +AC_SUBST(GLIB_LIBS) +AC_SUBST(ADNS_LIBS) +AC_SUBST(WWW_INCLUDES) +AC_SUBST(WWW_LIBS) AC_OUTPUT(Makefile) diff --git a/foreign/HTEvent.h b/foreign/HTEvent.h new file mode 100644 index 0000000000000000000000000000000000000000..655027623a8b447f3b850fe99cad602c4ef40771 --- /dev/null +++ b/foreign/HTEvent.h @@ -0,0 +1,246 @@ +/* + + W3C Sample Code Library libwww Event Class + + +! + The Event Class +! +*/ + +/* +** (c) COPYRIGHT MIT 1995. +** Please first read the full copyright statement in the file COPYRIGH. +*/ + +/* + +The Event Class defines any event manager to be used by libwww for handling +events. An event is not strictly defined as it is highly platform +dependent and hence out of scope for the Library. If you are using the libwww +pseudo threads on Unix then an event is when the select() system +call returns a notification on a socket descriptor, but it may as well +be an asynchronous event from the windows manager etc. If your application +is not using anything but traditional blocking sockets then you do not need +an event manager at all. In that case, libwww will block on any socket or +system call until the process can proceed. + +The libwww interface to an event manager is very simple as it consists of +registering a socket descriptor, the location in the +program, and the current state when an operation (for example +read) would block. When the event manager at a later point in +time gets a notification that the socket has become ready, it can then call +libwww with the state saved from the registration and libwww can continue. +Second, libwww must be able to unregister a socket when it is not +anymore in a state where it can block. Only in case the application +wishes to use non-blocking sockets it should register methods for +handling the registration process as described below. + +Note: The library core does not define any event manager +- it is considered part of the application. The library comes with a +default event manager which can be initiated +using the function HTEventInit() in HTInit +module + +This module is implemented by HTEvent.c, and it is +a part of the W3C Sample Code Library. +*/ + +#ifndef HTEVENT_H +#define HTEVENT_H +#include "wwwsys.h" +#ifdef IN_EVENT +typedef struct _HTTimer HTTimer; +#endif + +typedef enum _HTPriority { + HT_PRIORITY_INV = -1, + HT_PRIORITY_OFF = 0, + HT_PRIORITY_MIN = 1, + HT_PRIORITY_MAX = 20 +} HTPriority; + +#define HTEVENT_INDEX 0x10 +typedef enum { +#ifdef WWW_WIN_ASYNC + HTEvent_READ = (0x001 | 0 << HTEVENT_INDEX), + HTEvent_WRITE = (0x002 | 1 << HTEVENT_INDEX), + HTEvent_OOB = (0x004 | 2 << HTEVENT_INDEX), + HTEvent_ACCEPT = (0x008 | 3 << HTEVENT_INDEX), + HTEvent_CONNECT = (0x010 | 4 << HTEVENT_INDEX), + HTEvent_CLOSE = (0x020 | 5 << HTEVENT_INDEX), + HTEvent_TYPES = 6, /* winsock has seperate events for all of these */ +#define HTEVENT_TYPES 6 /* use in constructing the fake event below */ +#else /* WWW_WIN_ASYNC */ + HTEvent_READ = (0x001 | 0 << HTEVENT_INDEX), + HTEvent_ACCEPT = (0x002 | 0 << HTEVENT_INDEX), + HTEvent_CLOSE = (0x004 | 0 << HTEVENT_INDEX), + HTEvent_WRITE = (0x008 | 1 << HTEVENT_INDEX), + HTEvent_CONNECT = (0x010 | 1 << HTEVENT_INDEX), + HTEvent_OOB = (0x020 | 2 << HTEVENT_INDEX), + HTEvent_TYPES = 3, /* only READ, WRITE, and OOB are real types */ +#define HTEVENT_TYPES 3 /* use in constructing the fake event below */ +#endif /* !WWW_WIN_ASYNC */ + /* + ** fake events - these don't correspond to event manager events, but they + ** are usefull for communicating with the protocol modules + */ + HTEvent_TIMEOUT = (0x040 | HTEVENT_TYPES << HTEVENT_INDEX), + HTEvent_BEGIN = (0x000 | HTEVENT_TYPES << HTEVENT_INDEX), + HTEvent_END = (0x080 | HTEVENT_TYPES << HTEVENT_INDEX), + HTEvent_FLUSH = (0x100 | HTEVENT_TYPES << HTEVENT_INDEX), + HTEvent_RESET = (0x200 | HTEVENT_TYPES << HTEVENT_INDEX), + HTEvent_ALL = 0xFFFF +} HTEventType; + +#define HTEvent_BITS(type) (type & 0xFFFF) +#define HTEvent_INDEX(type) (type >> HTEVENT_INDEX) + +#define HT_EVENT_INITIALIZER \ + {HTEvent_READ, "HTEvent_READ"}, \ + {HTEvent_ACCEPT, "HTEvent_ACCEPT"}, \ + {HTEvent_CLOSE, "HTEvent_CLOSE"}, \ + {HTEvent_WRITE, "HTEvent_WRITE"}, \ + {HTEvent_CONNECT, "HTEvent_CONNECT"}, \ + {HTEvent_OOB, "HTEvent_OOB"}, \ + {HTEvent_TIMEOUT, "HTEvent_TIMEOUT"}, \ + {HTEvent_BEGIN, "HTEvent_BEGIN"}, \ + {HTEvent_END, "HTEvent_END"}, \ + {HTEvent_FLUSH, "HTEvent_FLUSH"}, \ + {HTEvent_RESET, "HTEvent_RESET"} + +extern char * HTEvent_type2str(HTEventType type); + +/* +. + Event Handlers +. + +A location is a function that can be registered by the event manager +and called at a later point in time in order to continue an operation. All +locations must be of type HTEventCallback as defined here: +*/ + +typedef int HTEventCallback (SOCKET, void *, HTEventType); +typedef struct _HTEvent HTEvent; + +/* Avoid circular include for HTReq->HTNet->HTHost: HTEvent blah */ +#include "HTReq.h" + +/* + +There are many default event handlers provided with the Library. For example, +all the protocol modules such as the HTTP client module +are implemented as event handlers. In stead of using blocking sockets, this +allows a protocol module to register itself when performing an operation +that would block. When the sockets becomes ready the handler is called with +th socket in question, the request object, and the socket operation +. + Registering and Unregistering Events +. + +As mentioned above, the only interface libwww requires from an event manager +is a method to register an event when an operation would block and +unregister it when the operation has completed The library registers +and unregisters events by calling the following two functions: +*/ + +extern int HTEvent_register (SOCKET, HTEventType, HTEvent *); +extern int HTEvent_unregister (SOCKET, HTEventType); + +/* + +The register function contains information about which socket we are waiting +on to get ready and which operation we are waiting for (read, write, etc.), +the request object containing the current request, the event handler that +we want to be called when the socket becomes reasy, and finally the priority +by which we want the thread to be processed by the event manager. Likewise, +libwww can unregister a operation on a socket which means that libwww is +no longer waiting for this actiion to become ready. +. + Registering an Event Manager +. + +Libwww core does not contain any event manager as it depends on whether you +want to use pseudo threads no threads, or real threads. Instead, libwww comes +with a default implementation that you may register, +but you may as well implement and register your own. The register and unregister +functions above actually does nothing than looking for a registered event +manager and then passes the call on to that. You register your own event +manager by using the methods below: +*/ + +typedef int HTEvent_registerCallback(SOCKET, HTEventType, HTEvent *); +typedef int HTEvent_unregisterCallback(SOCKET, HTEventType); + +extern void HTEvent_setRegisterCallback(HTEvent_registerCallback *); +extern void HTEvent_setUnregisterCallback(HTEvent_unregisterCallback *); + +/* +( + Has Register and Unregister Callbacks been setup? +) + +Replies YES if both an HTEvent_setRegisterCallback and +HTEvent_setUnregisterCallback have been called with non NULL callbacks. +*/ + +extern BOOL HTEvent_isCallbacksRegistered(void); + +/* +. + Create and Delete Events +. +*/ + +extern HTEvent * HTEvent_new (HTEventCallback * cbf, void * context, + HTPriority pritority, int timeoutInMillis); +extern BOOL HTEvent_delete (HTEvent * event); + +/* +( + Event Timeouts, Priorities, Callbacks, and Contexts +) + +Normally, these are set when creating the event. +*/ + +extern BOOL HTEvent_setParam(HTEvent * event, void * param); +extern BOOL HTEvent_setPriority(HTEvent * event, HTPriority priority); +extern BOOL HTEvent_setTimeout(HTEvent * event, int timeoutInMillis); +extern BOOL HTEvent_setCallback(HTEvent * event, HTEventCallback * cbf); + +/* +. + The Raw Event Type +. + +Don't use this directly, use the methods above instead. +*/ + +struct _HTEvent { + HTPriority priority; /* Priority of this request (event) */ + int millis; /* Timeout in ms for this event */ +#ifdef IN_EVENT + HTTimer * timer; +#endif + HTEventCallback * cbf; /* Protocol state machine */ + void * param; /* HTEvent_register parameter */ + HTRequest * request; +}; + +/* + +You can register the event manager provided together with libwww by using +the HTEventInit() in the HTInit module +*/ + +#endif /* HTEVENT_H */ + +/* + + + + @(#) $Id: HTEvent.h,v 1.1 1999-10-09 19:05:39 egnor Exp $ + +*/ diff --git a/foreign/README b/foreign/README index b3734283a9805a1e741ba9cb526d8f01af0b5125..78a46829eb1bc7902607378f3d7e9ea6e70fda6e 100644 --- a/foreign/README +++ b/foreign/README @@ -5,7 +5,7 @@ adapters without requiring the presence of the foreign components in question. An adapter will still not function without the code it adapts, of course, but at least this way we eliminate pesky build ordering issues. -Many of these are licensed under specific agreements: +Many of these have specific licensing terms and agreements: adns.h @@ -21,3 +21,36 @@ adns.h and to any files adns.h with similar contents and function I might release during the remainder of this calendar year (1999). +HTEvent.h +HTMemory.h +HTUtils.h + + These header files are extracted from libwww. + Libwww is a general-purpose Web API written in C. + <URL:http://www.w3.org/Library/> + + Libwww code is subject to this copyright: + + Copyright � 1995-1998 World Wide Web Consortium, (Massachusetts Institute + of Technology, Institut National de Recherche en Informatique et en + Automatique, Keio University). All Rights Reserved. This program is + distributed under the W3C's Software Intellectual Property License. This + program is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. + + See W3C License http://www.w3.org/Consortium/Legal/ for more details. + + Copyright � 1995 CERN. "This product includes computer software created and + made available by CERN. This acknowledgment shall be mentioned in full in + any product which includes the CERN computer software included herein or + parts thereof." + +glib.h + + This is the public header file for GLIB, a "library of useful routines + for C programming" used heavily by the popular GTK+ widget set. + <URL:http://www.gtk.org/> + + GLIB is licensed under the GNU Library GPL, version 2. The copyright + is held by Peter Mattis, Spencer Kimball and Josh MacDonald. diff --git a/foreign/adns.h b/foreign/adns.h index 550c6f453c18883841fad3c9751605fafb657b21..bc6d6eb3b6cf3b36dc80998baf8c1ae008125a0e 100644 --- a/foreign/adns.h +++ b/foreign/adns.h @@ -19,7 +19,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * $Id: adns.h,v 1.1 1999-08-09 07:11:52 egnor Exp $ + * $Id: adns.h,v 1.2 1999-10-09 19:05:39 egnor Exp $ */ #ifndef ADNS_H_INCLUDED @@ -32,6 +32,9 @@ extern "C" { /* I really dislike this - iwj. */ #include <sys/socket.h> #include <netinet/in.h> +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> /* All struct in_addr anywhere in adns are in NETWORK byte order. */ @@ -300,6 +303,9 @@ void adns_cancel(adns_query query); * first adns_submit or _transact call using the same adns_state after * it became invalid, so you may compare it for equality with other * query handles until you next call _query or _transact. + * + * _submit and _synchronous return ENOSYS if they don't understand the + * query type. */ void adns_finish(adns_state ads); diff --git a/glib.c b/glib.c new file mode 100644 index 0000000000000000000000000000000000000000..566740a3663b0364fc9d28e5bdaf67db20d11bc7 --- /dev/null +++ b/glib.c @@ -0,0 +1,100 @@ +/* glib.c, liboop, copyright 1999 Dan Egnor + + This is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License, version 2.1 or later. + See the file COPYING for details. */ + +#include "glib.h" +#include "oop-glib.h" +#include "oop.h" + +#include <assert.h> +#include <poll.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + +static int use_count = 0; +static oop_source_sys *sys; +static oop_adapter_select *sel; + +static fd_set read_set,write_set; +static int count; +static void *ret = NULL; + +static void *on_select( + oop_adapter_select *s,int num,fd_set *r,fd_set *w, + struct timeval now,void *x) +{ + read_set = *r; + write_set = *w; + count = num; + return &use_count; +} + +static gint on_poll(GPollFD *array,guint num,gint timeout) { + struct timeval tv; + int i; + + FD_ZERO(&read_set); + FD_ZERO(&write_set); + count = 0; + for (i = 0; i < num; ++i) { + if (array[i].events & G_IO_IN) + FD_SET(array[i].fd,&read_set); + if (array[i].events & G_IO_OUT) + FD_SET(array[i].fd,&write_set); + if (array[i].fd >= count) + count = 1 + array[i].fd; + } + + tv.tv_sec = timeout / 1000; + tv.tv_usec = timeout % 1000; + + oop_select_set(sel,count,&read_set,&write_set,timeout < 0 ? NULL : &tv); + ret = oop_sys_run(sys); + + if (&use_count != ret) { + /* I really wish I could: g_main_quit(glib_loop); */ + return -1; + /* but they even ignore the error return... sigh. */ + } + + for (i = 0; i < num; ++i) { + if (FD_ISSET(array[i].fd,&read_set)) + array[i].revents |= G_IO_IN; + if (FD_ISSET(array[i].fd,&write_set)) + array[i].revents |= G_IO_OUT; + } + + return count; +} + +static gint real_poll(GPollFD *array,guint num,gint timeout) { + assert(sizeof(GPollFD) == sizeof(struct pollfd)); + return poll((struct pollfd *) array,num,timeout); +} + +oop_source *oop_glib_new() { + if (use_count++) return oop_sys_source(sys); + + sys = oop_sys_new(); + sel = oop_select_new(oop_sys_source(sys),on_select,NULL); + g_main_set_poll_func(on_poll); + return oop_sys_source(sys); +} + +void *oop_glib_return() { + if (&use_count == ret) return NULL; + return ret; +} + +void oop_glib_delete() { + assert(use_count > 0 && "oop_glib_delete() called too much"); + if (0 != --use_count) return; + + oop_select_delete(sel); + oop_sys_delete(sys); + g_main_set_poll_func(real_poll); +} diff --git a/oop-adns.h b/oop-adns.h index e702243d26aff56a69cd686c55c1842abf5f0089..82a7a84c8d3e47e3c46e195156cfa29f62dab3ac 100644 --- a/oop-adns.h +++ b/oop-adns.h @@ -8,7 +8,7 @@ #define OOP_ADNS_H #ifndef ADNS_H_INCLUDED -#error You must include "adns.h" before "oop_adns.h"! +#error You must include "adns.h" before "oop-adns.h"! #endif #include "oop.h" diff --git a/oop-glib.h b/oop-glib.h new file mode 100644 index 0000000000000000000000000000000000000000..95776f79642f4cf0eb38203521ecc968c4ec200b --- /dev/null +++ b/oop-glib.h @@ -0,0 +1,25 @@ +/* oop-glib.h, liboop, copyright 1999 Dan Egnor + + This is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License, version 2.1 or later. + See the file COPYING for details. */ + +#ifndef OOP_GLIB_H +#define OOP_GLIB_H + +#ifndef __G_LIB_H__ +#error You must include "glib.h" before "oop-glib.h"! +#endif + +#include "oop.h" + +/* Create an event source based on the GLib event loop. */ +oop_source *oop_glib_new(); + +/* Delete the event source so created. (Uses reference counting.) */ +void oop_glib_delete(); + +/* Get the value used to terminate the event loop (e.g. OOP_HALT). */ +void *oop_glib_return(); + +#endif diff --git a/oop.h b/oop.h index c046f223daa70c3a5a69f7ef677a5ab8b8c9cdc2..ebc8923e92c1e6da1727f3a8603a760137c6c82f 100644 --- a/oop.h +++ b/oop.h @@ -26,6 +26,9 @@ typedef enum { /* Pass this to on_time to schedule an event immediately */ static const struct timeval OOP_TIME_NOW = { 0, 0 }; +/* Maximum signal number. (The OS may have a stricter limit!) */ +#define OOP_NUM_SIGNALS 256 + /* Callbacks may return one of these */ #define OOP_CONTINUE NULL #define OOP_HALT ((void *) 1) /* (or any non-NULL pointer of your choice) */ @@ -37,7 +40,7 @@ typedef void *oop_call_signal(oop_source *,int sig,void *); struct oop_source { void (*on_fd)(oop_source *,int fd,oop_event,oop_call_fd *,void *); - void (*cancel_fd)(oop_source *,int fd,oop_event,oop_call_fd *,void *); + void (*cancel_fd)(oop_source *,int fd,oop_event); void (*on_time)(oop_source *,struct timeval,oop_call_time *,void *); void (*cancel_time)(oop_source *,struct timeval,oop_call_time *,void *); @@ -92,4 +95,13 @@ void oop_select_set( void oop_select_delete(oop_adapter_select *); +/* ------------------------------------------------------------------------- */ + +/* Helper for event sources without signal handling. */ +typedef struct oop_adapter_signal oop_adapter_signal; + +oop_adapter_signal *oop_signal_new(oop_source *); +void oop_signal_delete(oop_adapter_signal *); +oop_source *oop_signal_source(oop_adapter_signal *); + #endif diff --git a/select.c b/select.c index ec86aca094c66950fb9a4b0861580ebfa64ca3c2..9972d653a523303a6db22a4808c0030dd90e2e5e 100644 --- a/select.c +++ b/select.c @@ -77,18 +77,18 @@ void oop_select_set( FD_SET(fd,&s->watch.rfd); } - if (wfd_set && !w_wfd_set) { - s->source->cancel_fd(s->source,fd,OOP_READ,on_fd,s); + if (!rfd_set && w_rfd_set) { + s->source->cancel_fd(s->source,fd,OOP_READ); FD_CLR(fd,&s->watch.rfd); } - if (!rfd_set && w_rfd_set) { + if (wfd_set && !w_wfd_set) { s->source->on_fd(s->source,fd,OOP_WRITE,on_fd,s); FD_SET(fd,&s->watch.wfd); } if (!wfd_set && w_wfd_set) { - s->source->cancel_fd(s->source,fd,OOP_WRITE,on_fd,s); + s->source->cancel_fd(s->source,fd,OOP_WRITE); FD_CLR(fd,&s->watch.wfd); } } @@ -155,12 +155,10 @@ static void *on_timeout(oop_source *source,struct timeval when,void *data) { static void *on_collect(oop_source *source,struct timeval when,void *data) { oop_adapter_select *s = (oop_adapter_select *) data; + struct select_set set = s->active; + int num = s->num_fd_active; struct timeval now; - void *r; - gettimeofday(&now,NULL); - r = s->call(s,s->num_fd_active,&s->active.rfd,&s->active.wfd,now,s->data); deactivate(s); - - return r; + return s->call(s,num,&set.rfd,&set.wfd,now,s->data); } diff --git a/sys.c b/sys.c index 14495d4942ddd725cfb53cf1d8a3724a3e64e53a..442b1f306011d0d37d8e125d34adbad2038fe83c 100644 --- a/sys.c +++ b/sys.c @@ -16,7 +16,6 @@ #include <setjmp.h> #define MAGIC 0x9643 -#define NUM_SIGNALS 256 struct sys_time { struct sys_time *next; @@ -54,7 +53,7 @@ struct oop_source_sys { struct sys_time *time_queue,*time_run; /* Signal handling */ - struct sys_signal sig[NUM_SIGNALS]; + struct sys_signal sig[OOP_NUM_SIGNALS]; sigjmp_buf env; int do_jmp,sig_active; @@ -63,7 +62,7 @@ struct oop_source_sys { sys_file *files; }; -struct oop_source_sys *sys_sig_owner[NUM_SIGNALS]; +struct oop_source_sys *sys_sig_owner[OOP_NUM_SIGNALS]; static oop_source_sys *verify_source(oop_source *source) { oop_source_sys *sys = (oop_source_sys *) source; @@ -94,11 +93,9 @@ static void sys_on_fd(oop_source *source,int fd,oop_event ev, ++sys->num_events; } -static void sys_cancel_fd(oop_source *source,int fd,oop_event ev, - oop_call_fd *f,void *v) { +static void sys_cancel_fd(oop_source *source,int fd,oop_event ev) { oop_source_sys *sys = verify_source(source); - if (fd < sys->num_files && NULL != f - && f == sys->files[fd][ev].f && v == sys->files[fd][ev].v) { + if (fd < sys->num_files && NULL != sys->files[fd][ev].f) { sys->files[fd][ev].f = NULL; --sys->num_events; } @@ -179,7 +176,7 @@ static void sys_on_signal(oop_source *source,int sig, struct sys_signal_handler *handler = oop_malloc(sizeof(*handler)); if (NULL == handler) return; /* ugh */ - assert(sig > 0 && sig < NUM_SIGNALS && "invalid signal number"); + assert(sig > 0 && sig < OOP_NUM_SIGNALS && "invalid signal number"); handler->f = f; handler->v = v; @@ -205,25 +202,26 @@ static void sys_on_signal(oop_source *source,int sig, static void sys_cancel_signal(oop_source *source,int sig, oop_call_signal *f,void *v) { oop_source_sys *sys = verify_source(source); - struct sys_signal_handler *p,**pp = &sys->sig[sig].list; + struct sys_signal_handler **pp = &sys->sig[sig].list; - assert(sig > 0 && sig < NUM_SIGNALS && "invalid signal number"); + assert(sig > 0 && sig < OOP_NUM_SIGNALS && "invalid signal number"); while (NULL != *pp && ((*pp)->f != f || (*pp)->v != v)) pp = &(*pp)->next; if (NULL != *pp) { - p = *pp; - *pp = p->next; - if (sys->sig[sig].ptr == p) sys->sig[sig].ptr = *pp; - --sys->num_events; - oop_free(p); + struct sys_signal_handler *p = *pp; - if (NULL == sys->sig[sig].list) { + if (NULL == p->next && &sys->sig[sig].list == pp) { sigaction(sig,&sys->sig[sig].old,NULL); sys->sig[sig].active = 0; sys_sig_owner[sig] = NULL; } + + *pp = p->next; + if (sys->sig[sig].ptr == p) sys->sig[sig].ptr = *pp; + --sys->num_events; + oop_free(p); } } @@ -244,7 +242,7 @@ oop_source_sys *oop_sys_new(void) { source->do_jmp = 0; source->sig_active = 0; - for (i = 0; i < NUM_SIGNALS; ++i) { + for (i = 0; i < OOP_NUM_SIGNALS; ++i) { source->sig[i].list = NULL; source->sig[i].ptr = NULL; source->sig[i].active = 0; @@ -324,7 +322,7 @@ void *oop_sys_run(oop_source_sys *sys) { if (sys->sig_active) { sys->sig_active = 0; - for (i = 0; NULL == ret && i < NUM_SIGNALS; ++i) { + for (i = 0; NULL == ret && i < OOP_NUM_SIGNALS; ++i) { if (sys->sig[i].active) { sys->sig[i].active = 0; sys->sig[i].ptr = sys->sig[i].list; @@ -332,8 +330,8 @@ void *oop_sys_run(oop_source_sys *sys) { while (NULL == ret && NULL != sys->sig[i].ptr) { struct sys_signal_handler *h; h = sys->sig[i].ptr; - ret = h->f(&sys->oop,i,h->v); sys->sig[i].ptr = h->next; + ret = h->f(&sys->oop,i,h->v); } } if (NULL != ret) { @@ -387,7 +385,7 @@ void oop_sys_delete(oop_source_sys *sys) { && NULL == sys->time_run && "cannot delete with timeout"); - for (i = 0; i < NUM_SIGNALS; ++i) + for (i = 0; i < OOP_NUM_SIGNALS; ++i) assert(NULL == sys->sig[i].list && "cannot delete with signal handler"); for (i = 0; i < sys->num_files; ++i) diff --git a/test-oop.c b/test-oop.c index bd021ae6edf937cc57d9d07efbe3b99a9ebc4550..38edbbcef718043bc8434dc3da126f372c30ccd1 100644 --- a/test-oop.c +++ b/test-oop.c @@ -1,22 +1,63 @@ +/* test-oop.c, liboop, copyright 1999 Dan Egnor + + This is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License, version 2.1 or later. + See the file COPYING for details. */ + #include <stdio.h> +#include <assert.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> #include <sys/time.h> +#include <arpa/inet.h> + #include "oop.h" +#ifdef HAVE_GLIB +#include <glib.h> +#include "oop-glib.h" +GMainLoop *glib_loop; +#endif + struct timer { struct timeval tv; int delay; }; +static oop_source_sys *source_sys; +static oop_adapter_signal *source_signal; + +static void usage(void) { + fputs( +"usage: test-oop <source> <sink> [<sink> ...]\n" +"sources: sys system event source\n" +" signal system event source with signal adapter\n" +#ifdef HAVE_GLIB +" glib GLib source adapter\n" +#endif +"sinks: timer some timers\n" +" echo a stdin->stdout copy\n" +" signal some signal handlers\n" +#ifdef HAVE_ADNS +" adns some asynchronous DNS lookups\n" +#endif +#ifdef HAVE_WWW +" libwww some HTTP GET operations\n" +#endif + ,stderr); + exit(1); +} + +/* -- timer ---------------------------------------------------------------- */ + oop_call_time on_timer; void *on_timer(oop_source *source,struct timeval tv,void *data) { struct timer *timer = (struct timer *) data; timer->tv = tv; timer->tv.tv_sec += timer->delay; source->on_time(source,timer->tv,on_timer,data); - printf("This message should be output once every "); + printf("timer: once every "); if (1 == timer->delay) printf("second\n"); else printf("%d seconds\n",timer->delay); return OOP_CONTINUE; @@ -26,7 +67,7 @@ oop_call_signal stop_timer; void *stop_timer(oop_source *source,int sig,void *data) { struct timer *timer = (struct timer *) data; source->cancel_time(source,timer->tv,on_timer,timer); - source->cancel_signal(source,SIGINT,stop_timer,timer); + source->cancel_signal(source,SIGQUIT,stop_timer,timer); return OOP_CONTINUE; } @@ -34,42 +75,323 @@ void add_timer(oop_source *source,int interval) { struct timer *timer = malloc(sizeof(*timer)); gettimeofday(&timer->tv,NULL); timer->delay = interval; - source->on_signal(source,SIGINT,stop_timer,timer); + source->on_signal(source,SIGQUIT,stop_timer,timer); on_timer(source,timer->tv,timer); } -oop_call_fd on_data; -void *on_data(oop_source *source,int fd,oop_event event,void *data) { +/* -- echo ----------------------------------------------------------------- */ + +static oop_call_fd on_data; +static void *on_data(oop_source *source,int fd,oop_event event,void *data) { char buf[BUFSIZ]; int r = read(fd,buf,sizeof(buf)); write(1,buf,r); return OOP_CONTINUE; } -oop_call_signal stop_data; -void *stop_data(oop_source *source,int sig,void *data) { - source->cancel_fd(source,0,OOP_READ,on_data,NULL); - source->cancel_signal(source,SIGINT,stop_data,NULL); +static oop_call_signal stop_data; +static void *stop_data(oop_source *source,int sig,void *data) { + source->cancel_fd(source,0,OOP_READ); + source->cancel_signal(source,SIGQUIT,stop_data,NULL); + return OOP_CONTINUE; +} + +/* -- signal --------------------------------------------------------------- */ + +static oop_call_signal on_signal; +static void *on_signal(oop_source *source,int sig,void *data) { + switch (sig) { + case SIGINT: + puts("signal: SIGINT (control-C) caught. " + "(Use SIGQUIT, control-\\, to terminate.)"); + break; + case SIGQUIT: + puts("signal: SIGQUIT (control-\\) caught, terminating."); + source->cancel_signal(source,SIGINT,on_signal,NULL); + source->cancel_signal(source,SIGQUIT,on_signal,NULL); + break; + default: + assert(0 && "unknown signal?"); + } + return OOP_CONTINUE; +} + +/* -- adns ----------------------------------------------------------------- */ + +#ifdef HAVE_ADNS + +#include "adns.h" +#include "oop-adns.h" + +#define NUM_Q 6 +oop_adns_query *q[NUM_Q]; +oop_adapter_adns *adns; + +void *stop_lookup(oop_source *src,int sig,void *data) { + int i; + + for (i = 0; i < NUM_Q; ++i) + if (NULL != q[i]) { + oop_adns_cancel(q[i]); + q[i] = NULL; + } + + if (NULL != adns) { + oop_adns_delete(adns); + adns = NULL; + } + + src->cancel_signal(src,SIGQUIT,stop_lookup,NULL); return OOP_CONTINUE; } -oop_call_signal on_intr; -void *on_intr(oop_source *source,int sig,void *data) { - puts("SIGINT (control-C) received, terminating!"); - source->cancel_signal(source,SIGINT,on_intr,NULL); +void *on_lookup(oop_adapter_adns *adns,adns_answer *reply,void *data) { + int i; + for (i = 0; i < NUM_Q; ++i) if (data == &q[i]) q[i] = NULL; + + printf("adns: %s =>",reply->owner); + if (adns_s_ok != reply->status) { + printf(" error: %s\n",adns_strerror(reply->status)); + return OOP_CONTINUE; + } + if (NULL != reply->cname) printf(" (%s)",reply->cname); + assert(adns_r_a == reply->type); + for (i = 0; i < reply->nrrs; ++i) + printf(" %s",inet_ntoa(reply->rrs.inaddr[i])); + printf("\n"); + free(reply); + return OOP_CONTINUE; } -int main(void) { - oop_source_sys *sys = oop_sys_new(); - oop_source *src = oop_sys_source(sys); - add_timer(src,1); - add_timer(src,2); - add_timer(src,3); - src->on_fd(src,0,OOP_READ,on_data,NULL); - src->on_signal(src,SIGINT,stop_data,NULL); - src->on_signal(src,SIGINT,on_intr,NULL); - oop_sys_run(sys); - oop_sys_delete(sys); +static void get_name(int i,const char *name) { + q[i] = oop_adns_submit( + adns,name,adns_r_a,adns_qf_owner, + on_lookup,&q[i]); +} + +static void add_adns(oop_source *src) { + adns = oop_adns_new(src,0,NULL); + get_name(0,"g.mp"); + get_name(1,"cnn.com"); + get_name(2,"slashdot.org"); + get_name(3,"love.ugcs.caltech.edu"); + get_name(4,"intel.ugcs.caltech.edu"); + get_name(5,"ofb.net"); + src->on_signal(src,SIGQUIT,stop_lookup,NULL); +} + +#else + +static void add_adns(oop_source *src) { + fputs("sorry, adns not available\n",stderr); + usage(); +} + +#endif + +/* -- libwww --------------------------------------------------------------- */ + +#ifdef HAVE_WWW + +/* Yuck: */ +#define HAVE_CONFIG_H +#undef PACKAGE +#undef VERSION + +#include "oop.h" +#include "HTEvent.h" +#include "oop-www.h" + +#include "WWWLib.h" +#include "WWWInit.h" + +static int remaining = 0; + +static int on_print(const char *fmt,va_list args) { + return (vfprintf(stdout,fmt,args)); +} + +static int on_trace (const char *fmt,va_list args) { + return (vfprintf(stderr,fmt,args)); +} + +static int on_complete(HTRequest *req,HTResponse *resp,void *x,int status) { + HTChunk *chunk = (HTChunk *) HTRequest_context(req); + char *address = HTAnchor_address((HTAnchor *) HTRequest_anchor(req)); + + HTPrint("%d: done with %s\n",status,address); + HTMemory_free(address); + HTRequest_delete(req); + + if (NULL != chunk) HTChunk_delete(chunk); + + if (0 == --remaining) { + /* stop ... */ + } + + return HT_OK; +} + +static void get_uri(const char *uri) { + HTRequest *req = HTRequest_new(); + HTRequest_setOutputFormat(req, WWW_SOURCE); + HTRequest_setContext(req,HTLoadToChunk(uri,req)); + ++remaining; +} + +static void *stop_www(oop_source *source,int sig,void *x) { + oop_www_cancel(); + HTProfile_delete(); + source->cancel_signal(source,sig,stop_www,x); + return OOP_CONTINUE; +} + +void add_www(oop_source *source) { + puts("libwww: known bug: termination (^\\) may abort due to cached " + "connections, sorry."); + HTProfile_newNoCacheClient("test-www","1.0"); + oop_www_register(source); + + HTPrint_setCallback(on_print); + HTTrace_setCallback(on_trace); + + HTNet_addAfter(on_complete, NULL, NULL, HT_ALL, HT_FILTER_LAST); + HTAlert_setInteractive(NO); + + get_uri("http://ofb.net/~egnor/oop/"); + get_uri("http://ofb.net/does.not.exist"); + get_uri("http://slashdot.org/"); + get_uri("http://www.w3.org/Library/"); + get_uri("http://does.not.exist/"); + + source->on_signal(source,SIGQUIT,stop_www,NULL); +} + +#else + +void add_www(oop_source *source) { + fputs("sorry, libwww not available\n",stderr); + usage(); +} + +#endif + +/* -- core ----------------------------------------------------------------- */ + +static void *stop_loop_delayed(oop_source *source,struct timeval tv,void *x) { + return OOP_HALT; +} + +static void *stop_loop(oop_source *source,int sig,void *x) { + /* give everyone else a chance to shut down. */ + source->on_time(source,OOP_TIME_NOW,stop_loop_delayed,NULL); + source->cancel_signal(source,SIGQUIT,stop_loop,NULL); + return OOP_CONTINUE; +} + +static oop_source *create_source(const char *name) { + if (!strcmp(name,"sys")) { + source_sys = oop_sys_new(); + return oop_sys_source(source_sys); + } + + if (!strcmp(name,"signal")) { + source_sys = oop_sys_new(); + source_signal = oop_signal_new(oop_sys_source(source_sys)); + return oop_signal_source(source_signal); + } + +#ifdef HAVE_GLIB + if (!strcmp(name,"glib")) { + puts("glib: known bug: termination (^\\) won't quit, sorry."); + glib_loop = g_main_new(FALSE); + return oop_glib_new(); + } +#endif + + fprintf(stderr,"unknown source \"%s\"\n",name); + usage(); + return NULL; +} + +static void run_source(const char *name) { + if (!strcmp(name,"sys") + || !strcmp(name,"signal")) + oop_sys_run(source_sys); + +#ifdef HAVE_GLIB + if (!strcmp(name,"glib")) + g_main_run(glib_loop); +#endif +} + +static void delete_source(const char *name) { + if (!strcmp(name,"sys")) + oop_sys_delete(source_sys); + if (!strcmp(name,"signal")) { + oop_signal_delete(source_signal); + oop_sys_delete(source_sys); + } + +#ifdef HAVE_GLIB + if (!strcmp(name,"glib")) { + oop_glib_delete(); + g_main_destroy(glib_loop); + } +#endif +} + +static void add_sink(oop_source *src,const char *name) { + if (!strcmp(name,"timer")) { + add_timer(src,1); + add_timer(src,2); + add_timer(src,3); + return; + } + + if (!strcmp(name,"echo")) { + src->on_fd(src,0,OOP_READ,on_data,NULL); + src->on_signal(src,SIGQUIT,stop_data,NULL); + return; + } + + if (!strcmp(name,"signal")) { + src->on_signal(src,SIGINT,on_signal,NULL); + src->on_signal(src,SIGQUIT,on_signal,NULL); + return; + } + +#ifdef HAVE_ADNS + if (!strcmp(name,"adns")) { + add_adns(src); + return; + } +#endif + +#ifdef HAVE_WWW + if (!strcmp(name,"libwww")) { + add_www(src); + return; + } +#endif + + fprintf(stderr,"unknown sink \"%s\"\n",name); + usage(); +} + +int main(int argc,char *argv[]) { + oop_source *source; + int i; + + if (argc < 3) usage(); + puts("test-oop: use ^\\ (SIGQUIT) for clean shutdown"); + source = create_source(argv[1]); + source->on_signal(source,SIGQUIT,stop_loop,NULL); + for (i = 2; i < argc; ++i) + add_sink(source,argv[i]); + + run_source(argv[1]); + delete_source(argv[1]); return 0; } diff --git a/www.c b/www.c new file mode 100644 index 0000000000000000000000000000000000000000..3ae6eb78ec9dca95403eaa39687102b074819021 --- /dev/null +++ b/www.c @@ -0,0 +1,185 @@ +/* www.c, liboop, copyright 1999 Dan Egnor + + This is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License, version 2.1 or later. + See the file COPYING for details. */ + +/* Yecch: the libwww header files need this. */ +#define HAVE_CONFIG_H +#undef PACKAGE +#undef VERSION + +#include <stdarg.h> /* Needed for our cut-down libwww headers. */ + +#include "oop.h" +#include "HTEvent.h" +#include "HTMemory.h" +#include "oop-www.h" + +#include <assert.h> + +struct event { + HTEvent *event; + struct timeval time; +}; + +typedef struct event descriptor[HTEvent_TYPES]; + +static int num = 0,size = 0; +static descriptor *array = NULL; +static oop_source *oop = NULL; + +static struct event *get_event(SOCKET sock,HTEventType type) { + assert(sock < size && "invalid file descriptor"); + return &array[sock][HTEvent_INDEX(type)]; +} + +static void *on_time(oop_source *s,struct timeval tv,void *x) { + struct event *event; + SOCKET sock = (int) x; + int j; + + for (j = 0; j < HTEvent_TYPES; ++j) { + event = &array[sock][j]; + if (NULL != event->event && 0 <= event->event->millis + && tv.tv_sec == event->time.tv_sec + && tv.tv_usec == event->time.tv_usec) + break; + } + + assert(j < HTEvent_TYPES); + event->event->cbf(sock,event->event->param,HTEvent_TIMEOUT); + return OOP_CONTINUE; +} + +static void set_timer(struct event *event) { + if (0 <= event->event->millis) { + gettimeofday(&event->time,NULL); + event->time.tv_sec += event->event->millis / 1000; + event->time.tv_usec += event->event->millis % 1000; + if (event->time.tv_usec > 1000000) { + event->time.tv_usec -= 1000000; + ++event->time.tv_sec; + } + oop->on_time(oop,event->time,on_time,event); + } +} + +static void *on_fd(oop_source *s,int fd,oop_event type,void *x) { + HTEventType www_type; + struct event *event; + + switch (type) { + case OOP_READ: + www_type = HTEvent_READ; + break; + case OOP_WRITE: + www_type = HTEvent_WRITE; + break; + default: + assert(0); + } + + event = get_event(fd,www_type); + if (0 <= event->event->millis) { + oop->cancel_time(oop,event->time,on_time,event); + set_timer(event); + } + event->event->cbf(fd,event->event->param,www_type); + return OOP_CONTINUE; +} + +static void dereg(SOCKET sock,HTEventType www_type,oop_event oop_type) { + struct event *event = get_event(sock,www_type); + assert(sock < size && "invalid file descriptor"); + if (NULL != event->event) { + --num; + oop->cancel_fd(oop,sock,oop_type); + if (0 <= event->event->millis) + oop->cancel_time(oop,event->time,on_time,event); + event->event = NULL; + } +} + +static int reg(SOCKET sock,HTEventType type,HTEvent *www_event) { + oop_event oop_type; + struct event *event; + + switch (HTEvent_INDEX(type)) { + case HTEvent_INDEX(HTEvent_READ): + oop_type = OOP_READ; + break; + case HTEvent_INDEX(HTEvent_WRITE): + oop_type = OOP_WRITE; + break; + case HTEvent_INDEX(HTEvent_OOB): + // XXX: we don't handle this; does anything use it? + return HT_ERROR; + default: + assert(0 && "invalid HTEvent type specified"); + } + + if (sock >= size) { + int newsize = size ? (2*size) : 16; + descriptor *newarray = oop_malloc(sizeof(*newarray) * newsize); + int i,j; + + if (NULL == newarray) return HT_ERROR; + + memcpy(newarray,array,sizeof(*newarray) * size); + for (i = size; i < newsize; ++i) + for (j = 0; j < HTEvent_TYPES; ++j) { + newarray[i][j].event = NULL; + } + + array = newarray; + size = newsize; + } + + dereg(sock,type,oop_type); + event = get_event(sock,type); + event->event = www_event; + oop->on_fd(oop,sock,oop_type,on_fd,NULL); + set_timer(event); + ++num; + + return HT_OK; +} + +static int unreg(SOCKET sock,HTEventType type) { + oop_event oop_type; + switch (HTEvent_INDEX(type)) { + case HTEvent_INDEX(HTEvent_READ): + oop_type = OOP_READ; + break; + case HTEvent_INDEX(HTEvent_WRITE): + oop_type = OOP_WRITE; + break; + case HTEvent_INDEX(HTEvent_OOB): + // XXX: we don't handle this; does anything use it? + return HT_ERROR; + default: + assert(0 && "invalid HTEvent type specified"); + } + + dereg(sock,type,oop_type); + return HT_OK; +} + +void oop_www_register(oop_source *source) { + oop = source; + HTEvent_setRegisterCallback(reg); + HTEvent_setUnregisterCallback(unreg); +} + +void oop_www_cancel() { + assert(0 == num && "cannot unregister with pending libwww events"); + HTEvent_setRegisterCallback(NULL); + HTEvent_setUnregisterCallback(NULL); + oop = NULL; +} + +void oop_www_memory() { + oop_malloc = HTMemory_malloc; + oop_free = HTMemory_free; +}