From 3f558de30a8202a0820dbf327ca0361b258231c3 Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Thu, 19 Aug 2010 14:30:11 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create tag 'glite-lb_R_1_10_0_2'. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Sprout from branch_RC31_3 2010-08-19 14:30:10 UTC Zdeněk Å ustr 'New age for the subsys' Cherrypick from master 2010-06-25 09:08:51 UTC Michal Voců 'plugin framework fixes': org.glite.lb.harvester/doc/INSTALL org.glite.lb.harvester/doc/README org.glite.lb.harvester/doc/glite-lb-harvester.sgml org.glite.lb.harvester/examples/test.sql org.glite.lb.harvester/project/package.summary org.glite.lb.logger/Makefile org.glite.lb.logger/config/startup org.glite.lb.logger/configure org.glite.lb.logger/doc/glite-lb-interlogd.8 org.glite.lb.logger/doc/glite-lb-logd.8 org.glite.lb.logger/interface/il_error.h org.glite.lb.logger/interface/interlogd.h org.glite.lb.logger/project/ChangeLog org.glite.lb.logger/project/package.description org.glite.lb.logger/project/package.summary org.glite.lb.logger/project/version.properties org.glite.lb.logger/src-nt/Connection.H org.glite.lb.logger/src-nt/Connection.cpp org.glite.lb.logger/src-nt/EventManager.H org.glite.lb.logger/src-nt/EventManager.cpp org.glite.lb.logger/src-nt/Exception.H org.glite.lb.logger/src-nt/HTTPTransport.H org.glite.lb.logger/src-nt/HTTPTransport.cpp org.glite.lb.logger/src-nt/InputChannel.H org.glite.lb.logger/src-nt/InputChannel.cpp org.glite.lb.logger/src-nt/Makefile org.glite.lb.logger/src-nt/Message.H org.glite.lb.logger/src-nt/MessageStore.H org.glite.lb.logger/src-nt/MessageStore.cpp org.glite.lb.logger/src-nt/PlainConnection.H org.glite.lb.logger/src-nt/PlainConnection.cpp org.glite.lb.logger/src-nt/PluginManager.H org.glite.lb.logger/src-nt/PluginManager.cpp org.glite.lb.logger/src-nt/Properties.H org.glite.lb.logger/src-nt/Singleton.H org.glite.lb.logger/src-nt/SocketInput.H org.glite.lb.logger/src-nt/SocketInput.cpp org.glite.lb.logger/src-nt/ThreadPool.H org.glite.lb.logger/src-nt/ThreadPool.cpp org.glite.lb.logger/src-nt/Transport.H org.glite.lb.logger/src-nt/Transport.cpp org.glite.lb.logger/src-nt/main.cpp org.glite.lb.logger/src-nt/test/EventManagerTest.cpp org.glite.lb.logger/src-nt/test/PluginManagerTest.cpp org.glite.lb.logger/src-nt/test/SingletonTest.cpp org.glite.lb.logger/src-nt/test/ThreadPoolTest.cpp org.glite.lb.logger/src-nt/test/test_main.cpp org.glite.lb.logger/src/activemq_cpp_plugin.cpp org.glite.lb.logger/src/event_queue.c org.glite.lb.logger/src/event_store.c org.glite.lb.logger/src/event_store_http.c org.glite.lb.logger/src/http.c org.glite.lb.logger/src/il_error.c org.glite.lb.logger/src/il_master.c org.glite.lb.logger/src/input_queue_socket.c org.glite.lb.logger/src/input_queue_socket_http.c org.glite.lb.logger/src/interlogd.c org.glite.lb.logger/src/logd.c org.glite.lb.logger/src/logd_proto.c org.glite.lb.logger/src/logd_proto.h org.glite.lb.logger/src/perftest_il.sh org.glite.lb.logger/src/perftest_ll.sh org.glite.lb.logger/src/plugin_mgr.c org.glite.lb.logger/src/queue_mgr.c org.glite.lb.logger/src/queue_mgr_http.c org.glite.lb.logger/src/queue_thread.c org.glite.lb.logger/src/recover.c org.glite.lb.logger/src/send_event.c org.glite.lb.logger/src/send_event_http.c org.glite.lb.logger/src/server_msg.c org.glite.lb.logger/src/server_msg_http.c org.glite.lb.logger/test/IlTestBase.cpp org.glite.lb.logger/test/IlTestBase.h org.glite.lb.logger/test/event_queueTest.cpp org.glite.lb.logger/test/event_storeTest.cpp org.glite.lb.logger/test/il_test.cpp org.glite.lb.logger/test/input_queue_socketTest.cpp org.glite.lb.logger/test/ll_test.cpp org.glite.lb.logger/test/logd_proto_test.c org.glite.lb.logger/test/server_msgTest.cpp Cherrypick from master 2010-03-10 12:17:51 UTC Zdeněk Å ustr 'The most recent version copied. Do not modify this instance (RW in ./org.glite.lb).': org.glite.lb.harvester/Makefile org.glite.lb.harvester/configure org.glite.lb.harvester/examples/test.sh org.glite.lb.harvester/project/ChangeLog org.glite.lb.harvester/project/package.description org.glite.lb.harvester/project/version.properties org.glite.lb.harvester/src/harvester.c Delete: org.glite.lb.logger/src/il_error.h org.glite.lb.logger/src/interlogd.h --- org.glite.lb.harvester/Makefile | 89 + org.glite.lb.harvester/configure | 789 ++++++ org.glite.lb.harvester/doc/INSTALL | 42 + org.glite.lb.harvester/doc/README | 81 + org.glite.lb.harvester/doc/glite-lb-harvester.sgml | 480 ++++ org.glite.lb.harvester/examples/test.sh | 876 +++++++ org.glite.lb.harvester/examples/test.sql | 55 + org.glite.lb.harvester/project/ChangeLog | 20 + org.glite.lb.harvester/project/package.description | 3 + org.glite.lb.harvester/project/package.summary | 1 + org.glite.lb.harvester/project/version.properties | 2 + org.glite.lb.harvester/src/harvester.c | 2691 ++++++++++++++++++++ org.glite.lb.logger/Makefile | 124 +- org.glite.lb.logger/config/startup | 92 +- org.glite.lb.logger/configure | 843 ++++++ org.glite.lb.logger/doc/glite-lb-interlogd.8 | 18 +- org.glite.lb.logger/doc/glite-lb-logd.8 | 18 +- org.glite.lb.logger/interface/il_error.h | 49 + org.glite.lb.logger/{src => interface}/interlogd.h | 120 +- org.glite.lb.logger/project/ChangeLog | 59 +- org.glite.lb.logger/project/package.description | 1 + org.glite.lb.logger/project/package.summary | 1 + org.glite.lb.logger/project/version.properties | 4 +- org.glite.lb.logger/src-nt/Connection.H | 19 + org.glite.lb.logger/src-nt/Connection.cpp | 21 + org.glite.lb.logger/src-nt/EventManager.H | 130 +- org.glite.lb.logger/src-nt/EventManager.cpp | 40 + org.glite.lb.logger/src-nt/Exception.H | 23 + org.glite.lb.logger/src-nt/HTTPTransport.H | 46 +- org.glite.lb.logger/src-nt/HTTPTransport.cpp | 149 +- org.glite.lb.logger/src-nt/InputChannel.H | 46 + org.glite.lb.logger/src-nt/InputChannel.cpp | 54 + org.glite.lb.logger/src-nt/Makefile | 21 +- org.glite.lb.logger/src-nt/Message.H | 83 + org.glite.lb.logger/src-nt/MessageStore.H | 101 + org.glite.lb.logger/src-nt/MessageStore.cpp | 41 + org.glite.lb.logger/src-nt/PlainConnection.H | 26 +- org.glite.lb.logger/src-nt/PlainConnection.cpp | 24 +- org.glite.lb.logger/src-nt/PluginManager.H | 19 + org.glite.lb.logger/src-nt/PluginManager.cpp | 20 + org.glite.lb.logger/src-nt/Properties.H | 53 + org.glite.lb.logger/src-nt/Singleton.H | 17 + org.glite.lb.logger/src-nt/SocketInput.H | 17 + org.glite.lb.logger/src-nt/SocketInput.cpp | 33 +- org.glite.lb.logger/src-nt/ThreadPool.H | 19 + org.glite.lb.logger/src-nt/ThreadPool.cpp | 77 +- org.glite.lb.logger/src-nt/Transport.H | 46 +- org.glite.lb.logger/src-nt/Transport.cpp | 22 + org.glite.lb.logger/src-nt/main.cpp | 26 +- .../src-nt/test/EventManagerTest.cpp | 44 + .../src-nt/test/PluginManagerTest.cpp | 17 + org.glite.lb.logger/src-nt/test/SingletonTest.cpp | 17 + org.glite.lb.logger/src-nt/test/ThreadPoolTest.cpp | 19 +- org.glite.lb.logger/src-nt/test/test_main.cpp | 17 + org.glite.lb.logger/src/activemq_cpp_plugin.cpp | 400 +++ org.glite.lb.logger/src/event_queue.c | 137 +- org.glite.lb.logger/src/event_store.c | 870 +++++-- org.glite.lb.logger/src/event_store_http.c | 1130 ++++++++ org.glite.lb.logger/src/http.c | 214 ++ org.glite.lb.logger/src/il_error.c | 35 +- org.glite.lb.logger/src/il_error.h | 34 - org.glite.lb.logger/src/il_master.c | 199 +- org.glite.lb.logger/src/input_queue_socket.c | 97 +- org.glite.lb.logger/src/input_queue_socket_http.c | 184 ++ org.glite.lb.logger/src/interlogd.c | 324 ++- org.glite.lb.logger/src/logd.c | 384 +-- org.glite.lb.logger/src/logd_proto.c | 395 ++- org.glite.lb.logger/src/logd_proto.h | 31 +- org.glite.lb.logger/src/perftest_il.sh | 76 +- org.glite.lb.logger/src/perftest_ll.sh | 18 +- org.glite.lb.logger/src/plugin_mgr.c | 88 + org.glite.lb.logger/src/queue_mgr.c | 33 +- org.glite.lb.logger/src/queue_mgr_http.c | 181 ++ org.glite.lb.logger/src/queue_thread.c | 101 +- org.glite.lb.logger/src/recover.c | 75 +- org.glite.lb.logger/src/send_event.c | 107 +- org.glite.lb.logger/src/send_event_http.c | 299 +++ org.glite.lb.logger/src/server_msg.c | 55 +- org.glite.lb.logger/src/server_msg_http.c | 145 ++ org.glite.lb.logger/test/IlTestBase.cpp | 17 + org.glite.lb.logger/test/IlTestBase.h | 17 + org.glite.lb.logger/test/event_queueTest.cpp | 17 + org.glite.lb.logger/test/event_storeTest.cpp | 17 + org.glite.lb.logger/test/il_test.cpp | 17 + .../test/input_queue_socketTest.cpp | 17 + org.glite.lb.logger/test/ll_test.cpp | 17 + org.glite.lb.logger/test/logd_proto_test.c | 17 + org.glite.lb.logger/test/server_msgTest.cpp | 17 + 88 files changed, 12220 insertions(+), 1290 deletions(-) create mode 100644 org.glite.lb.harvester/Makefile create mode 100755 org.glite.lb.harvester/configure create mode 100644 org.glite.lb.harvester/doc/INSTALL create mode 100644 org.glite.lb.harvester/doc/README create mode 100644 org.glite.lb.harvester/doc/glite-lb-harvester.sgml create mode 100755 org.glite.lb.harvester/examples/test.sh create mode 100644 org.glite.lb.harvester/examples/test.sql create mode 100644 org.glite.lb.harvester/project/ChangeLog create mode 100644 org.glite.lb.harvester/project/package.description create mode 100644 org.glite.lb.harvester/project/package.summary create mode 100644 org.glite.lb.harvester/project/version.properties create mode 100644 org.glite.lb.harvester/src/harvester.c create mode 100755 org.glite.lb.logger/configure create mode 100644 org.glite.lb.logger/interface/il_error.h rename org.glite.lb.logger/{src => interface}/interlogd.h (67%) create mode 100644 org.glite.lb.logger/project/package.description create mode 100644 org.glite.lb.logger/project/package.summary create mode 100644 org.glite.lb.logger/src-nt/Connection.cpp create mode 100644 org.glite.lb.logger/src-nt/EventManager.cpp create mode 100644 org.glite.lb.logger/src-nt/InputChannel.H create mode 100644 org.glite.lb.logger/src-nt/InputChannel.cpp create mode 100644 org.glite.lb.logger/src-nt/Message.H create mode 100644 org.glite.lb.logger/src-nt/MessageStore.H create mode 100644 org.glite.lb.logger/src-nt/MessageStore.cpp create mode 100644 org.glite.lb.logger/src-nt/Properties.H create mode 100644 org.glite.lb.logger/src-nt/Transport.cpp create mode 100644 org.glite.lb.logger/src/activemq_cpp_plugin.cpp create mode 100644 org.glite.lb.logger/src/event_store_http.c create mode 100644 org.glite.lb.logger/src/http.c delete mode 100644 org.glite.lb.logger/src/il_error.h create mode 100644 org.glite.lb.logger/src/input_queue_socket_http.c create mode 100644 org.glite.lb.logger/src/plugin_mgr.c create mode 100644 org.glite.lb.logger/src/queue_mgr_http.c create mode 100644 org.glite.lb.logger/src/send_event_http.c create mode 100644 org.glite.lb.logger/src/server_msg_http.c diff --git a/org.glite.lb.harvester/Makefile b/org.glite.lb.harvester/Makefile new file mode 100644 index 0000000..15f0b92 --- /dev/null +++ b/org.glite.lb.harvester/Makefile @@ -0,0 +1,89 @@ +top_srcdir=.. +stagedir=. +package=glite-lb-harvester +module.version=0.0.0 +PREFIX=/opt/glite +globus_prefix=/opt/globus + +archlib:=lib +thrflavour:=gcc32dbgpthr +host_cpu:=${shell uname -m} +ifeq (${host_cpu},x86_64) + archlib:=lib64 + thrflavour:=gcc64dbgpthr +endif + +-include Makefile.inc +-include ../project/version.properties +version:=${module.version} + +CC=gcc +VPATH=${top_srcdir}/src:${top_srcdir}/doc + +GLOBUS_CPPFLAGS:=-I${globus_prefix}/include/${thrflavour} +CPPFLAGS:=-I${stagedir}/include -D_GNU_SOURCE -D_REENTRANT ${CPPFLAGS} +CFLAGS:=-W -Wall -g -O2 ${CFLAGS} +LDFLAGS:=${LDFLAGS} +LIBS:=-L${stagedir}/${archlib} -L${stagedir}/lib \ + -lglite_lb_common_${thrflavour} \ + -lglite_lb_client_${thrflavour} \ + -lpthread -lglite_security_gss_${thrflavour} + +ifneq ($(GLITE_LB_HARVESTER_WITH_LBU_DB),no) +CPPFLAGS:=$(CPPFLAGS) -DWITH_LBU_DB=1 +LIBS:=$(LIBS) -lglite_lbu_db +endif +ifeq ($(GLITE_LB_HARVESTER_WITH_OLD_LB),yes) +CPPFLAGS:=${GLOBUS_CPPFLAGS} $(CPPFLAGS) -DWITH_OLD_LB=1 +LIBS:=$(LIBS) -lglite_wmsutils_cjobid +else +LIBS:=$(LIBS) -lglite_jobid -lglite_lbu_trio +endif + +COMPILE:=libtool --mode=compile ${CC} ${CPPFLAGS} ${CFLAGS} +LINK:=libtool --mode=link ${CC} ${LDFLAGS} +INSTALL:=libtool --mode=install install + +default: all + +compile all: harvester doc debug + +check: + +debug: harvester-dbg + +doc: glite-lb-harvester.8 + +stage: compile + $(MAKE) install PREFIX=${stagedir} + +install: compile + -mkdir -p ${PREFIX}/bin ${PREFIX}/examples ${PREFIX}/share/doc/${package}-${version} ${PREFIX}/share/man/man8 + ${INSTALL} -m 755 harvester ${PREFIX}/bin/glite-lb-harvester + ${INSTALL} -m 755 harvester-dbg ${PREFIX}/examples/glite-lb-harvester-dbg + ${INSTALL} -m 755 ../examples/test.sh ${PREFIX}/examples/glite-lb-harvester-test.sh + ${INSTALL} -m 444 ../doc/README ${PREFIX}/share/doc/${package}-${version} + ${INSTALL} -m 444 glite-lb-harvester.8 ${PREFIX}/share/man/man8 + +clean: + rm -rfv *.o *.lo *.loT .libs/ manpage.links manpage.refs + rm -rvf harvester harvester-dbg glite-lb-harvester.* + rm -rvf log.xml project/ rpmbuild/ RPMS/ tgz/ + +harvester: harvester.o + ${LINK} -o $@ $+ ${LIBS} + +harvester-dbg: harvester-dbg.o + ${LINK} -o $@ $+ ${LIBS} + +harvester-dbg.o: harvester.c + ${COMPILE} -DLOG=1 -DWITH_RTM_SQL_STORAGE=1 -c $< -o $@ + +%.o: %.c + ${COMPILE} -c $< + +%.8: %.sgml + docbook2man $< + mv $(@:.8=.1) $@ + +.PHONY: default all compile debug check doc stage install clean diff --git a/org.glite.lb.harvester/configure b/org.glite.lb.harvester/configure new file mode 100755 index 0000000..4ee7639 --- /dev/null +++ b/org.glite.lb.harvester/configure @@ -0,0 +1,789 @@ +#!/usr/bin/perl + +# WARNING: Don't edit this file unless it is the master copy in org.glite.lb +# +# For the purpose of standalone builds of lb/jobid/lbjp-common components +# it is copied on tagging + +# $Header$ + +use Getopt::Long; + +my $pwd = `pwd`; chomp $pwd; +my $prefix = $pwd.'/stage'; +my $stagedir; +my $staged; +my $module; +my $thrflavour = 'gcc64dbgpthr'; +my $nothrflavour = 'gcc64dbg'; +my $mode = 'build'; +my $help = 0; +my $listmodules; +my $version; +my $output; +my $lb_tag = ''; +my $lbjp_tag = ''; +my $jp_tag = ''; +my $sec_tag = ''; +my $jobid_tag = ''; +my $libdir = getlibdir(); + +my @nodes = qw/client server logger utils client-java doc ws-test db jpprimary jpindex jpclient harvester/; +my %enable_nodes; +my %disable_nodes; + +my %extern_prefix = ( + cares => '/opt/c-ares', + classads => '/opt/classads', + cppunit => '/usr', + expat => '/usr', + globus => '/opt/globus', + gsoap => '/usr', + mysql => '/usr', + 'mysql-devel' => '', + 'mysql-server' => '', + voms => '/opt/glite', + gridsite => '/opt/glite', + lcas => '/opt/glite', + trustmanager => '/opt/glite', + ant => '/usr', + jdk => '/usr', + libtar => '/usr', + axis => '/usr', + log4c => '/usr', + postgresql => '/usr' +); + +my %jar = ( + 'commons-codec' => '/usr/share/java/commons-codec.jar', + 'commons-lang' => '/usr/share/java/commons-lang.jar', +); + + +my %glite_prefix; +my %need_externs; +my %need_externs_type; +my %need_jars; +my %extrafull; +my %extranodmod; +my %deps; +my %deps_type; +my %topbuild; + +my %lbmodules = ( + 'lb' => [ qw/client client-java common doc logger server state-machine types utils ws-interface ws-test harvester/], + 'security' => [qw/gss gsoap-plugin/], + 'lbjp-common' => [qw/db log maildir server-bones trio jp-interface/], + 'jobid' => [qw/api-c api-cpp api-java/], + 'jp' => [ qw/client doc index primary server-common ws-interface/ ], + ); + + +my @opts = ( + 'prefix=s' => \$prefix, + 'staged=s' => \$staged, + 'module=s' => \$module, + 'thrflavour=s' => \$thrflavour, + 'nothrflavour=s' => \$nothrflavour, + 'mode=s' => \$mode, + 'listmodules=s' => \$listmodules, + 'version=s' => \$version, + 'output=s' => \$output, + 'stage=s' => \$stagedir, + 'lb-tag=s' => \$lb_tag, + 'lbjp-common-tag=s' => \$lbjp_tag, + 'jp-tag=s' => \$jp_tag, + 'security-tag=s' => \$sec_tag, + 'jobid-tag=s' => \$jobid_tag, + 'help' => \$help, + 'libdir=s' => \$libdir, +); + +for (@nodes) { + $enable_nodes{$_} = 0; + $disable_nodes{$_} = 0; + + push @opts,"disable-$_",\$disable_nodes{$_}; + push @opts,"enable-$_",\$enable_nodes{$_}; +} + +push @opts,"with-$_=s",\$extern_prefix{$_} for keys %extern_prefix; +push @opts,"with-$_=s",\$jar{$_} for keys %jar; + +my @keeparg = @ARGV; + +GetOptions @opts or die "Errors parsing command line\n"; + +$extern_prefix{'mysql-devel'}=$extern_prefix{mysql} if $extern_prefix{'mysql-devel'} eq ''; +$extern_prefix{'mysql-server'}=$extern_prefix{mysql} if $extern_prefix{'mysql-server'} eq ''; + +if ($help) { usage(); exit 0; } + +if ($listmodules) { + my @m = map "org.glite.$listmodules.$_",@{$lbmodules{$listmodules}}; + print "@m\n"; + exit 0; +} + +warn "$0: --version and --output make sense only in --mode=etics\n" + if ($version || $output) && $mode ne 'etics'; + +my $en; +for (keys %enable_nodes) { $en = 1 if $enable_nodes{$_}; } + +my $dis; +for (keys %disable_nodes) { $dis = 1 if $disable_nodes{$_}; } + +die "--enable-* and --disable-* are mutually exclusive\n" + if $en && $dis; + +die "--module cannot be used with --enable-* or --disable-*\n" + if $module && ($en || $dis); + +die "$module: unknown module\n" if $module && ! grep $module,@{$lbmodules{lb}},@{$lbmodules{security}},{$lbmodules{jp}}; + +if ($dis) { + for (@nodes) { + $enable_nodes{$_} = 1 unless $disable_nodes{$_}; + } +} + +if (!$en && !$dis) { $enable_nodes{$_} = 1 for (@nodes) } ; + +for (keys %enable_nodes) { delete $enable_nodes{$_} unless $enable_nodes{$_}; } + +$stagedir = $prefix unless $stagedir; + +if ($mode eq 'build') { + print "Writing config.status\n"; + open CONF,">config.status" or die "config.status: $!\n"; + print CONF "$0 @keeparg\n"; + close CONF; +} + + +my @modules; +my %aux; + +if ($module) { +# push @modules,split(/[,.]+/,$module); + push @modules,$module; +} +else { + @modules = map(($extranodmod{$_} ? $extranodmod{$_} : 'lb.'.$_),(keys %enable_nodes)); + + my $n; + + do { + local $"="\n"; + $n = $#modules; + push @modules,(map @{$deps{$_}},@modules); + + undef %aux; @aux{@modules} = (1) x ($#modules+1); + @modules = keys %aux; + } while ($#modules > $n); +} + +@aux{@modules} = (1) x ($#modules+1); +delete $aux{$_} for (split /,/,$staged); +@modules = keys %aux; + +mode_build() if $mode eq 'build'; +mode_checkout() if $mode eq 'checkout'; +mode_etics($module) if $mode eq 'etics'; + +sub mode_build { + print "\nBuilding modules: @modules\n"; + + my @ext = map @{$need_externs{$_}},@modules; + my @myjars = map @{$need_jars{$_}},@modules; + undef %aux; @aux{@ext} = 1; + @ext = keys %aux; + undef %aux; @aux{@myjars} = (1) x ($#myjars+1); + @myjars = keys %aux; + + print "\nRequired externals:\n"; + print "\t$_: $extern_prefix{$_}\n" for @ext; + print "\t$_: $jar{$_}\n" for @myjars; + print "\nThis is a poor-man configure, it's up to you to have sources and externals there\n\n"; + + mkinc($_) for @modules; + + print "Creating Makefile\n"; + + open MAK,">Makefile" or die "Makefile: $!\n"; + + print MAK "all: @modules\n\nclean:\n"; + + for (@modules) { + my $full = full($_); + my $build = $topbuild{$_} ? '': '/build'; + print MAK "\tcd $full$build && \${MAKE} clean\n" + } + + print MAK "\ndistclean:\n"; + + for (@modules) { + my $full = full($_); + print MAK $topbuild{$_} ? + "\tcd $full$build && \${MAKE} distclean\n" : + "\trm -rf $full$build\n" + } + + print MAK "\n"; + + for (@modules) { + my %ldeps; undef %ldeps; + @ldeps{@{$deps{$_}}} = 1; + for my $x (split /,/,$staged) { delete $ldeps{$x}; } + my @dnames = $module ? () : keys %ldeps; + + my $full = full($_); + my $build = $topbuild{$_} ? '': '/build'; + + print MAK "$_: @dnames\n\tcd $full$build && \${MAKE} && \${MAKE} install\n\n"; + } + + close MAK; +} + +sub mode_checkout() { + for (@modules) { + my $module = $_; + my $tag = ""; + if ($lb_tag){ + for (@{$lbmodules{lb}}){ + if ("lb.".$_ eq $module){ + $tag = '-r '.$lb_tag; + } + } + } + if ($lbjp_tag){ + for (@{$lbmodules{'lbjp-common'}}){ + if ("lbjp-common.".$_ eq $module){ + $tag = '-r '.$lbjp_tag; + } + } + } + if ($jp_tag){ + for (@{$lbmodules{'jp'}}){ + if ("jp.".$_ eq $module){ + $tag = '-r '.$jp_tag; + } + } + } + if ($sec_tag){ + for (@{$lbmodules{security}}){ + if ("security.".$_ eq $module){ + $tag = '-r '.$sec_tag; + } + } + } + if ($jobid_tag){ + for (@{$lbmodules{jobid}}){ + if ("jobid.".$_ eq $module){ + $tag = '-r '.$jobid_tag; + } + } + } + #if (grep {"lb.".$_ eq $module} @{$lbmodules{lb}}){ + # print "found"; + #} + $_ = full($_); + print "\n*** Checking out $_\n"; + system("cvs checkout $tag $_") == 0 or die "cvs checkout $tag $_: $?\n"; + } +} + +BEGIN{ +%need_externs_aux = ( + 'lb.client' => [ qw/cppunit:B classads/ ], + 'lb.client-java' => [ qw/ant:B jdk:B axis:B trustmanager/ ], + 'lb.common' => [ qw/expat cppunit:B classads/ ], + 'lb.doc' => [], + 'lb.logger' => [ qw/cppunit:B log4c/ ], + 'lb.server' => [ qw/globus_essentials:R globus:B expat cares mysql:R mysql-server:R mysql-devel:B cppunit:B gsoap:B classads voms lcas gridsite log4c/ ], + 'lb.state-machine' => [ qw/classads/ ], + 'lb.utils' => [ qw/cppunit:B/ ], + 'lb.ws-interface' => [], + 'lb.ws-test' => [ qw/gsoap:B/ ], + 'lb.types' => [ qw// ], + 'lb.harvester' => [ qw/postgresql:R/ ], + 'lbjp-common.db' => [ qw/mysql:B mysql-devel:B postgresql:B/ ], + 'lbjp-common.log' => [ qw// ], + 'lbjp-common.maildir' => [ qw// ], + 'lbjp-common.server-bones' => [ qw/log4c/ ], + 'lbjp-common.trio' => [ qw/cppunit:B/ ], + 'lbjp-common.jp-interface' => [ qw/cppunit:B/ ], + 'security.gss' => [ qw/globus_essentials:R globus:B cares cppunit:B/ ], + 'security.gsoap-plugin' => [ qw/cppunit:B globus_essentials:R globus:B cares:B gsoap:B/ ], + 'jobid.api-c' => [ qw/cppunit:B/ ], + 'jobid.api-cpp' => [ qw/cppunit:B/ ], + 'jobid.api-java' => [ qw/ant:B jdk:B/ ], + 'jp.client' => [ qw/gsoap libtar globus_essentials:R globus:B/ ], + 'jp.doc' => [], + 'jp.index' => [ qw/gsoap globus_essentials:R globus:B/ ], + 'jp.primary' => [ qw/classads gsoap libtar globus_essentials:R globus:B/ ], + 'jp.server-common' => [], + 'jp.ws-interface' => [], +); + +for my $ext (keys %need_externs_aux) { + for (@{$need_externs_aux{$ext}}) { + /([^:]*)(?::(.*))?/; + push @{$need_externs{$ext}},$1; + my $type = $2 ? $2 : 'BR'; + $need_externs_type{$ext}->{$1} = $type; + } +} + +%need_jars = ( + 'jobid.api-java' => [ qw/commons-codec/ ], + 'lb.client-java' => [ qw/commons-lang/ ], +); + +for my $jar (keys %need_jars) { + for (@{$need_jars{$jar}}) { + $need_externs_type{$jar}->{$_} = 'BR'; # XXX + } +} + +%deps_aux = ( + 'lb.client' => [ qw/ + lb.types:B lb.common + lbjp-common.trio + jobid.api-cpp jobid.api-c + security.gss + / ], + 'lb.client-java' => [ qw/ + lb.types:B + lb.ws-interface:B + jobid.api-java + / ], + 'lb.common' => [ qw/ + jobid.api-cpp jobid.api-c + lb.types:B lbjp-common.trio security.gss + / ], + 'lb.doc' => [ qw/lb.types:B/ ], + 'lb.logger' => [ qw/ + lbjp-common.trio + lbjp-common.log + jobid.api-c + lb.common + security.gss + / ], + 'lb.server' => [ qw/ + lb.ws-interface lb.types:B lb.common lb.state-machine + lbjp-common.db lbjp-common.server-bones lbjp-common.trio lbjp-common.maildir lbjp-common.log + jobid.api-c + security.gsoap-plugin security.gss + / ], + 'lb.state-machine' => [ qw/lb.types:B lb.common lbjp-common.jp-interface security.gss/ ], + 'lb.utils' => [ qw/ + lbjp-common.jp-interface + jobid.api-c + lbjp-common.trio lbjp-common.maildir + lb.client lb.state-machine + / ], + 'lb.ws-test' => [ qw/security.gsoap-plugin lb.ws-interface/ ], + 'lb.ws-interface' => [ qw/lb.types:B/ ], + 'lb.types' => [ qw// ], + 'lb.harvester' => [ qw/ + jobid.api-c lbjp-common.trio lbjp-common.db lb.common lb.client + security.gss + / ], + 'lbjp-common.db' => [ qw/lbjp-common.trio/ ], + 'lbjp-common.maildir' => [ qw// ], + 'lbjp-common.server-bones' => [ qw/lbjp-common.log/ ], + 'lbjp-common.trio' => [ qw// ], + 'security.gss' => [ qw// ], + 'security.gsoap-plugin' => [ qw/security.gss/ ], + 'jobid.api-c' => [ qw// ], + 'jobid.api-cpp' => [ qw/jobid.api-c/ ], + 'jobid.api-java' => [ qw// ], + + 'lbjp-common.jp-interface' => [ qw/lbjp-common.db jobid.api-c/ ], + + 'jp.client' => [ qw/ + jp.ws-interface + lbjp-common.jp-interface lbjp-common.maildir + jobid.api-c + security.gsoap-plugin + / ], + 'jp.doc' => [ qw// ], + 'jp.index' => [ qw/ + jp.server-common jp.ws-interface + lbjp-common.jp-interface lbjp-common.trio lbjp-common.db lbjp-common.server-bones + security.gsoap-plugin + / ], + 'jp.primary' => [ qw/ + jobid.api-c + jp.server-common jp.ws-interface + lb.state-machine + lbjp-common.jp-interface lbjp-common.trio lbjp-common.db lbjp-common.server-bones + security.gsoap-plugin + / ], + 'jp.server-common' => [ qw/ + lbjp-common.jp-interface lbjp-common.db + / ], + 'jp.ws-interface' => [ qw// ], +); + +for my $ext (keys %deps_aux) { + for (@{$deps_aux{$ext}}) { + /([^:]*)(?::(.*))?/; + push @{$deps{$ext}},$1; + my $type = $2 ? $2 : 'BR'; + $deps_type{$ext}->{$1} = $type; + } +} + + +%extrafull = ( gridsite=>'org.gridsite.core'); + +#( java => 'client-java' ); +%extranodmod = ( + db => 'lbjp-common.db', + jpprimary => 'jp.primary', + jpindex => 'jp.index', + jpclient => 'jp.client', +); + +my @t = qw/lb.client-java jobid.api-java lb.types lbjp-common.log/; +@topbuild{@t} = (1) x ($#t+1); +} + +sub full +{ + my $short = shift; + return $extrafull{$short} ? $extrafull{$short} : 'org.glite.'.$short; +} + +sub mkinc +{ + my %aux; + undef %aux; + my @m=qw/ +lb.client lb.doc lb.state-machine lb.ws-interface lb.logger lb.types lb.common lb.server lb.utils lb.ws-test lb.client-java lb.harvester +security.gss security.gsoap-plugin +jobid.api-c jobid.api-cpp jobid.api-java +lbjp-common.db lbjp-common.log lbjp-common.maildir lbjp-common.server-bones lbjp-common.trio lbjp-common.jp-interface +jp.client jp.doc jp.index jp.primary jp.server-common jp.ws-interface +/; + @aux{@m} = (1) x ($#m+1); + + my $short = shift; + my $full = full $short; + + unless ($aux{$short}) { + print "Makefile.inc not needed in $full\n"; + return; + } + + my $build = ''; + + unless ($topbuild{$_}) { + $build = '/build'; + unless (-d "$full/build") { + mkdir "$full/build" or die "mkdir $full/build: $!\n"; + } + unlink "$full/build/Makefile"; + symlink "../Makefile","$full/build/Makefile" or die "symlink ../Makefile $full/build/Makefile: $!\n"; + } + + open MKINC,">$full$build/Makefile.inc" + or die "$full$build/Makefile.inc: $!\n"; + + print "Creating $full$build/Makefile.inc\n"; + + print MKINC qq{ +PREFIX = $prefix +stagedir = $stagedir +thrflavour = $thrflavour +nothrflavour = $nothrflavour +libdir = $libdir +}; + + for (@{$need_externs{$short}}) { + print MKINC "${_}_prefix = $extern_prefix{$_}\n" + } + + for (@{$need_jars{$short}}) { + print MKINC "${_}_jar = $jar{$_}\n" + } + + my $need_gsoap = 0; + for (@{$need_externs{$short}}) { $need_gsoap = 1 if $_ eq 'gsoap'; } + + print MKINC "gsoap_default_version=".gsoap_version()."\n" if $need_gsoap; + + close MKINC; +} + +my %etics_externs; +my %etics_projects; +BEGIN{ + %etics_externs = ( + globus_essentials=>'vdt_globus_essentials', + globus=>'globus', + cares=>'c-ares', + voms=>'org.glite.security.voms-api-cpp', + gridsite=>'org.gridsite.shared', + lcas=>'org.glite.security.lcas', + trustmanager=>'org.glite.security.trustmanager', + ); + %etics_projects = ( + vdt=>[qw/globus globus_essentials/], + 'org.glite'=>[qw/voms gridsite lcas/], + ); +}; + +sub mode_etics { + $fmod = shift; + + die "$0: --module required with --etics\n" unless $fmod; + + my ($subsys,$module) = split /\./,$fmod; + + my ($major,$minor,$rev,$age); + + if ($version) { + $version =~ /([[:digit:]]+)\.([[:digit:]]+)\.([[:digit:]]+)-(.+)/; + ($major,$minor,$rev,$age) = ($1,$2,$3,$4); + } + else { + open V,"org.glite.$subsys.$module/project/version.properties" + or die "org.glite.$subsys.$module/project/version.properties: $!\n"; + + while ($_ = ) { + chomp; + ($major,$minor,$rev) = ($1,$2,$3) if /module\.version\s*=\s*([[:digit:]]+)\.([[:digit:]]+)\.([[:digit:]]+)/; + $age = $1 if /module\.age\s*=\s*([[:digit:]]+)/; + } + close V; + } + + my @copts = (); + my %ge; + @ge{@{$etics_projects{'org.glite'}}} = (1) x ($#{$etics_projects{'org.glite'}}+1); + + for (@{$need_externs{"$subsys.$module"}}) { + if ($need_externs_type{"$subsys.$module"}->{$_}=~/B/) { + my $eext = $etics_externs{$_} ? $etics_externs{$_} : $_; + push @copts,$ge{$_} ? "--with-$_=\${stageDir}" : "--with-$_=\${$eext.location}"; + } + } + + for (@{$need_jars{"$subsys.$module"}}) { + my $eext = $etics_externs{$_} ? $etics_externs{$_} : $_; + + push @copts,"--with-$_ \${$eext.location}/$_*.jar"; + } + + + my $conf = "glite-$subsys-${module}_R_${major}_${minor}_${rev}_${age}"; + my $file = $output ? $output : "$conf.ini"; + open C,">$file" or die "$file: $!\n"; + + my $buildroot = $topbuild{"$subsys.$module"} ? '' : "build.root = build"; + + my $confdir = $topbuild{"$subsys.$module"} ? '..' : '../..'; + + my $package_description = ""; + my $package_summary = ""; + + if (-e "org.glite.$subsys.$module/project/package.description") { + open V, "org.glite.$subsys.$module/project/package.description"; + $package_description = join ("", ); + close V; + chomp $package_description; + $package_description =~ s/\n/\\n/g; + $package_description = "package.description = $package_description"; + } + else { + print STDERR "package.description not found for $subsys.$module!\n"; } + + if (-e "org.glite.$subsys.$module/project/package.summary") { + open V, "org.glite.$subsys.$module/project/package.summary"; + $package_summary = join ("", ); + close V; + chomp $package_summary; + $package_summary =~ s/\n/\\n/g; + $package_summary = "package.summary = $package_summary"; + } + else { + print STDERR "package.summary not found for $subsys.$module!\n"; } + + + print STDERR "Writing $file\n"; + print C qq{ +[Configuration-$conf] +profile = None +moduleName = org.glite.$subsys.$module +displayName = $conf +description = org.glite.$subsys.$module +projectName = org.glite +age = $age +deploymentType = None +tag = $conf +version = $major.$minor.$rev +path = \${projectName}/\${moduleName}/\${version}/\${platformName}/\${packageName}-\${version}-\${age}.tar.gz + +[Platform-default:VcsCommand] +displayName = None +description = None +tag = cvs -d \${vcsroot} tag -R \${tag} \${moduleName} +branch = None +commit = None +checkout = cvs -d \${vcsroot} co -r \${tag} \${moduleName} + +[Platform-default:BuildCommand] +postpublish = None +packaging = None +displayName = None +description = None +doc = None +prepublish = None +publish = None +compile = make +init = None +install = make install +clean = make clean +test = make check +configure = cd $confdir && \${moduleName}/configure --thrflavour=\${globus.thr.flavor} --nothrflavour=\${globus.nothr.flavor} --prefix=\${prefix} --stage=\${stageDir} --libdir=\${libdir} --module $subsys.$module @copts +checkstyle = None + +[Platform-default:Property] +$buildroot +$package_description +$package_summary + +[Platform-default:DynamicDependency] + +}; + for (@{$need_externs{"$subsys.$module"}},@{$need_jars{"$subsys.$module"}}) { + my $eext = $etics_externs{$_} ? $etics_externs{$_} : $_; + + my $proj = 'externals'; + for my $p (keys %etics_projects) { + for $m (@{$etics_projects{$p}}) { + $proj = $p if $m eq $_; + } + } + + my $type = $need_externs_type{"$subsys.$module"}->{$_}; + print C "$proj|$eext = $type\n"; + } + + for (@{$deps{"$subsys.$module"}}) { + my $type = $deps_type{"$subsys.$module"}->{$_}; + print C "org.glite|org.glite.$_ = $type\n"; + } + + close C; +} + +sub gsoap_version { + local $_; + my $gsoap_version; + open S,"$extern_prefix{gsoap}/bin/soapcpp2 -v 2>&1 |" or die "$extern_prefix{gsoap}/bin/soapcpp2: $!\n"; + + while ($_ = ) { + chomp; + + $gsoap_version = $1 if /The gSOAP Stub and Skeleton Compiler for C and C\+\+ ([.[:digit:][:alpha:]]+)$/; + } + close S; + return $gsoap_version; +} + +sub getlibdir { + if ( -e "/etc/debian_version") { # We are on Debian + $lib64="lib"; + $lib32="lib32"; } + else { # Another distribution + $lib64="lib64"; + $lib32="lib"; } + $libdir=$lib32; + + open INP, "uname -s | "; # Check kernel name + $kname= ; + chomp($kname); + close INP; + + if ( $kname == "Linux") { + $arch = ("x86_64\npowerpc\nppc64\n"); + + open INP, "uname -p | "; # Check processor type + $procname= ; + chomp($procname); + close INP; + + if ($arch =~/^$procname\n/) { + return ($lib64); } + + open INP, "uname -m | "; # Check machine hardware + $machname= ; + chomp($machname); + close INP; + + if ($arch =~/^$machname\n/) { + return ($lib64); } + + # special cases (hyperlink lib64, Debian) + if (-l "/usr/lib64") { + $libdir=$lib32; } + + # if /usr/lib64 doesn't exist at all (AIX) + unless ( -e "/usr/lib64" ) { + $libdir=$lib32; } + } + + if ( $kname == "SunOS") { + if (-e "/usr/lib/64") { + $libdir="lib/64"; } + } + + return $libdir; +} + +sub usage { + my @ext = keys %extern_prefix; + my @myjars, keys %jar; + + print STDERR qq{ +usage: $0 options + +General options (defaults in []): + --prefix=PREFIX destination directory [./stage] + --staged=module,module,... what is already in PREFIX (specify without org.glite.) + --thrflavour=flavour + --nothrflavour=flavour threaded and non-treaded flavours [gcc64dbgpthr,gcc64dbg] + --listmodules=subsys list modules of a subsystem + --libdir=libdir typically [lib,lib64] postfix + +Mode of operation: + --mode={checkout|build|etics} what to do [build] + +What to build: + --module=module build this module only (mostly in-Etics operation) + --enable-NODE build this "node" (set of modules) only. Available nodes are + @{$lbmodules{lb}},@{$lbmodules{security}} + --disable-NODE don't build this node + --lb-tag=tag checkout LB modules with specific tag + --jp-tag=tag checkout JP modules with specific tag + --lbjp-common-tag=tag checkout lbjp-common modules with specific tag + --security-tag=tag checkout security modules with specific tag + --jobid-tag=tag checkout jobid modules with specific tag + +Dependencies: + --with-EXTERNAL=PATH where to look for an external. Required externals + (not all for all modules) are: + @ext + --with-JAR=JAR where to look for jars. Required jars are: + @myjars + Summary of what will be used is always printed + +}; + +} diff --git a/org.glite.lb.harvester/doc/INSTALL b/org.glite.lb.harvester/doc/INSTALL new file mode 100644 index 0000000..f5ff9c9 --- /dev/null +++ b/org.glite.lb.harvester/doc/INSTALL @@ -0,0 +1,42 @@ +Requirements +============ + +1) gLite +- client L&B libraries: + - glite-jobid-api-c + - glite-lb-common + - glite-lb-client + - glite-security-gss + - globus essential libraries (threaded flavour), + use the vesion with the external SSL, not with bundled SSL (!) + - glite-lbjp-common-db (build only) + - mysql-devel (build only) +2) postgresql-devel + + +Steps +===== + +./configure +make +make install + +Use './configure --help' for the options. + + +Manual way +========== + +configure is simple script generating Makefile.inc. You can build harvester +straight away by make defining the variables manually. For example with gLite +installed in ~/glite/stage: + +(rm Makefile.inc) +make stagedir=$HOME/glite/stage + + +Testing +======= + +Test for basic functionality covered by 'test.sh' script in sources. +See './test.sh --help'. diff --git a/org.glite.lb.harvester/doc/README b/org.glite.lb.harvester/doc/README new file mode 100644 index 0000000..f1c393d --- /dev/null +++ b/org.glite.lb.harvester/doc/README @@ -0,0 +1,81 @@ +Introduction +============ + +L&B Harvester gathers information about jobs from L&B servers using effective +L&B notification mechanism. It manages notifications and keeps them in +a persistent storage (file or database table) to reuse later on next launch. +It takes care about refreshing notifications and queries L&B servers back when +some notification on expires. + +The tool was initially written for Real Time Monitor (project at Imperial +College in London), later was extended with messaging mechanism for WLCG. + + +Requirements +============ + +- lastUpdateTime index on L&B servers +- harvester identity in super users file on L&B servers + + +Launch (with msg-publish sending messages) +========================================= + +Harvester is sending notifications via msg-publish infrastructure. List of the +L&B server to harvest is specified via -c option. + +1) with newer LB 2.0 servers: + + glite-lb-harvester -c servers.txt -C certfile -K keyfile --wlcg + +2) with older LB servers (backward compatible but greedy notifications): + + glite-lb-harvester -c servers.txt -C certfile -K keyfile --wlcg --old + +Custom configuration of messaging: + --wlcg-binary $HOME/bin/msg-publish + --wlcg-topic org.wlcg.usage.JobStatus2 + --wlcg-config $HOME/etc/msg-publish.conf.wlcg + + +Launch (Real Time Monitor and storing to the database) +====================================================== + +Harvester is using postgres database. Table 'lb20' with L&B servers to +harvest (read-only), table 'jobs' with result job states (read/write). It's +possible to specify L&B servers list by file instead of 'lb20' table, +via -c option. + + glite-lb-harvester -C certfile -K keyfile --pg rtm/@:rtm + +The connection string after '--pg' is in format: + USER/PASSWORD@HOST:DATABASE +Database schema in 'test.sql'. + + +Other recommended options +========================= + +Use 'glite-lb-harvester --help' for additional options. + +For example: + - deamonizing and using syslog: + '--daemonize --pidfile /var/run/glite-lb-harvester.pid' + - decreasing verbosity: + '-d 2' (2 for errors and warnings only) + + +Stop +==== + +In non-daemon mode CTRL-C can be used, in daemon mode using specified +pidfile: + + kill `cat /var/run/glite-lb-harvester.pid` + +pidfile will vanish after exit. + +All notifications are preserved on LB servers, and will expire later. You can +purge them now, if they won't be needed: + + glite-lb-harvester --cleanup diff --git a/org.glite.lb.harvester/doc/glite-lb-harvester.sgml b/org.glite.lb.harvester/doc/glite-lb-harvester.sgml new file mode 100644 index 0000000..5d9f75a --- /dev/null +++ b/org.glite.lb.harvester/doc/glite-lb-harvester.sgml @@ -0,0 +1,480 @@ + + + + + + glite-lb-harvester + 1 + EU EGEE Project + + + + glite-lb-harvester + daemon for processing L&B notifications + + + + + glite-lb-harvester + + + -h + --help + + + + -v + --version + + + + -d + --debug + LEVEL + + + -D + --daemon + + + + -i + --pidfile + PIDFILE + + + -s + --threads + N + + + -t + --ttl + TIME + + + -H + --history + TIME + + + -c + --config + + + + -m + --pg + USER/PWD@SERVER:DBNAME + + + -n + --notifs + FILE + + + -p + --port + PORT + + + -C + --cert + FILE + + + -K + --key + FILE + + + -o + --old + + + + -l + --cleanup + + + + -u + --no-purge + + + + -w + --wlcg + + + + --wlcg-binary + EXECUTABLE + + + --wlcg-topic + TOPIC + + + --wlcg-config + FILENAME + + + --wlcg-flush + + + + + + DESCRIPTION + +L&B Harvester gathers information about jobs from L&B servers using efficient +L&B notification mechanism. It manages notifications and keeps them in +a persistent storage (file or database table) to reuse later on next launch. +It takes care about refreshing notifications and queries L&B servers back when +some notification expires. + +The tool was initially written for Real Time Monitor (project at Imperial +College in London), later was extended by MSG publish messaging mechanism for WLCG. + + + + + Requirements + +It is required on L&B servers side: + + +lastUpdateTime index, see "Changing Index Configuration" section in L&B Admin Guide + + +L&B harvester identity (certification subject) in super users file + + + + + + + OPTIONS + + + + | + +Print short usage. + + + + + + + | + +Print harvester version identifier. + + + + + | + + Verbosity level: + + 0error only + 1warnings + 2info/progress + 3debug + 4insane + +8 (8,9,10,11,12)don't fork and no preventive restarts + + + + + + | + +Daemonize and detach from console. Error messages are directed to syslog. + + + + + | + +The file with process ID. Automatically removed on shutdown. + + + + + | + +Number of threads (slaves). Configured L&B servers are equally distributed between threads. + + + + + | + +Validity (time to live) of the notifications. Daemon regularly refreshes notification in advance as needed. + + + + + | + +Historic dive limit in seconds. <= means unlimited. + + When staring, the L&B harvester queries the L&B servers for existing jobs. It queries L&B server when notification expires too and can't be refreshed on time. This parameter is used for limit, how deep into history L&B harvester should go. + + Another usage of this parameter is for derivation of the maximal time of retries. When some L&B server is inaccessible or it is in error condition, harvester linearly increases retry time. The maximal retry time is half of this parameter. + + + + + | + + Config file name with list of L&B servers. When used together with database option (), this parameter has precedence before lb20 table. + + + + + | + +Database connection string in the USER/PWD@SERVER:DBNAME form. There are used following tables in database: + + + lb20 - the list of L&B servers is taken from this table. But when is specified option () too, the file has precedence before this table. + +There is kept a column monitored in too: if there is any inactive notification because of errors on given L&B server (one expired or it was unable to create a new one), the false value is set. After refreshing or creating the notification, the value is set back to true. + + + jobs - table for storing job states. Each record is updated for each incoming notification - when state of the job changes in L&B server. + + +Database schema can be found in source code of org.glite.lb.harvester: examples/test.sql + +Developer note: information about notifications are kept in a file. It is possible to compile a binary keeping states in the database. It is used in the test in examples source directory. + + + + + | + +File for internal usage in L&B harvester. There is kept persistent information about active notifications or errors on L&B servers. Default is /var/tmp/notifs.txt. + + + + + | + +Specifies the port for listening and requests L&B nodes to send notification messages only to this port. May be needed for networks behind NAT or behind firewalls. + + + + + | + +X509 certificate file. + + + + + | + +X509 key file. + + + + + | + +"silly" mode for L&B servers < 2.0. In this mode transfer of the notification is not optimized at all. On the other hand it will work with older L&B servers. + + + + + | + +Cleans up all active notifications and quits. + +Each notification automatically expires. But if you know, than notifications used in previous run of L&B harvester won;t be needed, it is recommended to clean up the notifications and spare the resources on L&B servers (queue with undelivered notification messages and matching rules). + + + + + | + +By default jobs are purged from local database when purged on L&B server. This option forces keeping all jobs in database, only with changed state to 'Purged'. + +For using together with (). + + + + + | + +Enables delivery to MSG publish. Messages are sent by executing a binary with proper parameters. + + + + + + +Full path to msg-publish binary executable, which is called for sending messages. Default is /usr/bin/msg-publish. + + + + + + +Topic used in MSG publish messages. Default is org.wlcg.usage.jobStatus. + + + + + + +Config file used in MSG publish. Default is /etc/msg-publish/msg-publish.conf. + + + + + + +Messages are sent to MSG publish in batches by default. This option enforce sending the messages one by one on each notification from L&B server - for each job state change. + + + + + + + + ENVIRONMENT + + + + GLITE_LB_HARVESTER_NO_REMOVE + +0 or false instructs L&B harvester to not remove temporary files with sent messages for MSG publish. By default temporary files with successfully sent messages are removed. Files with failed messages are always preserved. + +Intended for debugging purposes. + + + + + + + EXAMPLES + + + MSG publish infrastructure + +Harvester will send notifications using msg-publish infrastructure. List of the L&B servers to harvest is specified in config file specified by option: + + + + glite-lb-harvester -c servers.txt -C certfile -K keyfile --wlcg + +With newer L&B servers >= 2.0. + + + + glite-lb-harvester -c servers.txt -C certfile -K keyfile --wlcg --old + +With older L&B servers < 2.0 (backward compatible but greedy notifications). + + + + + +Custom configuration examples for MSG publish: + + + $HOME/bin/msg-publish + + org.wlcg.usage.JobStatus2 + + $HOME/etc/msg-publish.conf.wlcg + + + + + + + Real Time Monitor + +Harvester will use postgres database. Table lb20 with L&B servers to harvest (read-only), table jobs for result job states (read/write): + + + + glite-lb-harvester -C certfile -K keyfile --pg rtm/@:rtm -p 9004 + +In this case the L&B harvester will connect to database rtm on localhost as user rtm. For incoming notification it will request and listen only on port 9004. + + + + + + + Other recommended options + +Use glite-lb-harvester --help for the whole summary. + +For example: + + + + +Daemonizing and using syslog. + + + + + + +Decreasing verbosity (2 for errors and warnings only). + + + + + + + + + EXIT + +In non-daemon mode CTRL-C can be used. + +Use the pidfile in daemon mode (pidfile will vanish after exit): + +kill `cat /var/run/glite-lb-harvester.pid` + +All notifications are preserved on LB servers, and will expire later. You can +purge them at once, if they won't be needed: + +glite-lb-harvester --cleanup + + + + + EXIT STATUS + + + 0 + Success. + + + 1 + Reloading, used only internally for preventive restarts. + + + 2 + Error occurred. Messages go on console (foreground run) or into syslog (daemon run), depending on verbosity. + + + + + + AUTHOR + gLite L&B product team, CESNET. + + + diff --git a/org.glite.lb.harvester/examples/test.sh b/org.glite.lb.harvester/examples/test.sh new file mode 100755 index 0000000..4bfba32 --- /dev/null +++ b/org.glite.lb.harvester/examples/test.sh @@ -0,0 +1,876 @@ +#! /bin/sh + + +usage() { +cat <&1| \ + grep timeleft| sed 's/^.* //'` + if [ "$timeleft" = "0:00:00" -o -z "$timeleft" ]; then + echo "Proxy certificate check failed."\ + " Aborting." + exit 1 + fi + else + echo "Can't check proxy cert (grid-proxy-info not found). If you do not have valid proxy certificate, set GLITE_HOST_KEY/GLITE_HOST_KEY - otherwise tests will fail!" + fi +# fi + identity=`X509_USER_KEY=${X509_USER_KEY} X509_USER_CERT=${X509_USER_CERT} $GLOBUS_LOCATION/bin/grid-proxy-info 2>&1| \ + grep identity| sed 's/^[^/]*//'` + + if [ -z "$GLITE_LB_TEST_DB" ]; then + GLITE_LB_TEST_DB="lbserver/@localhost:lbserver20test" + need_new_lb_db=1; + fi + DB_USER=`echo $GLITE_LB_TEST_DB| sed 's!/.*$!!'` + DB_HOST=`echo $GLITE_LB_TEST_DB| sed 's!^.*@!!' | sed 's!:.*!!'` + DB_NAME=`echo $GLITE_LB_TEST_DB| sed 's!^.*:!!'` + MYSQL_ARGS="-u ${GLITE_MYSQL_ROOT_USER:-root}" + [ -z "$GLITE_MYSQL_ROOT_PASSWORD" ] || ARGS="--password=${GLITE_MYSQL_ROOT_PASSWORD} $MYSQL_ARGS" + + if [ -z "$GLITE_RTM_TEST_DB" ]; then + GLITE_RTM_TEST_DB="rtm/@localhost:rtmtest" + need_new_rtm_db=1; + fi + RTM_USER=`echo $GLITE_RTM_TEST_DB| sed 's!/.*$!!'` + RTM_HOST=`echo $GLITE_RTM_TEST_DB| sed 's!^.*@!!' | sed 's!:.*!!'` + RTM_NAME=`echo $GLITE_RTM_TEST_DB| sed 's!^.*:!!'` + PG_ARGS="-U ${GLITE_PG_ROOT_USER:-postgres}" + + #other stuff + GLITE_LB_TEST_SERVER_PORT=${GLITE_LB_TEST_SERVER_PORT:-"10000"} + GLITE_LB_TEST_PIDFILE=${GLITE_LB_TEST_PIDFILE:-"/tmp/glite-lb-test.pid"} + GLITE_RTM_TEST_PIDFILE=${GLITE_RTM_TEST_PIDFILE:-"/tmp/glite-rtm-test.pid"} + GLITE_RTM_TEST_TTL=${GLITE_RTM_TEST_TTL:-"60"} + + jobreg="$GLITE_LOCATION/examples/glite-lb-job_reg -m `hostname -f`:${GLITE_LB_TEST_SERVER_PORT} -s UserInterface" + logev="$GLITE_LOCATION/bin/glite-lb-logevent -x -S `pwd`/LB/proxy.sockstore.sock -U localhost" + purge="$GLITE_LOCATION/bin/glite-lb-purge" + [ -x "$purge" ] || purge="$GLITE_LOCATION/sbin/glite-lb-purge" + for dir in "$GLITE_LOCATION/examlpes" "`pwd`/../build" "`pwd`"; do + if [ -x "$dir/glite-lb-harvester-dbg" ]; then + rtm="$dir/glite-lb-harvester-dbg" + fi + if [ -x "$dir/harvester-dbg" ]; then + rtm="$dir/harvester-dbg" + fi + done + if [ -z "$rtm" ]; then + echo "glite-lb-harvester-dbg not found" + return 1 + fi + + if echo "$GLITE_RTM_TEST_ADDITIONAL_ARGS" | grep -- '[^-]\?\(--old\>\|-o\>\)' >/dev/null; then + n_notifs=1 + else + n_notifs=2 + fi + + rm -f log +} + + +drop_db() { +return 0 + [ -z "$lb_db_created" ] || mysqladmin -f $MYSQL_ARGS drop "$DB_NAME" + [ -z "$rtm_db_created" ] || dropdb $PG_ARGS "$RTM_NAME" +} + + +create_db() { + echo -n "mysql." + # create database when needed + if [ "x$need_new_lb_db" = "x1" ]; then + mysqladmin -f $MYSQL_ARGS drop $DB_NAME > /dev/null 2>&1 + echo -n "." + mysqladmin -f $MYSQL_ARGS create $DB_NAME && \ + echo -n "." + mysql $MYSQL_ARGS -e "GRANT ALL on $DB_NAME.* to $DB_USER@$DB_HOST" && \ + echo -n "." + mysql -u $DB_USER $DB_NAME -h $DB_HOST < $GLITE_LOCATION/etc/glite-lb-dbsetup.sql || return $? + echo -n "." + mkdir -p `pwd`/LB + cat > `pwd`/LB/glite-lb-index.conf << EOF +[ + JobIndices = { + [ type = "system"; name = "lastUpdateTime" ] + } +] +EOF + LBDB="$GLITE_LB_TEST_DB" $GLITE_LOCATION/bin/glite-lb-bkindex -r `pwd`/LB/glite-lb-index.conf || return $? + lb_db_created="1" + echo -n "." + else + cleanup_mysql || return $? + fi + echo -n "OK psql." + if [ "x$need_new_rtm_db" = "x1" ]; then + dropdb $PG_ARGS "$RTM_NAME" >/dev/null 2>&1 + echo -n "." +# createuser $PG_ARGS -A -D "$RTM_NAME" >/dev/null 2>&1 +# echo -n "." + createdb $PG_ARGS --encoding "UTF-8" --owner "$RTM_USER" "$RTM_NAME" >psql-create.log 2>&1 || return $? + rm psql-create.log + echo -n "." + rtm_db_created="1" + echo "\i test.sql" | psql -AtF ',' -U "$RTM_USER" "$RTM_NAME" >/dev/null || return $? + echo -n "." + else + cleanup_pg || return $? + fi + echo "OK" +} + + +cleanup_mysql() { + cat << EOF | mysql -u $DB_USER $DB_NAME -h $DB_HOST || return $? +DELETE FROM acls; +DELETE FROM events; +DELETE FROM events_flesh; +DELETE FROM jobs; +DELETE FROM long_fields; +DELETE FROM notif_jobs; +DELETE FROM notif_registrations; +DELETE FROM server_state; +DELETE FROM short_fields; +DELETE FROM states; +DELETE FROM status_tags; +DELETE FROM users; +DELETE FROM zombie_jobs; +DELETE FROM zombie_prefixes; +DELETE FROM zombie_suffixes; +EOF + echo -n "." +} + + +cleanup_pg() { + cat << EOF | psql -AtF ',' -U "$RTM_USER" "$RTM_NAME" >/dev/null || return $? +DELETE FROM jobs; +DELETE FROM notifs; +EOF + echo -n "." +} + + +run_daemons() { + mkdir -p LB/dump LB/purge LB/voms 2>/dev/null + + # checks + if [ -f "${GLITE_LB_TEST_PIDFILE}" ]; then + echo "L&B server already running (${GLITE_LB_TEST_PIDFILE}, `cat ${GLITE_LB_TEST_PIDFILE}`)" + quit=1 + fi + if [ -f "${GLITE_RTM_TEST_PIDFILE}" ]; then + echo "L&B harvester already running (${GLITE_RTM_TEST_PIDFILE}, `cat ${GLITE_RTM_TEST_PIDFILE}`)" + quit=1 + fi + if [ -e "`pwd`/LB/notif.sock" ]; then + if [ "`lsof -t $(pwd)/LB/notif.sock | wc -l`" != "0" ]; then + echo "Notification interlogger already running (using LB/notif.sock, `lsof -t $(pwd)/LB/notif.sock`)" + quit=1 + fi + fi + if [ -e "`pwd`/LB/proxy-il.sock" ]; then + if [ "`lsof -t $(pwd)/LB/proxy-il.sock | wc -l`" != "0" ]; then + echo "Proxy interlogger already running (using LB/proxy-il.sock, `lsof -t $(pwd)/LB/proxy-il.sock`)" + quit=1 + fi + fi + [ -z "$quit" ] || exit 1 + + # run L&B server + echo -n "L" + X509_USER_KEY=${X509_USER_KEY} X509_USER_CERT=${X509_USER_CERT} \ + $GLITE_LOCATION/bin/glite-lb-bkserverd \ + -m $GLITE_LB_TEST_DB \ + -p $GLITE_LB_TEST_SERVER_PORT -w $(($GLITE_LB_TEST_SERVER_PORT + 3))\ + -i ${GLITE_LB_TEST_PIDFILE} \ + --withproxy -o `pwd`/LB/proxy.sock\ + --proxy-il-sock `pwd`/LB/proxy-il.sock --proxy-il-fprefix `pwd`/LB/proxy-data \ + -D `pwd`/LB/dump -S `pwd`/LB/purge \ + -V `pwd`/LB/voms \ + --notif-il-sock `pwd`/LB/notif.sock --notif-il-fprefix `pwd`/LB/notif-data \ + --super-user "$identity" > `pwd`/LB/glite-lb-test-pre.log 2>&1 + if [ x"$?" != x"0" ]; then + cat `pwd`/LB/glite-lb-test-pre.log + echo FAILED + drop_db; + exit 1 + fi + echo -n "B " + + # run L&B interlogger + echo -n "L" + X509_USER_KEY=${X509_USER_KEY} X509_USER_CERT=${X509_USER_CERT} \ + $GLITE_LOCATION/bin/glite-lb-interlogd \ + --file-prefix `pwd`/LB/proxy-data --socket `pwd`/LB/proxy-il.sock > `pwd`/LB/glite-interlog-test-pre.log 2>&1 + if [ x"$?" != x"0" ]; then + cat `pwd`/LB/glite-interlog-test-pre.log + echo FAILED + kill_bkserver + drop_db; + exit 1 + fi + echo -n "I " + + # run L&B notification interlogger + echo -n "N" + X509_USER_KEY=${X509_USER_KEY} X509_USER_CERT=${X509_USER_CERT} \ + $GLITE_LOCATION/bin/glite-lb-notif-interlogd \ + --file-prefix `pwd`/LB/notif-data --socket `pwd`/LB/notif.sock > `pwd`/LB/glite-notif-test-pre.log 2>&1 + if [ x"$?" != x"0" ]; then + cat `pwd`/LB/glite-notif-test-pre.log + echo FAILED + kill_daemons + drop_db; + exit 1 + fi + echo -n "I " + + if ! start_harvester; then + kill_daemons; + drop_db; + exit 1 + fi + + # wait for pidfiles + i=0 + while [ ! -s "${GLITE_LB_TEST_PIDFILE}" -a $i -lt 20 ]; do + sleep 0.1 + i=$(($i+1)) + done + if [ ! -s "${GLITE_LB_TEST_PIDFILE}" ]; then + echo "Can't startup L&B server." + kill_daemons; + drop_db; + exit 1 + fi + + echo -n "notifs." + pg_wait 20 "SELECT refresh FROM notifs WHERE notifid IS NOT NULL" $n_notifs || return $? + refresh=`echo "$result" | head -n 1` + if [ -z "$refresh" ]; then + echo "FAIL" + return 1 + fi +} + + +start_harvester() { + # run L&B harvester server + echo -n "R" + rm -Rf RTM + mkdir RTM 2>/dev/null + echo "`hostname -f`:${GLITE_LB_TEST_SERVER_PORT}" > `pwd`/RTM/config.txt + X509_USER_KEY=${X509_USER_KEY} X509_USER_CERT=${X509_USER_CERT} \ + ${rtm} \ + -m $GLITE_RTM_TEST_DB \ + --pidfile ${GLITE_RTM_TEST_PIDFILE} \ + --ttl ${GLITE_RTM_TEST_TTL} \ + --history $((GLITE_RTM_TEST_TTL / 2)) \ + --debug 12 \ + --config `pwd`/RTM/config.txt \ + --daemonize ${GLITE_RTM_TEST_ADDITIONAL_ARGS} 2>`pwd`/RTM/glite-rtm-test-pre.log >`pwd`/RTM/notifs.log + if [ x"$?" != x"0" ]; then + cat `pwd`/RTM/glite-rtm-test-pre.log + echo FAILED + return 1 + fi + + i=0 + while [ ! -s "${GLITE_RTM_TEST_PIDFILE}" -a $i -lt 20 ]; do + sleep 0.1 + i=$(($i+1)) + done + if [ ! -s "${GLITE_RTM_TEST_PIDFILE}" ]; then + echo "Can't startup L&B harvester." + kill_daemons; + drop_db; + exit 1 + fi + + echo -n "M " +} + + +cleanup_harvester() { + echo -n "cleaning up..." + X509_USER_KEY=${X509_USER_KEY} X509_USER_CERT=${X509_USER_CERT} \ + ${rtm} \ + -m $GLITE_RTM_TEST_DB \ + --cleanup \ + --debug 12 ${GLITE_RTM_TEST_ADDITIONAL_ARGS} >`pwd`/RTM/glite-rtm-test-cleanup.log 2>&1 + if [ x"$?" != x"0" ]; then + cat `pwd`/RTM/glite-rtm-test-cleanup.log + echo FAILED + return 1 + fi + echo -n "OK " +} + + +kill_daemons() { + pid1=`cat ${GLITE_LB_TEST_PIDFILE} 2>/dev/null` + [ -f "${GLITE_RTM_TEST_PIDFILE}" ] && pid2=`cat ${GLITE_RTM_TEST_PIDFILE}` + pid3=`lsof -t $(pwd)/LB/notif.sock 2>/dev/null` + pid4=`lsof -t $(pwd)/LB/proxy-il.sock 2>/dev/null` + [ ! -z "$pid1" ] && kill $pid1 + [ ! -z "$pid2" ] && kill -2 $pid2 + [ ! -z "$pid3" ] && kill $pid3 + [ ! -z "$pid4" ] && kill $pid4 + sleep 1; + [ ! -z "$pid1" ] && kill -9 $pid1 2>/dev/null + [ ! -z "$pid2" ] && kill -9 $pid2 2>/dev/null + [ ! -z "$pid3" ] && kill -9 $pid3 2>/dev/null + [ ! -z "$pid4" ] && kill -9 $pid4 2>/dev/null + rm -f "${GLITE_LB_TEST_PIDFILE}" "${GLITE_RTM_TEST_PIDFILE}" + rm -f `pwd`/LB/*.sock +} + + +kill_bkserver() { + pid=`cat ${GLITE_LB_TEST_PIDFILE} 2>/dev/null` + if [ ! -z "$pid1" ]; then + kill $pid; + sleep 1; + kill -9 $pid + fi + rm -f "${GLITE_LB_TEST_PIDFILE}" +} + + +kill_harvester() { + pid=`cat ${GLITE_RTM_TEST_PIDFILE} 2>/dev/null` + if [ ! -z "$pid1" ]; then + kill $pid + sleep 1; + kill -9 $pid 2>/dev/null + fi + rm -f "${GLITE_RTM_TEST_PIDFILE}" +} + + +reg() { + echo -n "R" + echo $jobreg $@ >> log + $jobreg $@ > jobreg.tmp + if [ $? -ne 0 ]; then + cat jobreg.tmp + rm -f jobreg.tmp + echo " FAIL!" + return 1; + fi + script=`cat jobreg.tmp | tail -n 2` + rm -f jobreg.tmp + EDG_JOBID= + EDG_WL_SEQUENCE= + eval $script + if [ -z "$EDG_JOBID" -o -z "$EDG_WL_SEQUENCE" ]; then + echo " FAIL!" + return 1; + fi + echo -n "G " +} + + +ev() { + echo -n "E" + echo $logev -j "$EDG_JOBID" -c "$EDG_WL_SEQUENCE" "$@" >> log + $logev -j "$EDG_JOBID" -c "$EDG_WL_SEQUENCE" "$@" 2> logev-err.tmp >logev.tmp + if [ $? -ne 0 ]; then + echo " FAIL!" + return 2; + fi + EDG_WL_SEQUENCE=`cat logev.tmp` + rm logev.tmp logev-err.tmp + echo -n "V " +} + + +pg_get() { + result= + lines= + echo "$1" | psql -AtF ',' -U "$RTM_USER" "$RTM_NAME" > psql.tmp + if [ $? != 0 ]; then + return $? + fi + result="`cat psql.tmp`" + lines=`wc -l psql.tmp | sed 's/^[ ]*//' | cut -f1 -d' '` +# rm psql.tmp + return 0 +} + + +pg_wait() { + timeout=$(($1*2)) + sql="$2" + n="$3" + + i=0 + found=0 + result= + echo -n "S" + echo "`date '+%Y-%m-%d %H:%M:%S'` $sql" >> log + while [ "$found" = "0" -a $i -lt $timeout ]; do + pg_get "$sql" || return $? + echo -n "." + if [ -z "$n" ]; then + if [ "$lines" != "0" ]; then found=1; fi + else + if [ "$lines" = "$n" ]; then found=1; fi + fi + if [ "$found" = "0" ]; then sleep 0.5; fi + i=$(($i+1)) + done + echo -n "Q " + result="$result" + echo "`date '+%Y-%m-%d %H:%M:%S'` $lines lines" >> log + if [ ! -z "$result" ]; then + echo "$result" | sed -e 's/\(.*\)/\t\1/' >> log + fi + return 0 +} + + +my_get() { + result= + lines= + echo "`date '+%Y-%m-%d %H:%M:%S'` $1" >> log + echo "$1" | mysql -B -u "$DB_USER" "$DB_NAME" > mysql.tmp + if [ $? != 0 ]; then + return $? + fi + result=`cat mysql.tmp | tail -n +2` + lines=`echo "$result" | grep -v '^$' | wc -l | sed 's/^[ ]*//'` + echo "`date '+%Y-%m-%d %H:%M:%S'` $lines lines" >> log + if [ ! -z "$result" ]; then + echo "$result" | sed -e 's/\(.*\)/\t\1/' >> log + fi +# rm -f mysql.tmp + return 0 +} + + +# notif propagation +test_basic() { + ok=0 + + # submited + echo -n "submitted..." + reg || return $? + pg_wait 10 "SELECT jobid, state FROM jobs WHERE state='Submitted'" || return $? + if [ -z "$result" ]; then + echo "FAIL" + return 0 + fi + + # waiting + echo -n "waiting..." + ev -s NetworkServer -e Accepted --from='UserInterface' --from_host=`hostname -f` --from_instance="pid$$" || return $? + pg_wait 10 "SELECT jobid, state FROM jobs WHERE state='Waiting'" || return $? + if [ -z "$result" ]; then + echo "FAIL" + return 0 + fi + + # running + echo -n "running..." + ev -s LogMonitor -e Running --node="worker node" || return $? + pg_wait 10 "SELECT jobid, state FROM jobs WHERE state='Running'" || return $? + if [ -z "$result" ]; then + echo "FAIL" + return 0 + fi + + ok=1 + echo "OK" +} + + +# proper notif registration cleanup +test_rebind() { + ok=0 + + # ---- active --- + echo -n "$n_notifs notifications " + my_get "SELECT notifid FROM notif_registrations" || return $? + # STATUS and JDL + if [ "$lines" != "$n_notifs" ]; then + echo "FAIL" + return 0 + fi + echo -n "OK " + + # ---- store & stop --- + echo -n "store&quit" + pid=`cat ${GLITE_RTM_TEST_PIDFILE}` + kill $pid + i=0 + while [ -s "${GLITE_RTM_TEST_PIDFILE}" -a $i -lt 200 ]; do + echo -n "." + sleep 0.5 + i=$(($i+1)) + done + if [ -s "${GLITE_RTM_TEST_PIDFILE}" ]; then + echo "FAIL" + return 0 + fi + echo -n "OK notifs " + my_get "SELECT notifid FROM notif_registrations" || return $? + if [ "$lines" != "$n_notifs" ]; then + echo "FAIL" + return 0 + fi + echo -n "OK " + + # ---- launch & rebind --- + if ! start_harvester; then + kill_daemons; + drop_db; + exit 1 + fi + + echo -n "bind" + pg_wait 20 "SELECT notifid FROM notifs WHERE notifid IS NOT NULL" $n_notifs || return $? + if [ x"$lines" != x"$n_notifs" ]; then + echo "FAIL" + return 0 + fi + + echo -n "Done " + ev -s LogMonitor -e Done --status_code=OK --reason="Finished, yeah!" --exit_code=0 || return $? + pg_wait 20 "SELECT jobid, state FROM jobs WHERE state='Done'" + if [ -z "$result" ]; then + echo "FAIL" + return 0 + fi + + ok=1 + echo "OK" +} + + +test_cleanup() { + ok=0 + + # ---- deep stop --- + echo -n "deep quit" + pid=`cat ${GLITE_RTM_TEST_PIDFILE}` + kill -2 $pid + i=0 + while [ -s "${GLITE_RTM_TEST_PIDFILE}" -a $i -lt 200 ]; do + echo -n "." + sleep 0.5 + i=$(($i+1)) + done + if [ -s "${GLITE_RTMTESTPIDFILE}" ]; then + echo "FAIL" + return 0 + fi + + echo -n "$n_notifs notifications..." + my_get "SELECT notifid FROM notif_registrations" || return 1 + if [ "$lines" != "$n_notifs" ]; then + echo "FAIL" + return 0 + fi + + cleanup_harvester || return $? + echo -n "0 notifications..." + my_get "SELECT notifid FROM notif_registrations" || return 1 + if [ "$lines" != "0" ]; then + echo "FAIL" + return 0 + fi + + echo -n "cleandb." + cleanup_pg || return $? + start_harvester || return $? + + echo -n "notifs." + pg_wait 20 "SELECT refresh FROM notifs WHERE notifid IS NOT NULL" $n_notifs || return $? + refresh=`echo "$result" | head -n 1` + if [ -z "$refresh" ]; then + echo "FAIL" + return 0 + fi + + ok=1 + echo "OK" +} + + +test_refresh() { + ok=0 + + echo -n "refresh." + pg_wait $((GLITE_RTM_TEST_TTL * 3 / 4)) "SELECT notifid FROM notifs WHERE notifid IS NOT NULL AND refresh>'$refresh'" $n_notifs || return $? + if [ -z "$result" ]; then + echo "FAIL" + return 0 + fi + + ok=1 + echo "OK" +} + + +test_jdl() { + ok=0 + +# kill_daemons +# cleanup_mysql && cleanup_pg || return $? +# run_daemons || return $? + + # need to wait for notifications to avoid bootstrap + echo -n "notifs." + pg_wait 20 "SELECT refresh FROM notifs WHERE notifid IS NOT NULL" $n_notifs || return $? + refresh=`echo "$result" | head -n 1` + if [ -z "$refresh" ]; then + echo "FAIL" + return 0 + fi + echo -n "OK " + + echo -n "submitted..." + reg || return $? + pg_wait 10 "SELECT jobid, state FROM jobs WHERE state='Submitted'" || return $? + if [ -z "$result" ]; then + echo "FAIL" + return 0 + fi + echo -n "OK " + + echo -n "waiting..." + cat > jdl.txt << EOF +[ + VirtualOrganisation = "TestingVO"; +] +EOF + ev -s NetworkServer -e Accepted --from='UserInterface' --from_host=`hostname -f` --from_instance="pid$$" || return $? + ev -s NetworkServer -e EnQueued --queue "very long and chaotic queue" --job=`pwd`/jdl.txt --result START || return $? + ev -s NetworkServer -e EnQueued --queue "very long and chaotic queue" --job="`cat jdl.txt`" --result OK || return $? + pg_wait 10 "SELECT jobid, state FROM jobs WHERE state='Waiting'" || return $? + if [ -z "$result" ]; then + echo "FAIL" + return 0 + fi + echo -n "OK " + + echo -n "waiting and VO..." + pg_wait 10 "SELECT jobid, state FROM jobs WHERE state='Waiting' AND vo='TestingVO'" || return $? + if [ -z "$result" ]; then + echo "FAIL" + return 0 + fi + echo -n "OK " + + # + # test JDL via VO change + # + # never do it at home ;-) + # + + echo -n "changed JDL..." + ev -s NetworkServer -e EnQueued --queue "very long and chaotic queue" --job="[ VirtualOrganisation=\"TestingVO2\";]" --result OK || return $? + pg_wait 10 "SELECT jobid, state FROM jobs WHERE state='Waiting' AND vo='TestingVO2'" || return $? + if [ -z "$result" ]; then + echo "FAIL" + return 0 + fi + echo -n "OK " + + echo -n "changed after waiting..." + ev -s WorkloadManager -e EnQueued --queue "very long and chaotic queue" --destination LogMonitor --dest_host localhost --dest_instance pid$$ --job "(car 'testing=true)" --result=OK || return $? + pg_wait 10 "SELECT jobid, state FROM jobs WHERE state='Ready' AND vo='TestingVO2'" || return $? + if [ -z "$result" ]; then + echo "FAIL" + return 0 + fi + echo -n "ready..." + ev -s NetworkServer -e EnQueued --queue "very long and chaotic queue" --job="[ VirtualOrganisation=\"TestingVO3\";]" --result OK || return $? + pg_wait 10 "SELECT jobid, state FROM jobs WHERE state='Waiting' AND vo='TestingVO3'" || return $? + if [ -z "$result" ]; then + echo "FAIL" + return 0 + fi + + ok=1 + echo "OK" +} + + +test_purge() { + ok=0 + + echo -n "purge." + pg_get "SELECT jobid FROM jobs" || return $? + if [ -z "$lines" -o $lines -le 0 ]; then + echo "no jobs! FAIL" + return 0 + fi + echo -n "P" + jobunique=`echo "$result" | head -n 1 | tr -d '\n'` + jobid="https://`hostname -f`:${GLITE_LB_TEST_SERVER_PORT}/$jobunique" + echo $jobid > jobs + echo "${purge} -a1 -c1 -n1 -e1 -o1 -m "`hostname -f`:${GLITE_LB_TEST_SERVER_PORT}" -j jobs" >> log + echo " jobs = `cat jobs` | tr -d '\n'" >> log + X509_USER_KEY=${X509_USER_KEY} X509_USER_CERT=${X509_USER_CERT} ${purge} -l -a1 -c1 -n1 -e1 -o1 -m "`hostname -f`:${GLITE_LB_TEST_SERVER_PORT}" -j jobs 2> purge-err.tmp >purge.tmp + if [ $? -ne 0 ]; then + echo " FAIL!" + return 2; + fi + rm -f jobs + echo -n "R " + + pg_wait 10 "SELECT * FROM jobs WHERE jobid='$jobunique'" 0 || return $? + if [ x"$lines" != x"0" ]; then + echo "FAIL" + return 0 + fi + + ok=1 + echo "OK" +} + + +quit() { + if [ x"$started" = x"" ]; then + kill_daemons + drop_db + fi + exit 1 +} + + +fatal() { + echo "Fatal error, end" + quit +} + + +start() { + echo -n "Launch: " + create_db || fatal + run_daemons || fatal + echo "OK" + started=1 +} + + +stop() { + kill_daemons + drop_db +} + + +test() { + echo -n "Basic: " + test_basic || fatal + if [ $ok != 1 ]; then quit; fi + + echo -n "Rebind: " + test_rebind || fatal + if [ $ok != 1 ]; then quit; fi + + echo -n "Cleanup: " + test_cleanup || fatal + if [ $ok != 1 ]; then quit; fi + + echo -n "Refresh: " + test_refresh || fatal + if [ $ok != 1 ]; then quit; fi + + echo -n "JDL: " + test_jdl || fatal + if [ $ok != 1 ]; then quit; fi + +# echo -n "Purge: " +# test_purge || fatal +# if [ $ok != 1]; then quit; fi +} + + +case x"$1" in +xstart) + init + start + ;; + +xstop) + init + stop + ;; + +xtest) + init + test + ;; + +x) + init + start + test + stop + ;; + +*) + usage + exit 1 +esac diff --git a/org.glite.lb.harvester/examples/test.sql b/org.glite.lb.harvester/examples/test.sql new file mode 100644 index 0000000..15736f6 --- /dev/null +++ b/org.glite.lb.harvester/examples/test.sql @@ -0,0 +1,55 @@ +-- +-- Inicialization (replace pgsql by actual postgres superuser): +-- +-- 1) grant privileges, someting like this in $data/pg_hba.conf: +-- local all all trust +-- +-- 2) create user: +-- createuser -U pgsql rtm +-- +-- 3) crate database: +-- createuser -U pgsql rtm +-- +-- 4) create tables: +-- psql -U rtm rtm < test.sql +-- + +CREATE TABLE "jobs" ( + jobid VARCHAR PRIMARY KEY, + lb VARCHAR, + ce VARCHAR, + queue VARCHAR, + rb VARCHAR, + ui VARCHAR, + state VARCHAR, + state_entered TIMESTAMP, + rtm_timestamp TIMESTAMP, + active BOOLEAN, + state_changed BOOLEAN, + registered TIMESTAMP, + vo VARCHAR +); + +CREATE TABLE "lb20" ( + ip TEXT NOT NULL, + branch TEXT NOT NULL, + serv_version TEXT NOT NULL, + monitored BOOLEAN DEFAULT FALSE, + last_seen DATE, + first_seen DATE, + + PRIMARY KEY(ip) +); + +CREATE TABLE "notifs" ( + lb VARCHAR, + port INTEGER, + notifid VARCHAR, + notiftype VARCHAR, + valid TIMESTAMP, + refresh TIMESTAMP, + last_update TIMESTAMP, + errors INTEGER, + + PRIMARY KEY(lb, port, notiftype) +); diff --git a/org.glite.lb.harvester/project/ChangeLog b/org.glite.lb.harvester/project/ChangeLog new file mode 100644 index 0000000..3198875 --- /dev/null +++ b/org.glite.lb.harvester/project/ChangeLog @@ -0,0 +1,20 @@ +1.0.0-1 +- Initial version + +1.0.1-1 +- Changes for Real Time Monitor +- Workaround for older Globus +- Minor memleak fixes + +1.0.2-1 +- Less verbosity in reporting single notifications +- Fixed postgres dependency + +1.0.3-1 +- Extended documentation +- Fixed purging +- Fixed build issues + +1.0.4-1 +- Fixed 'nodb' build issues + diff --git a/org.glite.lb.harvester/project/package.description b/org.glite.lb.harvester/project/package.description new file mode 100644 index 0000000..c969e8c --- /dev/null +++ b/org.glite.lb.harvester/project/package.description @@ -0,0 +1,3 @@ +L&B Harvester gathers information about jobs from L&B servers using efficient L&B notification mechanism. It manages notifications and keeps them in a persistent storage (file or database table) to reuse later on next launch. It takes care about refreshing notifications and queries L&B servers back when some notification expires. + +The tool was initially written for Real Time Monitor (project at Imperial College in London), later was extended by MSG publish messaging mechanism for WLCG. diff --git a/org.glite.lb.harvester/project/package.summary b/org.glite.lb.harvester/project/package.summary new file mode 100644 index 0000000..062972a --- /dev/null +++ b/org.glite.lb.harvester/project/package.summary @@ -0,0 +1 @@ +Enhanced L&B notification client. diff --git a/org.glite.lb.harvester/project/version.properties b/org.glite.lb.harvester/project/version.properties new file mode 100644 index 0000000..8366e02 --- /dev/null +++ b/org.glite.lb.harvester/project/version.properties @@ -0,0 +1,2 @@ +module.version=1.0.4 +module.age=1 diff --git a/org.glite.lb.harvester/src/harvester.c b/org.glite.lb.harvester/src/harvester.c new file mode 100644 index 0000000..c105189 --- /dev/null +++ b/org.glite.lb.harvester/src/harvester.c @@ -0,0 +1,2691 @@ +#ident "$Header$" + +/* + * Real time monitor. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WITH_LBU_DB +#include +#include +#endif +#include +#ifndef WITH_OLD_LB +#include +#endif +#include +#include + + +// default number of the threads/sockets +#define RTM_THREADS 5 +// requested notification life in seconds +#define RTM_NOTIF_TTL 86400 +// consider end of the notification life sooner +#define RTM_NOTIF_TTL_TO_DEAD 2 +// poll timeout in seconds +#define RTM_NOTIF_READ_TIMEOUT 5 +// recheck LB server after error in seconds +#define RTM_ERROR_REPEAT_RATE 120 +// initial read loop time (can be infinity) +#define RTM_NOTIF_LOOP_MAX_TIME 1800 +// idle "quit" poll +#define RTM_IDLE_POLL_TIME 0.5 +// purge & summary jobs poll time +#define RTM_SUMMARY_POLL_TIME 600 +// preventive suicide against memleaks and ugly things (12 h) +#define RTM_SUICIDE_TIME 43200 + +#define RTM_SUMMARY_JOBS 100 + +#define RTM_DB_TABLE_JOBS "jobs" +#define RTM_DB_TABLE_LBS "lb20" +#define DBPAR(N) ("$" (N)) +#define DBAMP "\"" + +// debug message level: insane, debug, progress, warning, error +#define INS 4 +#define DBG 3 +#define INF 2 +#define WRN 1 +#define ERR 0 +#define DEBUG_LEVEL_MASK 7 +#define DEBUG_GUARD_MASK 8 + +// internal quit codes +#define RTM_QUIT_RUN 0 +#define RTM_QUIT_CLEANUP 1 +#define RTM_QUIT_PRESERVE 2 +#define RTM_QUIT_RELOAD 3 + +// exit codes +#define RTM_EXIT_OK 0 +#define RTM_EXIT_RELOAD 1 +#define RTM_EXIT_ERROR 2 + +#define RTM_NOTIF_TYPE_STATUS 1 +#define RTM_NOTIF_TYPE_JDL 2 +#define RTM_NOTIF_TYPE_OLD 3 +#define RTM_NOTIF_TYPE_DONE 4 + +#ifdef RTM_NO_COLORS +#define RTM_TTY_RED "" +#define RTM_TTY_GREEN "" +#define RTM_TTY_RST "" +#else +#define RTM_TTY_RED "\e[1;31m" +#define RTM_TTY_GREEN "\e[1;32m" +#define RTM_TTY_RST "\e[0;39m" +#endif + +#ifndef LINE_MAX +#define LINE_MAX 1023 +#endif + +#define RTM_FILE_NOTIFS "/var/tmp/notifs.txt" +#define RTM_FILE_NOTIF_PRINTF "%s\t%s\t%s\t%s\t%s\t%d\n" +#define RTM_FILE_NOTIF_SCANF "%511[^\t]\t%511[^\t]\t%511[^\t]\t%511[^\t]\t%511[^\t]\t%511[^\t\r\n]\n" +#define RTM_FILE_NOTIF_NUM 6 + +#define WLCG_FILENAME_TEMPLATE "/tmp/wlcg_%02d_XXXXXX" +#define WLCG_COMMAND_MESSAGE "/opt/lcg/bin/msg-publish -c /opt/lcg/etc/msg-publish.conf org.wlcg.usage.jobStatus %s" +#define WLCG_BINARY "/usr/bin/msg-publish" +#define WLCG_CONFIG "/etc/msg-publish/msg-publish.conf" +#define WLCG_TOPIC "org.wlcg.usage.jobStatus" + + +#ifdef WITH_OLD_LB +#define glite_jobid_t edg_wlc_JobId +#define glite_jobid_create edg_wlc_JobIdCreate +#define glite_jobid_recreate edg_wlc_JobIdRecreate +#define glite_jobid_dup edg_wlc_JobIdDup +#define glite_jobid_free edg_wlc_JobIdFree +#define glite_jobid_parse edg_wlc_JobIdParse +#define glite_jobid_unparse edg_wlc_JobIdUnparse +#define glite_jobid_getServer edg_wlc_JobIdGetServer +#define glite_jobid_getServerParts edg_wlc_JobIdGetServerParts +#define glite_jobid_getUnique edg_wlc_JobIdGetUnique +#define edg_wll_NotifNew(CTX, CONDS, FLAGS, SOCK, LADDR, ID, VALID) edg_wll_NotifNew((CTX), (CONDS), (SOCK), (LADDR), (ID), (VALID)) +#define edg_wll_JDLField(STAT, NAME) NULL +#ifndef GLITE_JOBID_DEFAULT_PORT +#define GLITE_JOBID_DEFAULT_PORT GLITE_WMSC_JOBID_DEFAULT_PORT +#endif +#endif + +// TODO: ipv6? :-) + +typedef struct { + edg_wll_NotifId id; // notification context (after bootstrap/rebind) + char *id_str; // notification id string + int type; // for distinguish various notifications on one LB + char *server; // LB server hostname + unsigned int port; // LB server port + time_t valid; // maximal validity of the notification + time_t refresh; // when try to refresh (before expiration), + // used for retry time after error too + double last_update; // last change from the server + int active; // helper (compare LB servers and notifications, + // if to save to the persistent storage) + int error; // errors counter +} notif_t; + +typedef struct { + int id; + pthread_t thread; + notif_t *notifs; + int nservers; + time_t next_refresh; + char time_s[100]; + char *dash_filename; + int dash_fd; +#ifdef WITH_LBU_DB + glite_lbu_DBContext dbctx; + glite_lbu_Statement insertcmd, updatecmd, updatecmd_vo, updatecmd_mon, deletecmd; + int dbcaps; +#endif +} thread_t; + +typedef struct { + char *local_address; + int nthreads; + char *config_file; + char *notif_file; + int debug; + int guard; + int daemonize; + char *pidfile; + int dive; + char *dbcs; // DB connection string + char *cert, *key; + int ttl; // requested time to live (validity) of the notifications + int cleanup; // if to clean up notifications on LB servers + int wlcg; // dashboard messaging + int wlcg_no_remove; // don't remove temporary files (for debugging) + char *wlcg_binary; // path msg-publish binary + char *wlcg_config; // msg config file + char *wlcg_topic; // msg topic + int wlcg_flush; // send message for eachnotification + int silly; // old LB 1.9 mode + int no_purge; // disabled reaction on purge state + + int nservers; + notif_t *notifs; +} config_t; + +typedef struct { + notif_t *notifs; + int n, maxn; + pthread_mutex_t lock; + double last_check; + int was_summary; // flag for debugging +#ifdef WITH_LBU_DB + glite_lbu_DBContext dbctx; +#endif +} db_t; + + +static const char rcsid[] = "@(#)$Id$"; + +static int rtm2syslog[] = { + LOG_ERR, + LOG_WARNING, + LOG_INFO, + LOG_DEBUG, + LOG_DEBUG, +}; + +static const struct option opts[] = { + { "wlcg-binary", required_argument, NULL, 0}, + { "wlcg-config", required_argument, NULL, 0}, + { "wlcg-topic", required_argument, NULL, 0}, + { "wlcg-flush", no_argument, NULL, 0}, + { "help", no_argument, NULL, 'h'}, + { "version", no_argument, NULL, 'v'}, + { "threads", required_argument, NULL, 's'}, + { "debug", required_argument, NULL, 'd'}, + { "daemonize", no_argument, NULL, 'D'}, + { "pidfile", required_argument, NULL, 'i'}, + { "ttl", required_argument, NULL, 't'}, + { "history", required_argument, NULL, 'H'}, + { "config", required_argument, NULL, 'c'}, + { "notifs", required_argument, NULL, 'n'}, + { "port", required_argument, NULL, 'p'}, + { "pg", required_argument, NULL, 'm'}, + { "cert", required_argument, NULL, 'C'}, + { "key", required_argument, NULL, 'K'}, + { "wlcg", no_argument, NULL, 'w'}, + { "old", no_argument, NULL, 'o'}, + { "cleanup", no_argument, NULL, 'l'}, + { "no-purge", no_argument, NULL, 'u'}, + { NULL, no_argument, NULL, 0} +}; + +static const char *opts_line = "hvs:d:Di:t:H:c:n:p:m:C:K:wolu"; + +config_t config = { + local_address: NULL, + nthreads: RTM_THREADS, + config_file: NULL, + notif_file: NULL, + debug: DBG, + guard: 1, + dive: 10800, + dbcs: NULL, + cert: NULL, + key: NULL, + ttl: RTM_NOTIF_TTL, + cleanup: 0, + wlcg: 0, + silly: 0, + no_purge: 0, + + nservers: 0, + notifs: NULL, +}; +db_t db = { + notifs: NULL, + n: 0, + maxn: 0, + lock: PTHREAD_MUTEX_INITIALIZER, +#ifdef WITH_LBU_DB + dbctx: NULL +#endif +}; +thread_t *threads = NULL; +volatile sig_atomic_t quit = RTM_QUIT_RUN; + +static int listen_port = 0; + +#define lprintf(T, LEVEL, FMT, ARGS...) \ + if ((LEVEL) <= config.debug) lprintf_func((T), (LEVEL), (FMT), ##ARGS) +#define lprintf_ctx(T, LEVEL, CTX, FMT, ARGS...) \ + if ((LEVEL) <= config.debug) lprintf_ctx_func((T), (CTX), (LEVEL), (FMT), ##ARGS) +#define lprintf_dbctx(T, LEVEL, FMT, ARGS...) \ + if ((LEVEL) <= config.debug) lprintf_dbctx_func((T), (LEVEL), (FMT), ##ARGS) + +#ifdef WITH_OLD_LB +int edg_wll_gss_initialize() { + if (globus_module_activate(GLOBUS_GSI_GSSAPI_MODULE) != GLOBUS_SUCCESS) return EINVAL; + return 0; +} +#endif + +void lvprintf_func(thread_t *t, const char *description, int level, const char *fmt, va_list ap) { + char prefix[10]; + char *msg, *line; + + if (t) snprintf(prefix, sizeof prefix, "[%02d]", t->id); + else memcpy(prefix, "[main]", 8); + vasprintf(&msg, fmt, ap); + if (description) asprintf(&line, "%s %s, %s\n", prefix, msg, description); + else asprintf(&line, "%s %s\n", prefix, msg); + free(msg); + + if (level <= WRN && !config.daemonize) fprintf(stderr, RTM_TTY_RED); + if (config.daemonize) { + openlog(NULL, LOG_PID | LOG_CONS, LOG_DAEMON); + syslog(rtm2syslog[level], "%s", line); + closelog(); + } else { + fputs(line, stderr); + } + if (level <= WRN && !config.daemonize) fprintf(stderr, RTM_TTY_RST); + + free(line); +} + + +void lprintf_func(thread_t *t, int level, const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + lvprintf_func(t, NULL, level, fmt, ap); + va_end(ap); +} + + +void lprintf_ctx_func(thread_t *t, edg_wll_Context ctx, int level, const char *fmt, ...) { + va_list ap; + char *errText, *errDesc, *s; + + va_start(ap, fmt); + edg_wll_Error(ctx, &errText, &errDesc); + asprintf(&s, "%s: %s", errText, errDesc); + lvprintf_func(t, s, level, fmt, ap); + free(errText); + free(errDesc); + free(s); + va_end(ap); +} + + +#ifdef WITH_LBU_DB +void lprintf_dbctx_func(thread_t *t, int level, const char *fmt, ...) { + va_list ap; + char *errText = NULL, *errDesc = NULL, *s = NULL; + glite_lbu_DBContext dbctx = t ? t->dbctx : db.dbctx; + + va_start(ap, fmt); + if (dbctx) { + glite_lbu_DBError(dbctx, &errText, &errDesc); + asprintf(&s, "%s: %s", errText, errDesc); + } + lvprintf_func(t, s, level, fmt, ap); + free(errText); + free(errDesc); + free(s); + va_end(ap); +} +#endif + +#ifndef WITH_LBU_DB +time_t glite_lbu_StrToTime(const char *str) { + struct tm tm; + + memset(&tm,0,sizeof(tm)); + putenv("TZ=UTC"); tzset(); + sscanf(str,"%4d-%02d-%02d %02d:%02d:%02d", + &tm.tm_year,&tm.tm_mon,&tm.tm_mday, + &tm.tm_hour,&tm.tm_min,&tm.tm_sec); + tm.tm_year -= 1900; + tm.tm_mon--; + + return mktime(&tm); +} + +double glite_lbu_StrToTimestamp(const char *str) { + struct tm tm; + double sec; + + memset(&tm,0,sizeof(tm)); + putenv("TZ=UTC"); tzset(); + sscanf(str,"%4d-%02d-%02d %02d:%02d:%lf", + &tm.tm_year,&tm.tm_mon,&tm.tm_mday, + &tm.tm_hour,&tm.tm_min,&sec); + tm.tm_year -= 1900; + tm.tm_mon--; + tm.tm_sec = sec; + + return (sec - tm.tm_sec) + mktime(&tm); +} +#endif + + +// hacky time->string conversion +char *time2str(thread_t *t, time_t time) { + struct tm tm; + + if ((int)time <= 0) memcpy(t->time_s, "-", sizeof("-")); + else { + localtime_r(&time, &tm); + strftime(t->time_s, sizeof(t->time_s), "%F %T", &tm); + } + return t->time_s; +} + + +double rtm_gettimeofday() { + struct timeval tv; + + gettimeofday(&tv, NULL); + return tv.tv_sec + tv.tv_usec / 1000000.0; +} + + +void rtm_time2str(time_t t, char **str) { + struct tm *tm; + + if (t) { + tm = gmtime(&t); + asprintf(str,"%4d-%02d-%02d %02d:%02d:%02d",tm->tm_year+1900,tm->tm_mon+1, + tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec); + } else + *str = strdup("-"); +} + + +void rtm_timestamp2str(double t, char **str) { + time_t tsec = t; + struct tm *tm = gmtime(&tsec); + + if (t) { + t = t - tsec + tm->tm_sec; + asprintf(str,"%4d-%02d-%02d %02d:%02d:%02.09f",tm->tm_year+1900,tm->tm_mon+1, + tm->tm_mday,tm->tm_hour,tm->tm_min,t); + } else + *str = strdup("-"); +} + + +int rtm_str2time(const char *s) { + time_t t; + + if (s && memcmp(s, "-", 2) != 0) { + t = glite_lbu_StrToTime(s); + if (t == (time_t)-1) return 0; + } else + t = 0; + + return t; +} + + +int rtm_str2timestamp(const char *s) { + double t; + + if (s && memcmp(s, "-", 2) != 0) { + t = glite_lbu_StrToTimestamp(s); + if (t <= 0.5) return 0.0; + } else + t = 0.0; + + return t; +} + + +int rtm_str2notiftype(const char *str) { + if (strcasecmp(str, "STATUS") == 0) return RTM_NOTIF_TYPE_STATUS; + if (strcasecmp(str, "DONE") == 0) return RTM_NOTIF_TYPE_DONE; + if (strcasecmp(str, "JDL") == 0) return RTM_NOTIF_TYPE_JDL; + if (strcasecmp(str, "OLD") == 0) return RTM_NOTIF_TYPE_OLD; + return -1; +} + + +const char *rtm_notiftype2str(int type) { + switch (type) { + case RTM_NOTIF_TYPE_STATUS: return "STATUS"; + case RTM_NOTIF_TYPE_DONE: return "DONE"; + case RTM_NOTIF_TYPE_JDL: return "JDL"; + case RTM_NOTIF_TYPE_OLD: return "OLD"; + default: return NULL; + } +} + + +/** + * Cut the network server hostname from the full URL (got from RegJob event). + * + * Formats (only the first one should be in the wild): + * https://wms2.egee.cesnet.cz:7443/glite_wms_wmproxy_server + * wms2.egee.cesnet.cz + * 147.228.1.129 + * HTTPS://[2001:0f68:0000:0000:0000:0000:1986:69af]:80/ + * 2001:0f68::1986:69af + */ +char* rtm_ns2hostname(const char *network_server) { + char *ns, *pos; + size_t len; + + if (strncasecmp(network_server, "https://", 8) == 0) { + ns = strdup(network_server + 8); + // first backslash - path + pos = strchr(ns, '/'); + if (pos) pos[0] = '\0'; + // last colon - port separator + pos = strrchr(ns, ':'); + if (pos) pos[0] = '\0'; + // brackets - IPv6 address + len = strlen(ns); + if (len >= 2 && ns[0] == '[' && ns[len - 1] == ']') { + pos = strndup(ns + 1, len - 2); + free(ns); + ns = pos; + } + return ns; + } else + return strdup(network_server); +} + + +void wlcg_timeval2str(struct timeval *t, char **str) { + struct tm *tm; + + tm = gmtime(&t->tv_sec); + asprintf(str,"%4d-%02d-%02dT%02d:%02d:%02dZ",tm->tm_year+1900,tm->tm_mon+1, + tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec); +} + + +int wlcg_store_message(thread_t *t, __attribute((unused))notif_t *notif, edg_wll_JobStat *stat) { + unsigned int port; + int status = 0; + char *jobid_str = NULL, *state_str = NULL, *vo = NULL, *lbhost = NULL, *network_host = NULL; + char *wlcg_last_update_time_str = NULL, *wlcg_state_start_time_str = NULL; + + jobid_str = stat->jobId ? glite_jobid_unparse(stat->jobId) : strdup("Unknown"); + glite_jobid_getServerParts(stat->jobId, &lbhost, &port); + state_str = edg_wll_StatToString(stat->state); + vo = edg_wll_JDLField(stat,"VirtualOrganisation") ? : strdup("Unknown"); + network_host = stat->network_server ? rtm_ns2hostname(stat->network_server) : NULL; + + if (!t->dash_filename || !t->dash_fd) { + free(t->dash_filename); + asprintf(&t->dash_filename, WLCG_FILENAME_TEMPLATE, t->id); + if ((t->dash_fd = mkstemp(t->dash_filename)) == -1) { + status = errno; + lprintf(t, ERR, "can't create temporary file '%s': %s", t->dash_filename, strerror(status)); + free(t->dash_filename); + t->dash_filename = NULL; + goto quit; + } + } + + wlcg_timeval2str(&stat->lastUpdateTime, &wlcg_last_update_time_str); + wlcg_timeval2str(&stat->stateEnterTime, &wlcg_state_start_time_str); + + dprintf(t->dash_fd, "jobId: %s\n\ +stateName: %s\n\ +ownerDN: %s\n\ +voname: %s\n\ +bkHost: %s:%d\n\ +networkHost: %s\n\ +lastUpdateTime: %s\n\ +stateStartTime: %s\n\ +exitCode: %d\n\ +DoneCode: %d\n\ +destSite: %s\n\ +condorId: %s\n\ +StatusReason: %s\n\ +EOT\n", jobid_str, state_str, stat->owner, vo, lbhost, port, network_host ? : "unknown", wlcg_last_update_time_str, wlcg_state_start_time_str, stat->exit_code, stat->done_code, stat->destination ? : "NULLByPublisher", stat->condorId ? : "0", stat->reason && stat->reason[strspn(stat->reason, " \t\n\r")] != '\0' ? stat->reason : "UNAVAILABLE By Publisher"); + + free(wlcg_last_update_time_str); + free(wlcg_state_start_time_str); +quit: + free(jobid_str); + free(lbhost); + free(network_host); + free(state_str); + free(vo); + return status; +} + + +int wlcg_send_message(thread_t *t) { + int status = 0; + char *command; + + // WLCG message + if (t->dash_fd) { // send only if anything to send + close(t->dash_fd); + asprintf(&command, "'%s' -c '%s' '%s' '%s'", config.wlcg_binary, config.wlcg_config, config.wlcg_topic, t->dash_filename); + lprintf(t, DBG, "calling %s", command); + switch (vfork()) { + case 0: + if (execlp("/bin/sh", "/bin/sh", "-c", command, NULL) == -1) { + lprintf(t, ERR, "can't exec '%s':%s", command, strerror(errno)); + } + _exit(1); + break; + case -1: + lprintf(t, ERR, "can't fork: %s", strerror(errno)); + break; + default: + break; + } + wait(&status); + free(command); + if (WIFEXITED(status)) { + status = WEXITSTATUS(status); + if (status) { + lprintf(t, WRN, "%s exited with %d", config.wlcg_binary, status); + } else { + lprintf(t, DBG, "%s exited successfully", config.wlcg_binary); + if (!config.wlcg_no_remove) remove(t->dash_filename); + } + } else { + lprintf(t, ERR, "%s not exited normally", config.wlcg_binary); + status = -1; + } + free(t->dash_filename); + t->dash_filename = NULL; + t->dash_fd = 0; + } + + return status; +} + + +void notif_free(notif_t *notif) { + edg_wll_NotifIdFree(notif->id); + free(notif->id_str); + free(notif->server); + memset(notif, 0, sizeof(notif_t)); +} + + +void notif_invalidate(notif_t *notif) { + edg_wll_NotifIdFree(notif->id); + free(notif->id_str); + notif->id = NULL; + notif->id_str = NULL; + notif->error = 0; +} + + +int notif_copy(notif_t *dest, notif_t *src) { + if (!src || !dest) return EINVAL; + memset(dest, 0, sizeof(notif_t)); + if (src->id) dest->id = edg_wll_NotifIdDup(src->id); + if (src->id_str) dest->id_str = strdup(src->id_str); + dest->type = src->type; + if (src->server) dest->server = strdup(src->server); + dest->port = src->port; + dest->valid = src->valid; + dest->refresh = src->refresh; + dest->last_update = src->last_update; + dest->active = src->active; + dest->error = src->error; + return 0; +} + + +#ifdef WITH_LBU_DB +static int db_init(thread_t *t, glite_lbu_DBContext *dbctx) { + int err, dbcaps; + + if (config.dbcs) { + if ((err = glite_lbu_InitDBContext(dbctx, GLITE_LBU_DB_BACKEND_PSQL)) != 0) { + lprintf_dbctx(t, ERR, "can't initialize DB context"); + return err; + } + while ((err = glite_lbu_DBConnect(*dbctx, config.dbcs)) != 0 && !quit) { + lprintf_dbctx(t, ERR, "can't connect to '%s'", config.dbcs); + lprintf(t, INF, "still trying..."); + sleep(5); + } + if (err == 0) { + if ((dbcaps = glite_lbu_DBQueryCaps(*dbctx)) == -1) { + lprintf_dbctx(t, ERR, "can't get database capabilities"); + dbcaps = 0; + } + lprintf(t, INF, "DB connected, cs: %s, capabilities: %d", config.dbcs, dbcaps); + if (t == NULL && (dbcaps & GLITE_LBU_DB_CAP_PREPARED) == 0) { + lprintf(NULL, WRN, "postgresql server doesn't support SQL prepared commands, recommended version >= 8.2"); + } + if (t) t->dbcaps = dbcaps; + return 0; + } else { + glite_lbu_FreeDBContext(*dbctx); + return err; + } + } else { + lprintf(t, DBG, "no DB configured (--pg option)"); + return -1; + } +} + + +static void db_free(__attribute((unused))thread_t *t, glite_lbu_DBContext dbctx) { + if (dbctx) { + glite_lbu_DBClose(dbctx); + glite_lbu_FreeDBContext(dbctx); + } +} +#endif + + +static notif_t *db_add_notif(char *notifid, int type, time_t valid, time_t refresh, double last_update, char *server, int port, int active, int errors) { + void *tmp; + notif_t *notif; + + if (db.n >= db.maxn) { + db.maxn = db.n + 20; + if ((tmp = realloc(db.notifs, db.maxn * sizeof(notif_t))) == NULL) return NULL; + db.notifs = (notif_t *)tmp; + memset(db.notifs + db.n, 0, (db.maxn - db.n) * sizeof(notif_t)); + } + notif = db.notifs + db.n; + notif->id_str = notifid; + notif->type = type; + notif->valid = valid; + notif->refresh = refresh; + notif->last_update = last_update; + notif->server = server; + notif->port = port; + notif->active = active; + notif->error = errors; + db.n++; + + return notif; +} + + +static int db_save_notifs_file(thread_t *t) { + FILE *f; + char *filename = NULL; + int retval = 1; + notif_t *notif; + int i; + char *valid_str = NULL, *refresh_str = NULL, *last_update_str = NULL, *id_str = NULL; + + asprintf(&filename, "%s-new", config.notif_file); + if ((f = fopen(filename, "wt")) == NULL) { + lprintf(t, ERR, "can't write '%s': %s", filename, strerror(errno)); + goto quit; + } + + for (i = 0; i < db.n; i++) { + notif = db.notifs + i; + if (!notif->active) { + lprintf(t, DBG, "not saving inactive notif %s (%s), server %s:%d", notif->id_str, rtm_notiftype2str(notif->type), notif->server, notif->port); + continue; + } + + if (notif->id_str) id_str = strdup(notif->id_str); + else if (notif->error) asprintf(&id_str, "%s:%d", notif->server, notif->port); + if (id_str) { + rtm_time2str(notif->valid, &valid_str); + rtm_time2str(notif->refresh, &refresh_str); + rtm_timestamp2str(notif->last_update, &last_update_str); + + fprintf(f, RTM_FILE_NOTIF_PRINTF, id_str, rtm_notiftype2str(notif->type), valid_str, refresh_str, last_update_str, notif->error); + + free(valid_str); valid_str = NULL; + free(refresh_str); refresh_str = NULL; + free(last_update_str); last_update_str = NULL; + } + free(id_str); + id_str = NULL; + } + fclose(f); + if (rename(filename, config.notif_file) != 0) { + lprintf(t, ERR, "can't move new notification file '%s' to '%s': %s", filename, config.notif_file, strerror(errno)); + goto quit; + } + retval = 0; +quit: + free(filename); + free(valid_str); + free(refresh_str); + free(last_update_str); + return 0; +} + + +#if defined(WITH_RTM_SQL_STORAGE) && defined(WITH_LBU_DB) +static int db_save_notifs_sql(thread_t *t) { + int retval = 1; + notif_t *notif; + int i; + char *sql = NULL, *valid_str = NULL, *refresh_str = NULL, *last_update_str = NULL; + const char *type_str, *amp; + + for (i = 0; i < db.n; i++) { + notif = db.notifs + i; +/* + if (!notif->active) { + lprintf(t, INS, "not saving inactive notif %s (%s:%d)", notif->id_str, notif->server, notif->port); + continue; + } +*/ + type_str = rtm_notiftype2str(notif->type); + if (notif->id_str || notif->error) { + if (notif->valid) glite_lbu_TimeToDB(db.dbctx, notif->valid, &valid_str); + else valid_str = strdup("NULL"); + if (notif->refresh) glite_lbu_TimeToDB(db.dbctx, notif->refresh, &refresh_str); + else refresh_str = strdup("NULL"); + if (notif->last_update) glite_lbu_TimestampToDB(db.dbctx, notif->last_update, &last_update_str); + else last_update_str = strdup("NULL"); + amp = notif->id_str ? "'" : " "; + trio_asprintf(&sql, "UPDATE notifs SET notifid=%s%|Ss%s, valid=%s, refresh=%s, last_update=%s, errors=%d WHERE lb='%|Ss' AND port=%d AND notiftype='%|Ss'", amp, notif->id_str ? : "NULL", amp, valid_str, refresh_str, last_update_str, notif->error, notif->server, notif->port, type_str); + switch (glite_lbu_ExecSQL(db.dbctx, sql, NULL)) { + case 0: + // not found - insert + // can be handy when using file as input of LBs + free(sql); + trio_asprintf(&sql, "INSERT INTO notifs (lb, port, notifid, notiftype, valid, refresh, last_update, errors) VALUES ('%|Ss', %d, %s%|Ss%s, '%|Ss', %s, %s, %s, %d)", notif->server, notif->port, amp, notif->id_str ? : "NULL", amp, type_str, valid_str, refresh_str, last_update_str, notif->error); + switch (glite_lbu_ExecSQL(db.dbctx, sql, NULL)) { + case -1: + lprintf_dbctx(t, ERR, "notif '%s' (%s) insert failed", notif->id_str, type_str); + goto quit; + case 0: + lprintf(t, ERR, "notif '%s' (%s) not inserted for unknown reason", type_str); + break; + default: + lprintf(t, INS, "notif '%s' (%s) inserted", notif->id_str, type_str); + break; + } + break; + case -1: + lprintf_dbctx(t, ERR, "notif '%s' (%s) update failed", notif->id_str, type_str); + goto quit; + default: + lprintf(t, INS, "notif '%s' updated", notif->id_str); + break; + } + } else { + trio_asprintf(&sql, "UPDATE notifs SET notifid=NULL, valid=NULL, refresh=NULL, last_update=NULL WHERE lb='%|Ss' AND port=%d AND notiftype='%|Ss'", notif->server, notif->port, type_str); + switch (glite_lbu_ExecSQL(db.dbctx, sql, NULL)) { + case 0: + lprintf(t, INS, "cleared %s notif for %s:%d not found, ok", type_str, notif->server, notif->port); + break; + case -1: + lprintf_dbctx(t, ERR, "clearing notif %s for %s:%d failed", type_str, notif->server, notif->port); + goto quit; + default: + lprintf(t, INS, "cleared notif %s for %s:%d", type_str, notif->server, notif->port); + break; + } + } + free(sql); sql = NULL; + free(valid_str); valid_str = NULL; + free(refresh_str); refresh_str = NULL; + free(last_update_str); last_update_str = NULL; + } + retval = 0; +quit: + free(sql); + free(valid_str); + free(refresh_str); + free(last_update_str); + return 0; +} +#endif + + +static int db_save_notifs(thread_t *t) { +#if 0 + int i; + + for (i = 0; i < db.n; i++) { + notif_t *notif = db.notifs + i; + lprintf(NULL, DBG, "save: %s (%s), server: %s:%d, active: %d", notif->id_str, rtm_notiftype2str(notif->type), notif->server, notif->port, notif->active); + } +#endif + +#if defined(WITH_LBU_DB) + int i, ret; + notif_t *notif; + + // + // Keep monitored flag when: + // 1) used and opened DB + // 2) LB servers not from config file + // + if (t && t->dbctx && !config.config_file) { + for (i = 0; i < t->nservers; i++) { + notif = t->notifs + i; + + if (notif->type == RTM_NOTIF_TYPE_OLD || notif->type == RTM_NOTIF_TYPE_JDL) { + lprintf(t, DBG, "changing monitored flag of %d. notification for %s:%d to %d", i, notif->server, notif->port, notif->error ? 0 : 1); + if ((t->dbcaps & GLITE_LBU_DB_CAP_PREPARED) == 0) { + char *sql; + + trio_asprintf(&sql, "UPDATE " DBAMP RTM_DB_TABLE_LBS DBAMP " SET monitored=%s WHERE ip='%|Ss'", notif->error ? "false" : "true", notif->server); + ret = glite_lbu_ExecSQL(t->dbctx, sql, NULL); + free(sql); + } else { + ret = glite_lbu_ExecPreparedStmt(t->updatecmd_mon, 2, + GLITE_LBU_DB_TYPE_BOOLEAN, notif->error ? 0 : 1, + GLITE_LBU_DB_TYPE_VARCHAR, notif->server + ); + } + if (ret == -1) { + lprintf_dbctx(t, ERR, "can't update monitored flag in " RTM_DB_TABLE_LBS " table"); + return 1; + } + } + } + } +#endif + +#if defined(WITH_RTM_SQL_STORAGE) && defined(WITH_LBU_DB) + if (!db.dbctx) return db_save_notifs_file(t); + else return db_save_notifs_sql(t); +#else + return db_save_notifs_file(t); +#endif +} + + +static notif_t *db_search_notif(notif_t *notifs, int n, const char *notifid) { + int i; + + for (i = 0; i < n && (!notifs[i].id_str || strcmp(notifs[i].id_str, notifid) != 0); i++); + return i == n ? NULL : notifs + i; +} + + +static notif_t *db_search_notif_by_server(notif_t *notifs, int n, const char *server, unsigned int port, int type) { + int i; + + for (i = 0; i < n; i++) { + if (strcmp(notifs[i].server, server) == 0 && notifs[i].port == port && notifs[i].type == type) break; + } + + return i == n ? NULL : notifs + i; +} + + +#ifdef WITH_LBU_DB +typedef struct { + char *lb; + char *jobid; + char *unique_str; + char *ce; + char *queue; + char *rb; + char *ui; + char *state; + double state_entered; + double rtm_timestamp; + int registered; + char * vo; +} db_job_t; + + +// +// store state into dababase +// on purged status deletes the record +// +static void db_store_change_perform_sql(thread_t *t, edg_wll_JobStatCode state, db_job_t *rec) { + char *state_entered_str = NULL, *rtm_timestamp_str = NULL, *regtime_str = NULL; + char *sql = NULL, *sql2 = NULL, *sql_part = NULL; + const char *active = "true", *state_changed = "true"; + + if (state == EDG_WLL_JOB_PURGED) { + if (!config.no_purge) { + lprintf(t, DBG, "purge %s", rec->jobid); + if ((t->dbcaps & GLITE_LBU_DB_CAP_PREPARED) == 0) { + trio_asprintf(&sql, "DELETE FROM " RTM_DB_TABLE_JOBS " WHERE jobid='%|Ss' AND lb='%|Ss'", rec->unique_str, rec->lb); + lprintf(t, INS, "delete: %s", sql); + if (glite_lbu_ExecSQL(t->dbctx, sql, NULL) == -1) { + lprintf_dbctx(t, WRN, "can't delete job %s", rec->jobid); + goto quit; + } + } else { + if (glite_lbu_ExecPreparedStmt(t->deletecmd, 2, + GLITE_LBU_DB_TYPE_VARCHAR, rec->unique_str, + GLITE_LBU_DB_TYPE_VARCHAR, rec->lb + ) == -1) { + lprintf_dbctx(t, WRN, "can't delete job %s", rec->jobid); + goto quit; + } + } + } + } else { + if ((t->dbcaps & GLITE_LBU_DB_CAP_PREPARED) == 0) { + glite_lbu_TimestampToDB(t->dbctx, rec->state_entered, &state_entered_str); + glite_lbu_TimestampToDB(t->dbctx, rec->rtm_timestamp, &rtm_timestamp_str); + glite_lbu_TimeToDB(t->dbctx, rec->registered, ®time_str); + + if (rec->vo) trio_asprintf(&sql_part, ", vo='%|Ss' ", rec->vo); + else sql_part = strdup(""); + trio_asprintf(&sql, "UPDATE " RTM_DB_TABLE_JOBS " SET ce='%|Ss', queue='%|Ss', rb='%|Ss', ui='%|Ss', state='%|Ss', state_entered=%s, rtm_timestamp=%s, active=%s, state_changed=%s, registered=%s%sWHERE jobid='%|Ss' AND lb='%|Ss'", rec->ce, rec->queue, rec->rb, rec->ui, rec->state, state_entered_str, rtm_timestamp_str, active, state_changed, regtime_str, sql_part, rec->unique_str, rec->lb); + lprintf(t, INS, "update: %s", sql); + switch (glite_lbu_ExecSQL(t->dbctx, sql, NULL)) { + case -1: + lprintf_dbctx(t, ERR, "can't get jobs"); + goto quit; + case 0: + trio_asprintf(&sql2, "INSERT INTO " RTM_DB_TABLE_JOBS " " + "(ce, queue, rb, ui, state, state_entered, rtm_timestamp, jobid, lb, active, state_changed, registered, vo) VALUES " + "('%|Ss', '%|Ss', '%|Ss', '%|Ss', '%|Ss', %s, %s, '%|Ss', '%|Ss', %s, %s, %s, '%|Ss')", rec->ce, rec->queue, rec->rb, rec->ui, rec->state, state_entered_str, rtm_timestamp_str, rec->unique_str, rec->lb, active, state_changed, regtime_str, rec->vo ? : "unknown"); + lprintf(t, INS, "insert: %s", sql2); + if (glite_lbu_ExecSQL(t->dbctx, sql2, NULL) == -1) { + lprintf_dbctx(t, ERR, "can't insert job"); + goto quit; + } + break; + default: + break; + } + } else { // prepared commands + int ret; + + if (rec->vo) { + ret = glite_lbu_ExecPreparedStmt(t->updatecmd_vo, 13, + GLITE_LBU_DB_TYPE_VARCHAR, rec->ce, + GLITE_LBU_DB_TYPE_VARCHAR, rec->queue, + GLITE_LBU_DB_TYPE_VARCHAR, rec->rb, + GLITE_LBU_DB_TYPE_VARCHAR, rec->ui, + GLITE_LBU_DB_TYPE_VARCHAR, rec->state, + GLITE_LBU_DB_TYPE_TIMESTAMP, rec->state_entered, + GLITE_LBU_DB_TYPE_TIMESTAMP, rec->rtm_timestamp, + GLITE_LBU_DB_TYPE_BOOLEAN, 1, // active + GLITE_LBU_DB_TYPE_BOOLEAN, 1, // state_changed + GLITE_LBU_DB_TYPE_TIMESTAMP, (double)rec->registered, + GLITE_LBU_DB_TYPE_VARCHAR, rec->vo, // VO + + GLITE_LBU_DB_TYPE_VARCHAR, rec->unique_str, // jobid + GLITE_LBU_DB_TYPE_VARCHAR, rec->lb // L&B server + ); + } else { + ret = glite_lbu_ExecPreparedStmt(t->updatecmd, 12, + GLITE_LBU_DB_TYPE_VARCHAR, rec->ce, + GLITE_LBU_DB_TYPE_VARCHAR, rec->queue, + GLITE_LBU_DB_TYPE_VARCHAR, rec->rb, + GLITE_LBU_DB_TYPE_VARCHAR, rec->ui, + GLITE_LBU_DB_TYPE_VARCHAR, rec->state, + GLITE_LBU_DB_TYPE_TIMESTAMP, rec->state_entered, + GLITE_LBU_DB_TYPE_TIMESTAMP, rec->rtm_timestamp, + GLITE_LBU_DB_TYPE_BOOLEAN, 1, // active + GLITE_LBU_DB_TYPE_BOOLEAN, 1, // state_changed + GLITE_LBU_DB_TYPE_TIMESTAMP, (double)rec->registered, + + GLITE_LBU_DB_TYPE_VARCHAR, rec->unique_str, // jobid + GLITE_LBU_DB_TYPE_VARCHAR, rec->lb // L&B server + ); + } + + switch (ret) { + case -1: + lprintf_dbctx(t, ERR, "can't update " RTM_DB_TABLE_JOBS " table"); + goto quit; + case 0: + if (glite_lbu_ExecPreparedStmt(t->insertcmd, 13, + GLITE_LBU_DB_TYPE_VARCHAR, rec->ce, + GLITE_LBU_DB_TYPE_VARCHAR, rec->queue, + GLITE_LBU_DB_TYPE_VARCHAR, rec->rb, + GLITE_LBU_DB_TYPE_VARCHAR, rec->ui, + GLITE_LBU_DB_TYPE_VARCHAR, rec->state, + GLITE_LBU_DB_TYPE_TIMESTAMP, rec->state_entered, + GLITE_LBU_DB_TYPE_TIMESTAMP, rec->rtm_timestamp, + GLITE_LBU_DB_TYPE_VARCHAR, rec->unique_str, // jobid + GLITE_LBU_DB_TYPE_VARCHAR, rec->lb, // L&B server + GLITE_LBU_DB_TYPE_BOOLEAN, 1, // active + GLITE_LBU_DB_TYPE_BOOLEAN, 1, // state_changed + GLITE_LBU_DB_TYPE_TIMESTAMP, (double)rec->registered, + GLITE_LBU_DB_TYPE_VARCHAR, rec->vo ? : "unknown" // VO + ) == -1) { + lprintf_dbctx(t, ERR, "can't insert to " RTM_DB_TABLE_JOBS " table"); + goto quit; + } + break; + default: + break; + } + } // prepare commands + } + +quit: + free(sql); + free(sql2); + free(sql_part); + free(state_entered_str); + free(rtm_timestamp_str); + free(regtime_str); +} +#endif + + +static int db_store_change(thread_t *t, notif_t *notif, __attribute((unused))int index, edg_wll_JobStat *stat) { + char *jobid_str = NULL, *state_str = NULL, *vo = NULL, *lbhost = NULL; + unsigned int port; + + jobid_str = stat->jobId ? glite_jobid_unparse(stat->jobId) : strdup("unknown"); + glite_jobid_getServerParts(stat->jobId, &lbhost, &port); + state_str = edg_wll_StatToString(stat->state); + vo = edg_wll_JDLField(stat, "VirtualOrganisation"); + printf(RTM_TTY_GREEN "notifid: %s (%s), jobid: %s, state: %s, vo: %s, last time: %lf" RTM_TTY_RST "\n", notif->id_str, rtm_notiftype2str(notif->type), jobid_str, state_str, vo, notif->last_update); + +#ifdef WITH_LBU_DB + if (config.dbcs && t->dbctx) { + db_job_t rec; + char *colon; + char *unique_str = NULL, *network_server = NULL; + + memset(&rec, 0, sizeof rec); + // L&B server + rec.lb = lbhost; + // jobid + uniqe + unique_str = glite_jobid_getUnique(stat->jobId); + rec.unique_str = unique_str; + rec.jobid = jobid_str; + // CE + rec.ce = stat->destination ? : "unknown"; + // queue + rec.queue = strchr(rec.ce, '/'); + if (rec.queue) *rec.queue++='\0'; + else rec.queue = "unknown"; + colon = strchr(rec.ce, ':'); + if (colon) colon[0] = '\0'; + // Virtual Organization + rec.vo = vo; + // Resource Broker + network_server = stat->network_server ? rtm_ns2hostname(stat->network_server) : strdup("unknown"); + rec.rb = network_server; + // UI + rec.ui = stat->ui_host ? : "unknown"; + // state + rec.state = state_str ? : "unknown"; + // state time + rec.state_entered = stat->stateEnterTime.tv_sec + stat->stateEnterTime.tv_usec / 1000000.0; + // notification time + rec.rtm_timestamp = rtm_gettimeofday(); + // registration time + rec.registered = stat->stateEnterTimes[1 + EDG_WLL_JOB_SUBMITTED]; + + // store! + db_store_change_perform_sql(t, stat->state, &rec); + + free(unique_str); + free(network_server); + } +#endif + + // store message + if (config.wlcg) { + if (wlcg_store_message(t, notif, stat) != 0) goto quit; + if (config.wlcg_flush) wlcg_send_message(t); + } + +quit: + free(jobid_str); + free(state_str); + free(lbhost); + free(vo); + + return 0; +} + + +static int db_summary_getjobids(__attribute((unused))db_t *db, __attribute((unused))int maxn, __attribute((unused))char **jobids, int *n) { +/* + switch (db->was_summary) { + case 0: + *n = 3; + jobids[0] = strdup("https://skurut68-2.cesnet.cz:9000/FJldtiAR2EHC12C3Zz8WjQ"); + jobids[1] = strdup("https://skurut68-2.cesnet.cz:9000/AWTCWrUCr3uUh6cuRFaENQ"); + jobids[2] = strdup("https://skurut68-1.cesnet.cz:9000/o73CG2wrNdEQ909mG0Ac1g"); + break; + case 1: + *n = 1; + jobids[0] = strdup("https://skurut68-2.cesnet.cz:9000/-46Qa2ag4gLsA_Ki-3bSLw"); + + break; + default: *n = 0; break; + } + db->was_summary = (db->was_summary + 1) % 3; + return 0; +*/ + *n = 0; + return 0; +} + + +static int db_summary_setinfo(__attribute((unused))db_t *db, edg_wll_JobStat *stat) { + char *jobidstr; + + jobidstr = stat->jobId ? glite_jobid_unparse(stat->jobId) : NULL; + printf(RTM_TTY_GREEN "summary: jobid='%s'" RTM_TTY_RST "\n", jobidstr); + free(jobidstr); + return 0; +} + + +int rtm_summary(edg_wll_Context ctx, db_t *db) { + char *jobids[RTM_SUMMARY_JOBS]; + edg_wll_QueryRec lbquery[RTM_SUMMARY_JOBS + 1], *qr; + const edg_wll_QueryRec *lbqueryext[2]; + edg_wll_JobStat *jobstates = NULL; + int err = 0, ijob = 0, njobs = 0, iquery = 0, k, server_changed = 0; + glite_jobid_t jid = NULL; + char *server = NULL, *new_server = NULL; + unsigned int port = 0, new_port = 0; + + lprintf(NULL, INS, "Summary"); + + lbqueryext[0] = lbquery; + lbqueryext[1] = NULL; + memset(lbquery, 0, sizeof(lbquery)); + + do { + if (server) { + + if ((iquery >= RTM_SUMMARY_JOBS || server_changed || !njobs) && iquery) { + if ((err = edg_wll_QueryJobsExt(ctx, lbqueryext, 0, NULL, &jobstates)) != 0) { + lprintf_ctx(NULL, ERR, ctx, "query to '%s:%u' failed: %s", server, port, strerror(err)); + // report error jobids and skip the job (do nothing) + // TODO + } + for (k = 0; k < iquery; k++) glite_jobid_free((glite_jobid_t)lbquery[k].value.j); + + if (err == 0) { + for (k = 0; jobstates[k].state != EDG_WLL_JOB_UNDEF; k++) { + if ((err = db_summary_setinfo(db, jobstates + k)) != 0) lprintf(NULL, ERR, "Can't store %d. summary info for %s:%u", k, server, port); + edg_wll_FreeStatus(jobstates + k); + } + free(jobstates); + lprintf(NULL, DBG, "query to '%s:%u' succeed", server, port); + } + + iquery = 0; + memset(lbquery, 0, sizeof(lbquery)); + if (!njobs) break; // not needed, just spare summary select + + server_changed = 0; + } else { + lprintf(NULL, DBG, "summary pushed %d. %s\n", iquery, jobids[ijob]); + qr = lbquery + iquery; + iquery++; + qr->attr = EDG_WLL_QUERY_ATTR_JOBID; + qr->op = EDG_WLL_QUERY_OP_EQUAL; + glite_jobid_parse(jobids[ijob], (glite_jobid_t *)&qr->value.j); + free(jobids[ijob]); jobids[ijob] = NULL; + ijob++; + } + + } // server + + if (ijob >= njobs) { + ijob = 0; + memset(jobids, 0, sizeof(jobids)); + njobs = 0; + if ((err = db_summary_getjobids(db, RTM_SUMMARY_JOBS, jobids, &njobs)) != 0) { + lprintf(NULL, ERR, "Can't get jobs for the summary"); + return err; + } + lprintf(NULL, DBG, "summary for %d jobs", njobs); + if (!njobs) { + if (iquery) continue; // do the last query + else break; + } + } + + if ((err = glite_jobid_parse(jobids[ijob], &jid)) != 0) { + lprintf(NULL, ERR, "Can't parse jobid '%s': %s", jobids[ijob], strerror(err)); + // report error jobid and skip the job + // TODO + glite_jobid_free(jid); jid = NULL; + free(jobids[ijob]); jobids[ijob] = NULL; + ijob++; + continue; + } + free(new_server); + glite_jobid_getServerParts(jid, &new_server, &new_port); + glite_jobid_free(jid); jid = NULL; + + // first or different LB server + if (new_server && (!server || strcmp(server, new_server) != 0 || port != new_port)) { + if (server) server_changed = 1; + + free(server); + server = new_server; + port = new_port; + + new_server = NULL; + new_port = 0; + + edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER, server); + edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER_PORT, port); + lprintf(NULL, INF, "summary LB server '%s:%u'", server, port); + } + } while (njobs || iquery); + + free(server); + free(new_server); + + return err; +} + + +/* + * Updates error counter and retry times on the notification. + * + * On errors it lineary increases delay. Minimum delay is + * RTM_ERROR_REPEAT_RATE, maximum is half of the configured + * bootstrap time. + * + * \param t thread context + * \param notif updated notification + * \param[IN] index notification order (for debug printing) + * \param is_error[IN] error state (to reset or increment error counter) + * + */ +static int rtm_update_error_state(thread_t *t, notif_t *notif, int index, int is_error) { + int old_error, max_count; + + old_error = notif->error; + if (is_error) { + if (!notif->error++ || !notif->refresh) notif->refresh = time(NULL); + max_count = config.dive / RTM_ERROR_REPEAT_RATE / 2; + if (max_count <= 0) max_count = 1; + notif->refresh += (notif->error <= max_count ? notif->error : max_count) * RTM_ERROR_REPEAT_RATE; + lprintf(t, DBG, "planned to retry at %s", time2str(t, notif->refresh)); + } else { + notif->error = 0; + } + if (old_error != notif->error) { + lprintf(t, DBG, "error count of %d. server %s:%d changed from %d to %d", index, notif->server, notif->port, old_error, notif->error); + } + + return 0; +} + + +/** + * Updates notifications in persistent storage. Used to send WLCG messages too. + * + * \param t thread context + * \param[IN] new_notif updating notification, NULL = no change in shared memory + * \param[IN] store 0=light (just shared memory), 1=save (flush, really store) + * \retval 0 if OK + */ +int rtm_update_notif(thread_t *t, notif_t *new_notif, int store) { + notif_t *notif; + int retval = 1; + + pthread_mutex_lock(&db.lock); + + if (new_notif) { + if ((notif = db_search_notif_by_server(db.notifs, db.n, new_notif->server, new_notif->port, new_notif->type)) == NULL) { + if (db_add_notif(strdup(new_notif->id_str), new_notif->type, new_notif->valid, new_notif->refresh, new_notif->last_update, strdup(new_notif->server), new_notif->port, 1, 0) == NULL) { + lprintf(t, ERR, "can't realloc"); + goto quit; + } + } else { + notif_free(notif); + notif_copy(notif, new_notif); + } + } + + wlcg_send_message(t); + + if (store) { + if (db_save_notifs(t) != 0) goto quit; + } + retval = 0; + +quit: + pthread_mutex_unlock(&db.lock); + return retval; +} + + +int rtm_drop_notif(thread_t *t, char *notifid, int store) { + notif_t *notif; + int retval = 1; + + pthread_mutex_lock(&db.lock); + if ((notif = db_search_notif(db.notifs, db.n, notifid)) != NULL) { + notif_invalidate(notif); + if (store) + if (db_save_notifs(t) != 0) goto quit; + } + retval = 0; +quit: + pthread_mutex_unlock(&db.lock); + return retval; +} + + +int load_notifs_file() { + FILE *f; + char *results[5]; + notif_t *new_notif; + int err; + char *notifidstr; + time_t valid, refresh; + double last_update; + edg_wll_NotifId id; + int type, i, errcnt, port; + int retval = 1; + + if ((f = fopen(config.notif_file, "rt")) == NULL) { + lprintf(NULL, WRN, "WARNING: can't open notification file '%s'", config.notif_file); + return 0; + } + + results[0] = malloc(RTM_FILE_NOTIF_NUM * 512); + for (i = 1; i < RTM_FILE_NOTIF_NUM; i++) { + results[i] = results[0] + i * 512; + } + while ((err = fscanf(f, RTM_FILE_NOTIF_SCANF, results[0], results[1], results[2], results[3], results[4], results[5])) == RTM_FILE_NOTIF_NUM) { + notifidstr = results[0]; + if ((type = rtm_str2notiftype(results[1])) == -1) { + lprintf(NULL, ERR, "unknown notification type '%s' in '%s'", results[1], notifidstr); + continue; + } + + valid = rtm_str2time(results[2]); + refresh = rtm_str2time(results[3]); + last_update = rtm_str2timestamp(results[4]); + + errcnt = 0; + if (results[5] && strcasecmp(results[5], "-") != 0) { + errcnt = atoi(results[5]); + } + + if (errcnt) { + if (sscanf(notifidstr, "%511[^:]:%d", results[1], &port) != 2) { + lprintf(NULL, WRN, "can't parse server specification '%s'", notifidstr); + continue; + } + if ((new_notif = db_add_notif(NULL, type, valid, refresh, last_update, strdup(results[1]), port, 0, errcnt)) == NULL) { + lprintf(NULL, ERR, "can't alloc"); + goto quit; + } + } else { + if (edg_wll_NotifIdParse(notifidstr, &id) != 0) { + lprintf(NULL, WRN, "can't parse notification ID '%s'", notifidstr); + continue; + } + if ((new_notif = db_add_notif(strdup(notifidstr), type, valid, refresh, last_update, NULL, 0, 0, errcnt)) == NULL) { + lprintf(NULL, ERR, "can't alloc"); + goto quit; + } + edg_wll_NotifIdGetServerParts(id, &new_notif->server, &new_notif->port); + edg_wll_NotifIdFree(id); + } + } + if (err == EOF) retval = 0; + else lprintf(NULL, ERR, "can't parse notification file '%s'", config.notif_file); +quit: + fclose(f); + free(results[0]); + return retval; +} + + +#if defined(WITH_RTM_SQL_STORAGE) && defined(WITH_LBU_DB) +int load_notifs_sql() { + notif_t *new_notif; + int err; + char *notifidstr; + time_t valid, refresh; + double last_update; + edg_wll_NotifId id; + int type, i, errcnt; + int retval = 1; + glite_lbu_Statement stmt = NULL; + char *results[8]; + + if (glite_lbu_ExecSQL(db.dbctx, "SELECT notifid, notiftype, valid, refresh, last_update, errors, lb, port FROM notifs", &stmt) == -1) { + lprintf_dbctx(NULL, ERR, "fetching notification failed"); + goto quit; + } + while ((err = glite_lbu_FetchRow(stmt, 8, NULL, results)) > 0) { + if (results[0] && results[0][0]) notifidstr = strdup(results[0]); + else notifidstr = NULL; + free(results[0]); + results[0] = NULL; + + if ((type = rtm_str2notiftype(results[1])) == -1) { + lprintf(NULL, ERR, "unknown notification type '%s' in '%s'", results[1], notifidstr); + for (i = 0; i < 8; i++) free(results[i]); + free(notifidstr); + continue; + } + free(results[1]); + + valid = 0; + if (results[2] && results[2][0]) { + valid = glite_lbu_DBToTime(db.dbctx, results[2]); + } + free(results[2]); + + refresh = 0; + if (results[3] && results[3][0]) { + refresh = glite_lbu_DBToTime(db.dbctx, results[3]); + } + free(results[3]); + + last_update = 0; + if (results[4] && results[4][0]) { + last_update = glite_lbu_DBToTimestamp(db.dbctx, results[4]); + } + free(results[4]); + + errcnt = 0; + if (results[5] && results[5][0]) errcnt = atoi(results[5]); + free(results[5]); + + if ((new_notif = db_add_notif(notifidstr, type, valid, refresh, last_update, (results[6] && !notifidstr) ? strdup(results[6]) : NULL, atoi(results[7]), 0, errcnt)) == NULL) { + free(notifidstr); + free(results[6]); + free(results[7]); + lprintf(NULL, ERR, "can't alloc"); + goto quit; + } + free(results[6]); + free(results[7]); + if (notifidstr) { + if (edg_wll_NotifIdParse(notifidstr, &id) != 0) { + lprintf(NULL, WRN, "can't parse notification IDs '%s'", notifidstr); + notif_free(new_notif); + db.n--; + continue; + } + edg_wll_NotifIdGetServerParts(id, &new_notif->server, &new_notif->port); + edg_wll_NotifIdFree(id); + } + } + if (err == 0) retval = 0; + else lprintf_dbctx(NULL, ERR, "fetching failed"); +quit: + if (stmt) glite_lbu_FreeStmt(&stmt); + return retval; +} +#endif + + +int load_notifs() { + int i, ret; + + pthread_mutex_lock(&db.lock); + +#if defined(WITH_RTM_SQL_STORAGE) && defined(WITH_LBU_DB) + if (!db.dbctx) ret = load_notifs_file(); + else ret = load_notifs_sql(); +#else + ret = load_notifs_file(); +#endif + // try to reconnect on bad notifications immediately + for (i = 0; i < db.n; i++) + if (db.notifs[i].error) db.notifs[i].refresh = 0; + + pthread_mutex_unlock(&db.lock); + + return ret; +} + + +void db_free_notifs() { + int i; + + for (i = 0; i < db.n; i++) notif_free(db.notifs + i); + free(db.notifs); + db.notifs = NULL; + db.n = db.maxn = 0; +} + + +void *notify_thread(void *thread_data) { + struct sockaddr_in addr; + int i, j, err; + time_t now, bootstrap; + edg_wll_NotifId notifid; + struct timeval to; + edg_wll_JobStat jobstat, *jobstates; + notif_t *notif, *notif_jdl; + edg_wll_QueryRec *conditions[3] = { NULL, NULL, NULL }, condition[2], condition2[2]; + int sock = -1, updated = 0, error = 0, received = 0; + thread_t *t = (thread_t *)thread_data; + edg_wll_Context ctx = NULL; + int flags = 0; + + const int one = 1; + + lprintf(t, DBG, "thread started"); + + if (!t->nservers) goto exit; + + // LB + if (edg_wll_InitContext(&ctx) != 0) { + lprintf(t, ERR, "can't init LB context: %s", strerror(errno)); + goto exit; + } + if (config.cert) edg_wll_SetParam(ctx, EDG_WLL_PARAM_X509_CERT, config.cert); + if (config.key) edg_wll_SetParam(ctx, EDG_WLL_PARAM_X509_KEY, config.key); + + // socket + if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + lprintf(t, ERR, "can't create socket: %s", strerror(errno)); + goto exit; + } + lprintf(t, DBG, "socket created: %d", sock); + + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + + memset(&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + if (listen_port) addr.sin_port = htons(listen_port + t->id); + addr.sin_addr.s_addr = INADDR_ANY; + if (bind(sock, (const struct sockaddr*)&addr, sizeof addr) != 0) { + lprintf(t, ERR, "can't bind socket: %s, port = %d", strerror(errno), listen_port ? listen_port + t->id : -1); + goto exit; + } + if (listen(sock, 10) != 0) { + lprintf(t, ERR, "can't listen on socket: %s", strerror(errno)); + goto exit; + } + +#ifdef WITH_LBU_DB + if (db_init(t, &t->dbctx) == 0) + if ((t->dbcaps & GLITE_LBU_DB_CAP_PREPARED) != 0) { + if (glite_lbu_PrepareStmt(t->dbctx, "INSERT INTO " DBAMP RTM_DB_TABLE_JOBS DBAMP " " + "(ce, queue, rb, ui, state, state_entered, rtm_timestamp, jobid, lb, active, state_changed, registered, vo)" + " VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)", + &t->insertcmd) != 0 || glite_lbu_PrepareStmt(t->dbctx, "UPDATE " DBAMP RTM_DB_TABLE_JOBS DBAMP " " + "SET ce=$1, queue=$2, rb=$3, ui=$4, state=$5, state_entered=$6, rtm_timestamp=$7, active=$8, state_changed=$9, registered=$10 WHERE jobid=$11 AND lb=$12", + &t->updatecmd) != 0 || glite_lbu_PrepareStmt(t->dbctx, "UPDATE " DBAMP RTM_DB_TABLE_JOBS DBAMP " " + "SET ce=$1, queue=$2, rb=$3, ui=$4, state=$5, state_entered=$6, rtm_timestamp=$7, active=$8, state_changed=$9, registered=$10, vo=$11 WHERE jobid=$12 AND lb=$13", + &t->updatecmd_vo) != 0 || glite_lbu_PrepareStmt(t->dbctx, "UPDATE " DBAMP RTM_DB_TABLE_LBS DBAMP " " + "SET monitored=$1 WHERE ip=$2", + &t->updatecmd_mon) != 0 || glite_lbu_PrepareStmt(t->dbctx, "DELETE FROM " DBAMP RTM_DB_TABLE_JOBS DBAMP " WHERE jobid=$1 AND lb=$2", + &t->deletecmd) != 0) { + lprintf_dbctx(t, ERR, "can't create prepare commands"); + lprintf(t, DBG, "insertcmd=%p, updatecmd=%p, updatecmd_vo=%p, updatecmd_mon=%p, deletecmd=%p", t->insertcmd, t->updatecmd, t->updatecmd_vo, t->updatecmd_mon, t->deletecmd); + quit = RTM_QUIT_PRESERVE; + } + } +#endif + + // + // notifications loop: + // - refresh/create with bootstrap + // - receive & store changes + // + while (!quit) { + now = time(NULL); + t->next_refresh = now + RTM_NOTIF_LOOP_MAX_TIME; + for (i = 0; i < t->nservers; i++) { + notif = t->notifs + i; + if (!notif->active) { + lprintf(t, INS, "inactive %d. notification '%s' (%s)", i, notif->id_str, rtm_notiftype2str(notif->type)); + continue; + } + // skip invalid LBs if not planned yet + if (notif->error) { + if (notif->refresh > now) { + lprintf(t, INS, "not planned to retry previously failed %d. notification '%s' (%s), plan %s", i, notif->id_str, rtm_notiftype2str(notif->type), time2str(t, notif->refresh)); + if (t->next_refresh > notif->refresh) t->next_refresh = notif->refresh; + continue; + } + lprintf(t, DBG, "retry previously failed %d. notification '%s' (%s)", i, notif->id_str, rtm_notiftype2str(notif->type)); + } + edg_wll_SetParam(ctx, EDG_WLL_PARAM_NOTIF_SERVER, notif->server); + edg_wll_SetParam(ctx, EDG_WLL_PARAM_NOTIF_SERVER_PORT, notif->port); + now = time(NULL); + if (!notif->valid || notif->valid - RTM_NOTIF_TTL_TO_DEAD <= now || !notif->id_str) { + // new notification + lprintf(t, DBG, "host %s:%d, valid %s, notifstr '%s', notifid %p", notif->server, notif->port, time2str(t, notif->valid), notif->id_str, notif->id); + + // crazy inter-notif interactions + switch (notif->type) { + case RTM_NOTIF_TYPE_STATUS: + // STATUS must wait for existing JDL notification + notif_jdl = db_search_notif_by_server(t->notifs, t->nservers, notif->server, notif->port, RTM_NOTIF_TYPE_JDL); + if (!notif_jdl || !notif_jdl->valid || notif_jdl->valid - RTM_NOTIF_TTL_TO_DEAD <= now || !notif_jdl->id_str) { + lprintf(t, DBG, "not created %d. notification for %s:%d (%s), waiting for %d. (JDL)", i, notif->server, notif->port, rtm_notiftype2str(notif->type), i + RTM_NOTIF_TYPE_JDL - RTM_NOTIF_TYPE_STATUS); + // next retry of STATUS stright before the JDL + if (notif_jdl) { + notif->refresh = notif_jdl->refresh; + if (t->next_refresh > notif->refresh) t->next_refresh = notif->refresh; + } + continue; + } + break; + default: + break; + } + bootstrap = notif->valid > RTM_NOTIF_TTL_TO_DEAD ? notif->valid - RTM_NOTIF_TTL_TO_DEAD : 0; + if (config.dive > 0 && now - bootstrap > config.dive) { + bootstrap = now - config.dive; + lprintf(t, INS, "dive from %s:%d cut to %s (max. dive %d)", notif->server, notif->port, time2str(t, bootstrap), config.dive); + } + // explicitly drop old (failed) notification, if any + if (notif->id_str) { + if (notif->id) { + if (edg_wll_NotifDrop(ctx, notif->id)) lprintf_ctx(t, WRN, ctx, "dropping %d. notification '%s' (%s) failed", i, notif->id_str, rtm_notiftype2str(notif->type)); + } + // remove from the persistent storage now, + // invalidate && update + rtm_drop_notif(t, notif->id_str, 1); + // free the notification in the current thread + notif_invalidate(notif); + now = time(NULL); + } + // create the new notification + notif->valid = now + config.ttl; + + memset(conditions, 0, sizeof(conditions)); + memset(condition, 0, sizeof(condition)); + memset(condition2, 0, sizeof(condition2)); + flags = 0; + switch(notif->type) { +#ifndef WITH_OLD_LB + case RTM_NOTIF_TYPE_STATUS: + conditions[0] = condition; + condition[0].attr = EDG_WLL_QUERY_ATTR_STATUS; + condition[0].op = EDG_WLL_QUERY_OP_CHANGED; + break; + case RTM_NOTIF_TYPE_JDL: + conditions[0] = condition; + conditions[1] = condition2; + condition[0].attr = EDG_WLL_QUERY_ATTR_STATUS; + condition[0].op = EDG_WLL_QUERY_OP_EQUAL; + condition[0].value.i = EDG_WLL_JOB_WAITING; + condition2[0].attr = EDG_WLL_QUERY_ATTR_JDL_ATTR; + condition2[0].op = EDG_WLL_QUERY_OP_CHANGED; + flags = EDG_WLL_STAT_CLASSADS; + break; +#endif + case RTM_NOTIF_TYPE_OLD: + flags = EDG_WLL_STAT_CLASSADS; + break; + case RTM_NOTIF_TYPE_DONE: + conditions[0] = condition; + condition[0].attr = EDG_WLL_QUERY_ATTR_STATUS; + condition[0].op = EDG_WLL_QUERY_OP_EQUAL; + condition[0].value.i = EDG_WLL_JOB_DONE; + flags = EDG_WLL_STAT_CHILDREN; + break; + default: + assert(notif->type != notif->type); // unknown type + break; + } + if (edg_wll_NotifNew(ctx, (edg_wll_QueryRec const * const *) conditions, flags, sock, config.local_address, ¬if->id, ¬if->valid)) { + memset(condition,0,sizeof condition); + lprintf_ctx(t, ERR, ctx, "can't create notification on %s:%d", notif->server, notif->port); + notif->valid = 0; + notif->id = NULL; + rtm_update_error_state(t, notif, i, 1); + error = 1; + goto cont; + } + notif->id_str = edg_wll_NotifIdUnparse(notif->id); + lprintf(t, INF, "created %d. notification '%s' (%s), valid: %s", i, notif->id_str, rtm_notiftype2str(notif->type), time2str(t, notif->valid)); + + // bootstrap + memset(condition, 0, sizeof(condition)); + flags = 0; + switch (notif->type) { + case RTM_NOTIF_TYPE_STATUS: + condition[0].attr = EDG_WLL_QUERY_ATTR_LASTUPDATETIME; + condition[0].op = EDG_WLL_QUERY_OP_WITHIN; + condition[0].value.t.tv_sec = bootstrap; + condition[0].value2.t.tv_sec = now; + flags = EDG_WLL_STAT_CLASSADS; + break; + case RTM_NOTIF_TYPE_OLD: + break; + case RTM_NOTIF_TYPE_JDL: + break; + case RTM_NOTIF_TYPE_DONE: + break; + default: + assert(notif->type != notif->type); // unknown type + break; + } + + if (condition[0].attr) { + + lprintf(t, INF, "bootstrap %s:%d (%d), time %s..%d(now)", notif->server, notif->port, i, time2str(t, bootstrap), now); + edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER, notif->server); + edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER_PORT, notif->port); + if ((err = edg_wll_QueryJobs(ctx, condition, flags, NULL, &jobstates)) != 0 && err != ENOENT) { + lprintf_ctx(t, ERR, ctx, "can't bootstrap jobs on %s:%d, time %s..%d(now)", notif->server, notif->port, time2str(t, bootstrap), now); + // + // destroy the notification after failed bootstrap + // + // This error means there is something nasty on the remote LB server. + // It could lost some messages between recreating notification, + // so destroy this notification now. + // + if (edg_wll_NotifDrop(ctx, notif->id)) { + lprintf_ctx(t, WRN, ctx, "dropping %d. notification '%s' (%s) after failed bootstrap failed", i, notif->id_str, rtm_notiftype2str(notif->type)); + } else { + lprintf(t, INF, "dropped %d. notification '%s' (%s) after failed bootstrap", i, notif->id_str, rtm_notiftype2str(notif->type)); + } + // free the notification instance in the current thread + // (not propagated to the persistent storage yet) + edg_wll_NotifIdFree(notif->id); + notif->id = NULL; + free(notif->id_str); + notif->id_str = NULL; + notif->valid = 0; + rtm_update_error_state(t, notif, i, 1); + error = 1; + if (t->next_refresh > notif->refresh) t->next_refresh = notif->refresh; + goto cont; + } else { + for (j = 0; jobstates[j].state != EDG_WLL_JOB_UNDEF; j++) { + notif->last_update = jobstates[j].lastUpdateTime.tv_sec + jobstates[j].lastUpdateTime.tv_usec / 1000000.0; + db_store_change(t, notif, i, jobstates + j); + edg_wll_FreeStatus(jobstates + j); + } + free(jobstates); + lprintf(t, INF, "bootstrap %s:%d (%d), found %d jobs", notif->server, notif->port, i, j); + rtm_update_error_state(t, notif, i, 0); + updated = 1; + } + + } else { + rtm_update_error_state(t, notif, i, 0); + updated = 1; + } + } else if (!notif->id) { + // rebind existing still valid notification + if (edg_wll_NotifIdParse(notif->id_str, ¬if->id)) { + lprintf_ctx(t, WRN, ctx, "can't parse %d. notification '%s' (%s)", i, notif->id_str, rtm_notiftype2str(notif->type)); + notif->valid = 0; + notif->id = NULL; + i--; + continue; + } + notif->valid = now + config.ttl; + if (edg_wll_NotifBind(ctx, notif->id, sock, config.local_address, ¬if->valid)) { + lprintf_ctx(t, WRN, ctx, "can't rebind %d. notification '%s' (%s)", i, notif->id_str, rtm_notiftype2str(notif->type)); + notif->valid = 0; + edg_wll_NotifIdFree(notif->id); + notif->id = NULL; + i--; + continue; + } + lprintf(t, INF, "bound %d. notification '%s' (%s), valid: %s", i, notif->id_str, rtm_notiftype2str(notif->type), time2str(t, notif->valid)); + rtm_update_error_state(t, notif, i, 0); + // no bootstrap here, reliable delivery will send changes + updated = 1; + } else if (!notif->refresh || notif->refresh <= now) { + // refresh notification + time_t valid; + + valid = now + config.ttl; + if (edg_wll_NotifRefresh(ctx, notif->id, &valid)) { + lprintf_ctx(t, WRN, ctx, "can't refresh %d. notification '%s' (%s), will try up to %s...", i, notif->id_str, rtm_notiftype2str(notif->type), time2str(t, notif->valid - RTM_NOTIF_TTL_TO_DEAD)); + // refresh failed, just move the refresh time... + updated = 1; + } else { + notif->valid = valid; + lprintf(t, INF, "refreshed %d. notification '%s' (%s), valid: %s", i, notif->id_str, rtm_notiftype2str(notif->type), time2str(t, notif->valid)); + rtm_update_error_state(t, notif, i, 0); + updated = 1; + } + } else { + lprintf(t, INS, "no change in %d. notification '%s' (%s)", i, notif->id_str, rtm_notiftype2str(notif->type)); + } + +cont: + if (updated || error) { + if (!error) { + assert(notif->valid); + notif->refresh = notif->valid ? (now + ((notif->valid - now) >> 1)) : 0; + + } + // create or refresh OK, bootstrap if needed OK, store the new notification + updated = 0; + error = 0; + + // quicker refresh (or recreate) if needed + now = time(NULL); + if (notif->valid && now >= notif->refresh) { + lprintf(t, WRN, "operation not in time, refreshing/recreating the notification '%s' (%s) now", notif->id_str, rtm_notiftype2str(notif->type)); + i--; + continue; + } + rtm_update_notif(t, notif, 1); + } + + // compute time of the next event from the new refresh on notification + if (t->next_refresh > notif->refresh) t->next_refresh = notif->refresh; + } + + // receive + // + // cycle here locally around NotifReceive, we know about next + // refresh time + // + lprintf(t, DBG, "waiting for the notifications up to %s...", t->next_refresh ? time2str(t, t->next_refresh) : "0 (no wait)"); + while (t->next_refresh > now && !quit) { + to.tv_sec = t->next_refresh - now; + if (to.tv_sec > RTM_NOTIF_READ_TIMEOUT) to.tv_sec = RTM_NOTIF_READ_TIMEOUT; + to.tv_usec = 0; + memset(&jobstat, 0, sizeof(jobstat)); + notifid = NULL; + err = edg_wll_NotifReceive(ctx, sock, &to, &jobstat, ¬ifid); + lprintf(t, INS, "received, err=%d%s", err, err == ETIMEDOUT ? " (timeout)":""); + if (err != 0) { + if (err != ETIMEDOUT) { + lprintf_ctx(t, ERR, ctx, "can't receive notifications"); + // don't cycle too quick... + sleep(1); + } + // lazily refresh persistent storage here, only after timeouts + if (received) { + lprintf(t, DBG, "storing notification times"); + rtm_update_notif(t, NULL, 1); + received = 0; + } + } else { + char *jobidstr, *notifidstr; + double last_update; + + if (notifid) { + jobidstr = jobstat.jobId ? glite_jobid_unparse(jobstat.jobId) : NULL; + notifidstr = notifid ? edg_wll_NotifIdUnparse(notifid) : NULL; + for (i = 0; i < t->nservers && (!t->notifs[i].id_str || strcmp(notifidstr, t->notifs[i].id_str) != 0); i++); + if (i == t->nservers) { + lprintf(t, ERR, "received notify '%s' not found", notifidstr); + } else { + received = 1; + notif = t->notifs + i; + // + // last changed time from the arrived notification + // + last_update = jobstat.lastUpdateTime.tv_sec + jobstat.lastUpdateTime.tv_usec / 1000000.0; + if (last_update > notif->last_update) notif->last_update = last_update; + db_store_change(t, notif, i, &jobstat); + rtm_update_notif(t, notif, 0); + } + free(jobidstr); + free(notifidstr); + } + } + if (jobstat.state != EDG_WLL_JOB_UNDEF) edg_wll_FreeStatus(&jobstat); + if (notifid) edg_wll_NotifIdFree(notifid); + + now = time(NULL); + } // receive + } // main loop + +exit: + if (sock != -1) close(sock); +// for (i = 0; conditions[i]; i++) free(conditions[i]); + if (t->nservers && quit != RTM_QUIT_PRESERVE && quit != RTM_QUIT_RELOAD) { + for (i = 0; i < t->nservers; i++) { + if (t->notifs[i].id) { + char *notifidstr; + + notifidstr = edg_wll_NotifIdUnparse(t->notifs[i].id); + edg_wll_SetParam(ctx, EDG_WLL_PARAM_NOTIF_SERVER, t->notifs[i].server); + edg_wll_SetParam(ctx, EDG_WLL_PARAM_NOTIF_SERVER_PORT, t->notifs[i].port); + if (edg_wll_NotifDrop(ctx, t->notifs[i].id)) { + lprintf_ctx(t, WRN, ctx, "can't drop %s (%s)", notifidstr, rtm_notiftype2str(t->notifs[i].type)); + } else { + lprintf(t, INF, "notification %s (%s) dropped", notifidstr, rtm_notiftype2str(t->notifs[i].type)); + } + rtm_drop_notif(t, t->notifs[i].id_str, 0); + free(notifidstr); + } + } + rtm_update_notif(t, NULL, 1); + } +#ifdef WITH_LBU_DB + if (t->insertcmd) glite_lbu_FreeStmt(&t->insertcmd); + if (t->updatecmd) glite_lbu_FreeStmt(&t->updatecmd); + if (t->updatecmd_vo) glite_lbu_FreeStmt(&t->updatecmd_vo); + if (t->updatecmd_mon) glite_lbu_FreeStmt(&t->updatecmd_mon); + if (t->deletecmd) glite_lbu_FreeStmt(&t->deletecmd); + db_free(t, t->dbctx); +#endif + if (ctx) edg_wll_FreeContext(ctx); + lprintf(t, DBG, "thread ended"); + pthread_exit(NULL); + return NULL; +} + + +int reconcile_threads() { + int iserver, ithread, inotif, gran, mod, nnotifs; + int i, j, oldn, type, typestart, typeend; + notif_t *a, *b; + edg_wll_Context ctx = NULL; + edg_wll_NotifId notifid; + thread_t *t; + + if (!config.cleanup) { + if (config.silly) { + typestart = RTM_NOTIF_TYPE_OLD; + typeend = RTM_NOTIF_TYPE_OLD; + nnotifs = 1; + } else { + typestart = RTM_NOTIF_TYPE_STATUS; + typeend = RTM_NOTIF_TYPE_JDL; + nnotifs = 2; + } + + oldn = db.n; + + // distribute LB servers between threads + // (always use existing loaded notification when found) + threads = (thread_t *)calloc(config.nthreads, sizeof(thread_t)); + gran = config.nservers / config.nthreads, mod = config.nservers % config.nthreads; + t = NULL; + ithread = 0; + inotif = 0; + for (iserver = 0; iserver < config.nservers; iserver++) { + // new thread + if (!t || inotif + nnotifs > t->nservers) { + assert(ithread < config.nthreads); // proper number of threads + assert(!t || inotif == t->nservers); // start or exactly distributed + t = threads + ithread; + t->nservers = nnotifs * ((ithread < mod) ? gran + 1 : gran); + t->notifs = (notif_t *)calloc(t->nservers, sizeof(notif_t)); + lprintf(NULL, DBG, "%d. thread: %d notifications", ithread, t->nservers); + ithread++; + inotif = 0; + } + + // next configured server + a = config.notifs + iserver; + for (type = typestart; type <= typeend; type++) { + // find or create all notification types + b = db_search_notif_by_server(db.notifs, oldn, a->server, a->port, type); + if (!b) b = db_add_notif(NULL, type, 0, 0, 0, strdup(a->server), a->port, 1, 0); + else { + if (b->id_str) { + lprintf(NULL, INF, "found previous notification '%s' (%s)", b->id_str, rtm_notiftype2str(b->type)); + } else { + lprintf(NULL, INF, "found previous server %s:%d (%s), %d errors", b->server, b->port, rtm_notiftype2str(b->type), b->error); + } + b->active = 1; + } + // and add each to the thread + notif_copy(t->notifs + inotif, b); + lprintf(NULL, INS, "thread[%d][%d] <- %s:%d (%s), id %s", ithread-1, inotif, b->server, b->port, rtm_notiftype2str(b->type), b->id_str); + inotif++; + } + } + j = 0; + for (i = 0; i < db.n; i++) + if (db.notifs[i].active) j++; + assert(j % nnotifs == 0); // each server all notifs + } + + if (edg_wll_InitContext(&ctx) != 0) { + lprintf(NULL, ERR, "can't init LB context: %s", strerror(errno)); + return 1; + } + if (config.cert) edg_wll_SetParam(ctx, EDG_WLL_PARAM_X509_CERT, config.cert); + if (config.key) edg_wll_SetParam(ctx, EDG_WLL_PARAM_X509_KEY, config.key); + for (j = 0; j < db.n; j++) { + if (!db.notifs[j].active) { + if (db.notifs[j].id_str) { + lprintf(NULL, INF, "dropping previous notification '%s' (%s)", db.notifs[j].id_str, rtm_notiftype2str(db.notifs[j].type)); + if (edg_wll_NotifIdParse(db.notifs[j].id_str, ¬ifid)) { + lprintf(NULL, WRN, "can't parse notification ID '%s'", db.notifs[j].id_str); + continue; + } + edg_wll_SetParam(ctx, EDG_WLL_PARAM_NOTIF_SERVER, db.notifs[j].server); + edg_wll_SetParam(ctx, EDG_WLL_PARAM_NOTIF_SERVER_PORT, db.notifs[j].port); + if (edg_wll_NotifDrop(ctx, notifid) != 0) { + lprintf_ctx(NULL, WRN, ctx, "can't drop %s (%s)", db.notifs[j].id_str, rtm_notiftype2str(db.notifs[j].type)); + } + edg_wll_NotifIdFree(notifid); + notif_invalidate(db.notifs + j); + } + } + } + edg_wll_FreeContext(ctx); + + return db_save_notifs(NULL); +} + + +void usage(const char *prog) { + fprintf(stderr, "Usage: %s [options]\n" + " -h, --help display this help\n" + " -v, --version display version\n" + " -d, --debug LEVEL debug level (0=error,1=warn,2=info,3=debug,4=insane,\n" + " +8=not fork)\n" + " -D, --daemonize daemonize\n" + " -i, --pidfile the file with process ID\n" + " -s, --threads N number of slave threads\n" + " -t, --ttl TIME time to live (validity) of the notifications\n" + " in seconds (%d)\n" + " -H, --history historic dive in seconds (<=0 is unlimited)\n" + " -c, --config config file name (list of LB servers), precedence before " RTM_DB_TABLE_LBS " table\n" +#ifdef WITH_LBU_DB + " -m, --pg db connection string (user/pwd@server:dbname) to " RTM_DB_TABLE_LBS " table\n" +#endif + " -n, --notifs file for persistent information about active\n" + " notifications\n" + " -p, --port listen only on this port (default: use any)\n" + " -C, --cert X509 certificate file\n" + " -K, --key X509 key file\n" + " -o, --old \"silly\" mode for old L&B 1.9 servers\n" + " -l, --cleanup clean up the notifications and exit\n" + " -u, --no-purge disable purging from RTM database\n" + " -w, --wlcg enable messaging for dashboard\n" + " --wlcg-binary full path to msg-publish binary\n" + " --wlcg-topic topic for msg-publish\n" + " --wlcg-config config file for msg-publish\n" + " --wlcg-flush send message on each notification\n" + , prog, RTM_NOTIF_TTL); + fprintf(stderr, "\n"); + fprintf(stderr, "List of L&B servers: first it's read the config file if specified (-c option). When config file is not used and connection to database is specified, it's tried DB table " RTM_DB_TABLE_LBS ".\n"); + fprintf(stderr, "\n"); +} + + +int config_preload(int argn, char *argv[]) { + int opt, intval, index; + char *err, *s; + + while ((opt = getopt_long(argn, argv, opts_line, opts, &index)) != EOF) { + switch (opt) { + case 'h': + case '?': + usage(argv[0]); + return 1; + case 'v': + fprintf(stderr, "%s: %s\n", argv[0], rcsid); + return 1; + case 'd': + intval = strtol(optarg, &err, 10); + if (err && err[0]) { + lprintf(NULL, ERR, "debug level number required"); + return 2; + } + config.debug = (intval & DEBUG_LEVEL_MASK); + config.guard = !(intval & DEBUG_GUARD_MASK); + break; + case 'D': + config.daemonize = 1; + break; + case 'i': + config.pidfile = strdup(optarg); + break; + case 's': + intval = strtol(optarg, &err, 10); + if (err && err[0]) { + lprintf(NULL, ERR, "number of threads required"); + return 2; + } + config.nthreads = intval; + break; + case 't': + intval = strtol(optarg, &err, 10); + if (err && err[0]) { + lprintf(NULL, ERR, "requested validity in seconds required"); + return 2; + } + config.ttl = intval; + break; + case 'H': + intval = strtol(optarg, &err, 10); + if (err && err[0]) { + lprintf(NULL, ERR, "historic dive in seconds required"); + return 2; + } + config.dive = intval; + break; + case 'c': + free(config.config_file); + config.config_file = strdup(optarg); + break; + case 'n': + free(config.notif_file); + config.notif_file = strdup(optarg); + break; + case 'p': + listen_port = atoi(optarg); + break; + case 'm': + free(config.dbcs); + config.dbcs = strdup(optarg); + break; + case 'C': + free(config.cert); + config.cert = strdup(optarg); + break; + case 'K': + free(config.key); + config.key = strdup(optarg); + break; + case 'l': + config.cleanup = 1; + break; + case 'w': + config.wlcg = 1; + break; + case 'o': + config.silly = 1; + break; + case 'u': + config.no_purge = 1; + break; + case 0: + switch(index) { + case 0: + config.wlcg_binary = strdup(optarg); + break; + case 1: + config.wlcg_config = strdup(optarg); + break; + case 2: + config.wlcg_topic = strdup(optarg); + break; + case 3: + config.wlcg_flush = 1; + break; + default: + lprintf(NULL, ERR, "crazy option, index %d", index); + break; + } + break; + } + } + if (!config.notif_file) config.notif_file = strdup(RTM_FILE_NOTIFS); + if (config.wlcg) { + if (!config.wlcg_binary) config.wlcg_binary = strdup(WLCG_BINARY); + if (!config.wlcg_config) config.wlcg_config = strdup(WLCG_CONFIG); + if (!config.wlcg_topic) config.wlcg_topic = strdup(WLCG_TOPIC); + } +#ifdef WITH_OLD_LB + if (!config.silly) { + lprintf(NULL, WRN, "compiled with older LB library, switching on silly mode"); + config.silly = 1; + } +#endif + + if ((s = getenv("GLITE_LB_HARVESTER_NO_REMOVE")) != NULL) { + if (s[0] != '0' && strcasecmp(s, "false") != 0) config.wlcg_no_remove = 1; + } + + if (INF <= config.debug) { + lprintf(NULL, INF, "threads: %d", config.nthreads); + lprintf(NULL, INF, "notifs ttl: %d", config.ttl); + lprintf(NULL, INF, "historic dive: %d", config.dive); + if (config.dbcs) { + lprintf(NULL, INF, "database storage: '%s'", config.dbcs); + } else { + lprintf(NULL, INF, "file storage: '%s'", config.notif_file); + } + lprintf(NULL, INF, "WLCG messaging: %s%s", config.wlcg ? "enabled" : "disabled", config.wlcg_no_remove ? " (not removing tmp files)" : ""); + lprintf(NULL, INF, "debug level: %d", config.debug); + lprintf(NULL, INF, "daemonize: %s", config.daemonize ? "enabled" : "disabled"); + lprintf(NULL, INF, "fork guard: %s", config.guard ? "enabled" : "disabled"); + lprintf(NULL, INF, "silly compatibility mode: %s", config.silly ? "enabled" : "disabled"); + lprintf(NULL, INF, "purge: %s", !config.no_purge ? "enabled" : "disabled"); + } + + return 0; +} + + +int config_load() { + char line[LINE_MAX], *port, *s; + FILE *f; + void *tmp; + int i, n; +#ifdef WITH_LBU_DB + int major, minor, sub, version; + char *results[2]; + char *result = NULL; + glite_lbu_Statement stmt = NULL; + int err = 0; +#endif + + if (config.config_file) { + if ((f = fopen(config.config_file, "rt")) == NULL) { + lprintf(NULL, ERR, "can't open config file '%s': %s", config.config_file, strerror(errno)); + return 1; + } + + n = 10; + while (fgets(line, sizeof(line), f) != NULL) { + if ((s = strpbrk(line, "\n\r")) != NULL) s[0] = '\0'; + if (line[0] == '\0' || line[0] == '#') continue; + if (config.nservers >= n || !config.notifs) { + n = 2 * n; + if ((tmp = (notif_t *)realloc(config.notifs, n * sizeof(notif_t))) == NULL) { + lprintf(NULL, ERR, "insufficient memory"); + return 1; + } + config.notifs = tmp; + memset(config.notifs + config.nservers, 0, (n - config.nservers) * sizeof(notif_t)); + } + if ((port = strrchr(line, ':')) != NULL) { port[0] = '\0'; port++; } + config.notifs[config.nservers].server = strdup(line); + config.notifs[config.nservers++].port = (port && port[0]) ? atoi(port) : GLITE_JOBID_DEFAULT_PORT; + } + + fclose(f); + } else +#ifdef WITH_LBU_DB + if (db.dbctx) { + if ((err = glite_lbu_ExecSQL(db.dbctx, "SELECT COUNT(*) FROM " RTM_DB_TABLE_LBS, &stmt)) < 0 || + (err = glite_lbu_FetchRow(stmt, 1, NULL, &result)) < 0) { + goto err; + } + if (err == 0) { + lprintf(NULL, ERR, "can't count LB servers"); + goto err; + } + n = atoi(result); + free(result); + glite_lbu_FreeStmt(&stmt); + + config.notifs = calloc(n, sizeof(notif_t)); + config.nservers = 0; + if ((err = glite_lbu_ExecSQL(db.dbctx, "SELECT DISTINCT ip, serv_version FROM " RTM_DB_TABLE_LBS, &stmt)) < 0) { + goto err; + } + while (config.nservers < n && (err = glite_lbu_FetchRow(stmt, 2, NULL, results)) > 0) { + if (sscanf(results[1], "%d.%d.%d", &major, &minor, &sub) != 3) { + lprintf(NULL, ERR, "can't parse LB server version '%s'", results[1]); + free(results[1]); + break; + } + version = 10000 * major + 100 * minor + sub; + if (version >= 20000 || config.silly) { + config.notifs[config.nservers].server = strdup(results[0]); + config.notifs[config.nservers++].port = GLITE_JOBID_DEFAULT_PORT; + } else { + lprintf(NULL, INF, "skipped older LB server %s (version '%s')", results[0], results[1]); + } + free(results[0]); + free(results[1]); + } + if (err < 0) goto err; + glite_lbu_FreeStmt(&stmt); + } +#endif + + if (INF <= config.debug) { + lprintf(NULL, INF, "servers: %d", config.nservers); + for (i = 0; i < config.nservers; i++) lprintf(NULL, INF, " %s:%d", config.notifs[i].server, config.notifs[i].port); + } + + return 0; +#ifdef WITH_LBU_DB +err: + if (err) lprintf_dbctx(NULL, ERR, "can't get LB servers"); + if (stmt) glite_lbu_FreeStmt(&stmt); + if (result) free(result); +#endif + return 1; +} + + +void config_free() { + int i; + + for (i = 0; i < config.nservers; i++) free(config.notifs[i].server); + free(config.config_file); + free(config.notif_file); + free(config.pidfile); + free(config.dbcs); + free(config.notifs); + free(config.cert); + free(config.key); + free(config.wlcg_binary); + free(config.wlcg_config); + free(config.wlcg_topic); +} + + +// on keyboard cleanup notification, on termination signal break with +// notification preserved +void handle_signal(int num) { + lprintf(NULL, INF, "received signal %d", num); + switch (num) { + case SIGINT: + case SIGTERM: + default: + quit = RTM_QUIT_PRESERVE; + break; + } +} + + +int main(int argn, char *argv[]) { + struct sigaction sa; + sigset_t sset; + int i, j; + double t1, t2, last_summary = 0, start_time; + thread_t *t; + struct stat pstat; + pid_t watched; + int status; + edg_wll_Context ctx = NULL; + int retval = RTM_EXIT_ERROR; + int cert_mtime = 0; + + // load basic configurations + switch (config_preload(argn, argv)) { + case 0: + break; + case 1: + retval = RTM_EXIT_OK; + goto quit_guard0; + break; + default: + retval = RTM_EXIT_ERROR; + goto quit_guard0; + } + + // daemonize + if (config.pidfile) { + FILE *f; + char s[256]; + + if ((f = fopen(config.pidfile, "rt"))) { + if (fscanf(f, "%255[^\n\r]", s) == 1) { + if (kill(atoi(s),0)) { + lprintf(NULL, WRN, "stale pidfile, pid = %s, pidfile '%s'", s, config.pidfile); + fclose(f); + } + else { + lprintf(NULL, ERR, "another instance running, pid = %s, pidfile '%s'", s, config.pidfile); + fclose(f); + goto quit_guard0; + } + } else { + lprintf(NULL, ERR, "another instance possibly running, can't read pidfile '%s': %s", config.pidfile, strerror(errno)); + fclose(f); + goto quit_guard0; + } + } else if (errno != ENOENT) { + lprintf(NULL, ERR, "error opening pidfile '%s': %s", config.pidfile, strerror(errno)); + goto quit_guard0; + } + } + if (config.daemonize) { + if (daemon(0, 0) == -1) { + lprintf(NULL, ERR, "can't daemonize: %s", strerror(errno)); + goto quit_guard0; + } + } + + // disable signals to the guardian + sigemptyset(&sset); + sigaddset(&sset, SIGABRT); + sigaddset(&sset, SIGTERM); + sigaddset(&sset, SIGINT); + pthread_sigmask(SIG_BLOCK, &sset, NULL); + + if (!config.guard) { + // not guard + if (config.pidfile) { + FILE *f; + + if ((f = fopen(config.pidfile, "wt")) == NULL) { + lprintf(NULL, ERR, "can't create pidfile '%s': %s", config.pidfile, strerror(errno)); + goto quit_guard0; + } + fprintf(f, "%d", getpid()); + fclose(f); + } + } else + // guard + while ((watched = fork()) != 0) { + if (watched == -1) { + lprintf(NULL, ERR, "fork() failed: %s", strerror(errno)); + goto quit_guard; + } + if (config.pidfile) { + FILE *f; + + if ((f = fopen(config.pidfile, "wt")) == NULL) { + lprintf(NULL, ERR, "can't create pidfile '%s': %s", config.pidfile, strerror(errno)); + goto quit_guard0; + } + fprintf(f, "%d", watched); + fclose(f); + } + if (waitpid(watched, &status, 0) == -1) { + lprintf(NULL, ERR, "waitpid() failed: %s", strerror(errno)); + // orpaned child will restart later anyway, + // better to end the child process just now + kill(watched, SIGTERM); + goto quit_guard; + } + if (WIFSIGNALED(status)) { + switch (WTERMSIG(status)) { + case SIGSEGV: + case SIGILL: + case SIGABRT: +#ifdef SIGBUS + case SIGBUS: +#endif + lprintf(NULL, ERR, "caught signal %d from process %d, resurrecting...", WTERMSIG(status), watched); + // slow down the core generator ;-) + // disabled signals and ended child in pidfile, live with it + pthread_sigmask(SIG_UNBLOCK, &sset, NULL); + if (config.pidfile) { + if (remove(config.pidfile) == -1) lprintf(NULL, WRN, "can't remove pidfile '%s': %s", config.pidfile, strerror(errno)); + } + sleep(2); + pthread_sigmask(SIG_BLOCK, &sset, NULL); + break; + default: + lprintf(NULL, WRN, "ended with signal %d", WTERMSIG(status)); + goto quit_guard; + } + } else if (WIFEXITED(status)) { + retval = WEXITSTATUS(status); + switch(retval) { + case RTM_EXIT_OK: + lprintf(NULL, INF, "exit with status %d, OK", retval); + goto quit_guard; + case RTM_EXIT_RELOAD: + lprintf(NULL, INF, "exit with status %d, reloading", retval); + break; + default: + lprintf(NULL, WRN, "exit with status %d, error", retval); + goto quit_guard; + } + } else { + lprintf(NULL, ERR, "unknown child status"); + goto quit_guard; + } + } + + // child continues... + + // threads && Globus + if (edg_wll_gss_initialize()) { + lprintf(NULL, ERR, "can't initialize GSS"); + goto quit_guard; + } + +#ifndef WITH_OLD_LB + // connection pool manually (just for tuning memory leaks) + if (!edg_wll_initConnections()) { + lprintf(NULL, ERR, "can't initialize LB connections"); + goto quit_guard; + } +#endif + +#ifdef WITH_LBU_DB + // database + switch(db_init(NULL, &db.dbctx)) { + case 0: + break; + case -1: + // no db + break; + default: + // error + goto quit; + } +#endif + + // load configurations + if (config_load()) goto quit; +#ifdef WITH_OLD_LB + // other client certificate settings ignored by older globus, + // using environment (certificate the same for all threads) + { + char *s; + + if (config.cert) { + asprintf(&s, "X509_USER_CERT=%s", config.cert); + putenv(s); + } + if (config.key) { + asprintf(&s, "X509_USER_KEY=%s", config.key); + putenv(s); + } + } +#endif + + // load previous notifications + if (load_notifs()) goto quit; + // compare lb servers from configuration and notifications, + // or clean up and exit if specified + if (reconcile_threads()) goto quit; + if (config.cleanup) { + retval = RTM_EXIT_OK; + goto quit; + } + + // signal handler + sa.sa_handler = handle_signal; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESETHAND; + if (sigaction(SIGABRT, &sa, NULL) == -1 + || sigaction(SIGTERM, &sa, NULL) == -1 + || sigaction(SIGINT, &sa, NULL) == -1) { + lprintf(NULL, ERR, "can't handle signal: %s", strerror(errno)); + goto quit; + } + // enable signals in main + pthread_sigmask(SIG_UNBLOCK, &sset, NULL); + + // launch the threads + for (i = 0; i < config.nthreads; i++) { + t = threads + i; + t->id = i; + if (pthread_create(&threads[i].thread, NULL, notify_thread, t) != 0) { + lprintf(NULL, ERR, "[main] can't create %d. thread: %s\n", i, strerror(errno)); + goto quit; + } + } + + edg_wll_InitContext(&ctx); + if (config.cert) edg_wll_SetParam(ctx, EDG_WLL_PARAM_X509_CERT, config.cert); + if (config.key) edg_wll_SetParam(ctx, EDG_WLL_PARAM_X509_KEY, config.key); + last_summary = 0; + start_time = rtm_gettimeofday(); + while (!quit) { + t1 = rtm_gettimeofday(); + if (t1 - last_summary > RTM_SUMMARY_POLL_TIME) { + last_summary = t1; + rtm_summary(ctx, &db); + } + if (config.guard) { + if (t1 - start_time > RTM_SUICIDE_TIME) { + quit = RTM_QUIT_RELOAD; + lprintf(NULL, INF, "preventive suicide"); + break; + } + if (config.cert) { + if (stat(config.cert, &pstat) == 0) { + if (!cert_mtime) cert_mtime = pstat.st_mtime; + if (cert_mtime < pstat.st_mtime) { + lprintf(NULL, INF, "certificate '%s' changed, reloading", config.cert); + quit = RTM_QUIT_RELOAD; + break; + } + } else { + lprintf(NULL, ERR, "can't check certificate file '%s'", config.cert, strerror(errno)); + } + } + } + t2 = rtm_gettimeofday(); + if (t2 - t1 < RTM_IDLE_POLL_TIME) usleep((RTM_IDLE_POLL_TIME + t1 - t2) * 1000000); + } + retval = quit == RTM_QUIT_RELOAD ? RTM_EXIT_RELOAD : RTM_EXIT_OK; +quit: + // cleanup on error + if (!quit) quit = RTM_QUIT_CLEANUP; + if (threads) { + for (i = 0; i < config.nthreads; i++) { + t = threads + i; + if (t->thread) pthread_join(t->thread, NULL); + for (j = 0; j < t->nservers; j++) notif_free(t->notifs + j); + free(t->notifs); + } + free(threads); + } + + if (config.pidfile && !config.guard) { + if (remove(config.pidfile) == -1) lprintf(NULL, WRN, "can't remove pidfile '%s': %s", config.pidfile, strerror(errno)); + } + +#ifdef WITH_LBU_DB + db_free(NULL, db.dbctx); +#endif + edg_wll_FreeContext(ctx); + db_free_notifs(); + config_free(); +#ifndef WITH_OLD_LB + edg_wll_poolFree(); +#endif + + return retval; + +quit_guard: + if (config.pidfile) { + if (remove(config.pidfile) == -1) lprintf(NULL, WRN, "can't remove pidfile '%s': %s", config.pidfile, strerror(errno)); + } +quit_guard0: + config_free(); + return retval; +} diff --git a/org.glite.lb.logger/Makefile b/org.glite.lb.logger/Makefile index a759033..b6f57a9 100644 --- a/org.glite.lb.logger/Makefile +++ b/org.glite.lb.logger/Makefile @@ -1,15 +1,12 @@ # defaults -top_srcdir=. +top_srcdir=.. stagedir=. -distdir=. globalprefix=glite lbprefix=lb package=glite-lb-client version=0.0.0 PREFIX=/opt/glite -glite_location=/opt/glite -globus_prefix=/opt/globus nothrflavour=gcc32 thrflavour=gcc32pthr @@ -26,10 +23,6 @@ VERSION=-DVERSION=\"GLite-${version}\" SUFFIXES=.no -GLOBUSINC=-I${globus_prefix}/include/${nothrflavour} - -GLOBUSTHRINC=-I${globus_prefix}/include/${thrflavour} - ifdef LB_STANDALONE LB_STANDALONE_FLAGS:=-DLB_STANDALONE endif @@ -45,28 +38,23 @@ else LOGD:=glite-lb-logd INTERLOGD:=glite-lb-interlogd NOTIF_INTERLOGD:=glite-lb-notif-interlogd + WS_INTERLOGD:=glite-lb-ws-interlogd endif DEBUG:=-g -O0 CFLAGS:=${DEBUG} \ - -I${stagedir}/include -I${top_srcdir}/src \ + -I${stagedir}/include -I${top_srcdir}/src -I${top_srcdir}/interface \ -D_GNU_SOURCE \ ${COVERAGE_FLAGS} \ ${VERSION} ${LB_STANDALONE_FLAGS} ${LB_PERF_FLAGS} -LDFLAGS:=-L${stagedir}/lib \ +LDFLAGS:=-L${stagedir}/${libdir} \ ${COVERAGE_FLAGS} -LINK:=libtool --mode=link ${CC} ${LDFLAGS} -LINKXX:=libtool --mode=link ${CXX} -rpath ${stagedir}/lib ${LDFLAGS} -INSTALL:=libtool --mode=install install - -GLOBUS_LIBS:= -L${globus_prefix}/lib \ - -lglobus_common_${nothrflavour} \ - -lglobus_gssapi_gsi_${nothrflavour} -GLOBUS_THRLIBS:= -L${globus_prefix}/lib \ - -lglobus_common_${thrflavour} \ - -lglobus_gssapi_gsi_${thrflavour} +COMPILE:=libtool --mode=compile ${CC} +LINK:=libtool --mode=link ${CC} -rpath ${stagedir}/${libdir} ${LDFLAGS} +LINKXX:=libtool --mode=link ${CXX} -rpath ${stagedir}/${libdir} ${LDFLAGS} +INSTALL:=libtool --mode=install install #ifneq (${expat_prefix},/usr) # EXPAT_LIBS:=-L${expat_prefix}/lib @@ -75,11 +63,15 @@ GLOBUS_THRLIBS:= -L${globus_prefix}/lib \ # #EXT_LIBS:= ${EXPAT_LIBS} +HDRS:=interlogd.h il_error.h + COMMON_LIB:=-lglite_lb_common +EXT_LIB:=-lglite_lbu_trio -lglite_lbu_log + GLITE_GSS_LIB:=-lglite_security_gss -TEST_LIBS:=-L${cppunit_prefix}/lib -lcppunit +TEST_LIBS:=-L${cppunit_prefix}/${libdir} -lcppunit TEST_INC:=-I${cppunit_prefix}/include LOGD_OBJS:= logd_proto.o logd.o @@ -87,11 +79,17 @@ LOGD_OBJS:= logd_proto.o logd.o LOGD_NOBJS:=${LOGD_OBJS:.o=.no} INTERLOG_OBJS:=il_error.o input_queue_socket.o \ - recover.o send_event.o \ + recover.o send_event.o plugin_mgr.o \ event_queue.o event_store.o il_master.o interlogd.o \ - queue_mgr.o server_msg.o queue_thread.o + queue_mgr.o server_msg.o queue_thread.o \ -INTERLOG_NOBJS:=${INTERLOG_OBJS:.o=.no} +WS_INTERLOG_OBJS:=il_error.o input_queue_socket_http.o \ + recover.o http.o send_event_http.o plugin_mgr.o \ + event_queue.o event_store_http.o il_master.o interlogd.o \ + queue_mgr_http.o server_msg_http.o queue_thread.o + +INTERLOG_NOTIF_OBJS:=${INTERLOG_OBJS:.o=.notif.lo} +INTERLOG_WS_OBJS:=${WS_INTERLOG_OBJS:.o=.ws.o} INTERLOG_PERF_OBJS:=${INTERLOG_OBJS:.o=.perf.o} INTERLOG_EMPTY_OBJS:=${INTERLOG_OBJS:.o=.empty.o} #INTERLOG_INLINE_EMPTY_OBJS:=${INTERLOG_OBJS:.o=.io} @@ -108,6 +106,7 @@ INTERLOG_TEST_OBJS:= \ input_queue_socket.o \ input_queue_socketTest.o \ send_event.o \ + plugin_mgr. o \ event_queue.o \ event_queueTest.o \ IlTestBase.o \ @@ -118,51 +117,55 @@ MAN = $(MAN_GZ:.gz=) default: all -all compile: $(LOGD) $(INTERLOGD) ${MAN_GZ} +all compile: $(LOGD) $(INTERLOGD) $(NOTIF_INTERLOGD) ${MAN_GZ} glite-lb-logd: ${LOGD_OBJS} - ${LINK} -o $@ ${LOGD_OBJS} ${COMMON_LIB}_${nothrflavour} + ${LINK} -o $@ ${LOGD_OBJS} ${COMMON_LIB}_${nothrflavour} ${EXT_LIB} glite-lb-logd-perf: ${LOGD_OBJS} - ${LINK} -o $@ ${LOGD_OBJS} ${COMMON_LIB}_${nothrflavour} + ${LINK} -o $@ ${LOGD_OBJS} ${COMMON_LIB}_${nothrflavour} ${EXT_LIB} glite-lb-logd-nofile: ${LOGD_NOBJS} - ${LINK} -o $@ ${LOGD_NOBJS} ${COMMON_LIB}_${nothrflavour} + ${LINK} -o $@ ${LOGD_NOBJS} ${COMMON_LIB}_${nothrflavour} ${EXT_LIB} glite-lb-logd-perf-nofile: ${LOGD_NOBJS} - ${LINK} -o $@ ${LOGD_NOBJS} ${COMMON_LIB}_${nothrflavour} + ${LINK} -o $@ ${LOGD_NOBJS} ${COMMON_LIB}_${nothrflavour} ${EXT_LIB} glite-lb-interlogd: ${INTERLOG_OBJS} - ${LINK} -o $@ ${INTERLOG_OBJS} ${COMMON_LIB}_${thrflavour} + ${LINK} -o $@ ${INTERLOG_OBJS} ${COMMON_LIB}_${thrflavour} ${EXT_LIB} -glite-lb-notif-interlogd: ${INTERLOG_NOBJS} - ${LINK} -o $@ ${INTERLOG_NOBJS} ${COMMON_LIB}_${thrflavour} +glite-lb-notif-interlogd: ${INTERLOG_NOTIF_OBJS} + ${LINK} -export-dynamic -o $@ ${INTERLOG_NOTIF_OBJS} ${COMMON_LIB}_${thrflavour} ${EXT_LIB} glite-lb-interlogd-perf: ${INTERLOG_PERF_OBJS} - ${LINK} -o $@ ${INTERLOG_PERF_OBJS} ${COMMON_LIB}_${thrflavour} + ${LINK} -o $@ ${INTERLOG_PERF_OBJS} ${COMMON_LIB}_${thrflavour} ${EXT_LIB} glite-lb-interlogd-perf-empty: ${INTERLOG_EMPTY_OBJS} - ${LINK} -o $@ ${INTERLOG_EMPTY_OBJS} ${COMMON_LIB}_${thrflavour} + ${LINK} -o $@ ${INTERLOG_EMPTY_OBJS} ${COMMON_LIB}_${thrflavour} ${EXT_LIB} + +glite-lb-ws-interlogd: ${INTERLOG_WS_OBJS} + ${LINK} -o $@ ${INTERLOG_WS_OBJS} ${COMMON_LIB}_${thrflavour} ${EXT_LIB} #glite-lb-interlogd-perf-inline-empty: ${INTERLOG_INLINE_EMPTY_OBJS} # ${LINK} -o $@ ${INTERLOG_INLINE_EMPTY_OBJS} \ # ${COMMON_LIB}_${thrflavour} ${MAN_GZ}: ${MAN} + rm -f ${MAN_GZ} ${MAN} cp $? . - gzip $(notdir $?) + gzip -f $(notdir $?) man: ${MAN_GZ} stage: compile - $(MAKE) install PREFIX=${stagedir} DOSTAGE=yes + $(MAKE) install PREFIX=${stagedir} check: # do nothing until test/ is really added to CVS # check.ll check.il #check.ll: logd_proto_test.o ll_test.o -# ${LINKXX} -o $@ ${COMMON_LIB}_${nothrflavour} ${EXT_LIBS} ${GLOBUS_LIBS} ${TEST_LIBS} $+ +# ${LINKXX} -o $@ ${COMMON_LIB}_${nothrflavour} ${EXT_LIBS} ${TEST_LIBS} $+ # ./check.ll check.ll: @@ -171,66 +174,59 @@ check.ll: check.il: ${INTERLOG_TEST_OBJS} ${LINKXX} -o $@ ${COMMON_LIB}_${thrflavour} ${GLITE_GSS_LIB}_${nothrflavour} ${TEST_LIBS} -lpthread $+ -dist: distsrc distbin - -distsrc: - mkdir -p ${top_srcdir}/${package}-${version} - cd ${top_srcdir} && GLOBIGNORE="${package}-${version}" && cp -Rf * ${package}-${version} - cd ${top_srcdir} && tar -czf ${distdir}/${package}-${version}_src.tar.gz --exclude-from=project/tar_exclude ${package}-${version} - rm -rf ${top_srcdir}/${package}-${version} - -distbin: - $(MAKE) install PREFIX=`pwd`/tmpbuilddir${stagedir} - save_dir=`pwd`; cd tmpbuilddir${stagedir} && tar -czf $$save_dir/${top_srcdir}/${distdir}/${package}-${version}_bin.tar.gz *; cd $$save_dir - rm -rf tmpbuilddir - install: -mkdir -p ${PREFIX}/bin -mkdir -p ${PREFIX}/etc/init.d -mkdir -p ${PREFIX}/share/doc/${package}-${version} -mkdir -p ${PREFIX}/share/man/man8 + -mkdir -p ${PREFIX}/include/glite/lb ${INSTALL} -m 755 ${LOGD} ${PREFIX}/bin ${INSTALL} -m 755 ${INTERLOGD} ${PREFIX}/bin -# if [ x${DOSTAGE} = xyes ]; then \ -# ${INSTALL} -m 755 ${NOTIF_INTERLOGD} ${PREFIX}/bin; \ -# fi + ${INSTALL} -m 755 ${NOTIF_INTERLOGD} ${PREFIX}/bin ifdef LB_PERF + -mkdir -p ${PREFIX}/sbin ${INSTALL} -m 755 ${top_srcdir}/src/perftest_ll.sh ${PREFIX}/sbin ${INSTALL} -m 755 ${top_srcdir}/src/perftest_il.sh ${PREFIX}/sbin endif ${INSTALL} -m 755 ${top_srcdir}/config/startup ${PREFIX}/etc/init.d/glite-lb-locallogger ${INSTALL} -m 644 ${top_srcdir}/LICENSE ${PREFIX}/share/doc/${package}-${version} + ( cd ${top_srcdir}/interface && ${INSTALL} -m 644 ${HDRS} ${PREFIX}/include/${globalprefix}/${lbprefix} ) + ( cd ${top_srcdir}/project && ${INSTALL} -m 644 ChangeLog package.description package.summary ${PREFIX}/share/doc/${package}-${version} ) ${INSTALL} -m 644 ${MAN_GZ} ${PREFIX}/share/man/man8 -${INTERLOG_NOBJS}: %.no: %.c - ${CC} ${CFLAGS} ${GLOBUSTHRINC} -DIL_NOTIFICATIONS -c $< -o $@ +${INTERLOG_NOTIF_OBJS}: %.notif.lo: %.c + ${COMPILE} ${CFLAGS} -DIL_NOTIFICATIONS -c $< -o $@ ${INTERLOG_OBJS}: %.o: %.c - ${CC} ${CFLAGS} ${GLOBUSTHRINC} -c $< -o $@ + ${COMPILE} ${CFLAGS} -c $< -o $@ + +${INTERLOG_WS_OBJS}: %.ws.o: %.c + ${CC} ${CFLAGS} -DIL_WS -c $< -o $@ ${INTERLOG_EMPTY_OBJS}: %.empty.o: %.c - ${CC} ${CFLAGS} ${GLOBUSTHRINC} -DPERF_EMPTY -c $< -o $@ + ${CC} ${CFLAGS} -DPERF_EMPTY -c $< -o $@ ${INTERLOG_PERF_OBJS}: %.perf.o: %.c - ${CC} ${CFLAGS} ${GLOBUSTHRINC} -c $< -o $@ + ${CC} ${CFLAGS} -c $< -o $@ #${INTERLOG_INLINE_EMPTY_OBJS}: %.io: %.c -# ${CC} ${CFLAGS} ${GLOBUSTHRINC} -DLB_PERF -DPERF_EMPTY -DPERF_EVENTS_INLINE -c $< -o $@ +# ${CC} ${CFLAGS} -DLB_PERF -DPERF_EMPTY -DPERF_EVENTS_INLINE -c $< -o $@ ${LOGD_NOBJS}: %.no: %.c - ${CC} ${CFLAGS} ${GLOBUSINC} -DLOGD_NOFILE -c $< -o $@ + ${CC} ${CFLAGS} -DLOGD_NOFILE -c $< -o $@ ${LOGD_OBJS}: %.o: %.c - ${CC} ${CFLAGS} ${GLOBUSINC} -c $< -o $@ + ${CC} ${CFLAGS} -c $< -o $@ logd_proto_test.o: %.o: %.c - ${CC} ${CFLAGS} ${GLOBUSINC} -c $< -o $@ + ${CC} ${CFLAGS} -c $< -o $@ ll_test.o: %.o: %.cpp ${CXX} ${CFLAGS} ${TEST_INC} -c $< -o $@ il_test.o IlTestBase.o server_msgTest.o event_queueTest.o input_queue_socketTest.o event_storeTest.o: %.o: %.cpp - ${CXX} ${CFLAGS} ${GLOBUSTHRINC} ${TEST_INC} -c $< -o $@ + ${CXX} ${CFLAGS} ${TEST_INC} -c $< -o $@ clean: - rm -rf .libs/ *.o *.no ${LOGD} ${INTERLOGD} ${NOTIF_INTERLOGD} {MAN_GZ} + rm -rvf .libs/ *.o *.lo ${LOGD} ${INTERLOGD} ${NOTIF_INTERLOGD} ${MAN_GZ} + rm -rvf log.xml project/ rpmbuild/ RPMS/ tgz/ diff --git a/org.glite.lb.logger/config/startup b/org.glite.lb.logger/config/startup index 814f9b8..1454c9f 100755 --- a/org.glite.lb.logger/config/startup +++ b/org.glite.lb.logger/config/startup @@ -1,5 +1,21 @@ #!/bin/sh # chkconfig: 345 76 24 +# +# Copyright (c) Members of the EGEE Collaboration. 2004-2010. +# See http://www.eu-egee.org/partners/ for details on the copyright holders. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# GLITE_LOCATION=${GLITE_LOCATION:-/opt/glite} GLITE_LOCATION_VAR=${GLITE_LOCATION_VAR:-$GLITE_LOCATION/var} @@ -12,10 +28,36 @@ GLITE_LOCATION_VAR=${GLITE_LOCATION_VAR:-$GLITE_LOCATION/var} [ -f $HOME/.glite.conf ] && . $HOME/.glite.conf -unset creds port +LL_PIDFILE=${LL_PIDFILE:-$GLITE_LOCATION_VAR/glite-lb-logd.pid} +IL_PIDFILE=${IL_PIDFILE:-$GLITE_LOCATION_VAR/glite-lb-interlogd.pid} + +unset creds port log4c + +start_daemon() +{ + local name="$1" + local pidfile="$2" + local cmd="$3" + + if [ -f "$pidfile" ]; then + if kill -0 `cat $pidfile`; then + return 0 + fi + echo -n "Warning: stalled $pidfile for $name" + rm -f "$pidfile" + fi + echo -n "Starting $name ..." + su - $GLITE_USER -c "$log4c $cmd" && echo " done" || echo " FAILED" +} start() { + case "$GLITE_LB_TYPE" in + proxy) + echo 'Not starting logd and interlogger, proxy only instance (GLITE_LB_TYPE=proxy).' + return 0 + esac + if test -z "$GLITE_USER" ;then echo 'Error: GLITE_USER is not set' echo FAILED @@ -38,26 +80,50 @@ start() [ -n "$GLITE_LB_IL_SOCK" ] && sock="--socket $GLITE_LB_IL_SOCK" [ -n "$GLITE_LB_IL_FPREFIX" ] && fprefix="--file-prefix $GLITE_LB_IL_FPREFIX" + log4c="LOG4C_RCPATH='$GLITE_LOCATION/etc/glite-lb'" + mkdir -p /var/glite/log chown $GLITE_USER /var/glite/log - echo -n Starting glite-lb-logd ... (cd /tmp && ls -f /tmp |grep ^dglogd_sock_ |xargs rm -f) - su - $GLITE_USER -c "$GLITE_LOCATION/bin/glite-lb-logd \ - $creds $port $sock $fprefix" && echo " done" || echo " FAILED" + start_daemon "glite-lb-logd" "$LL_PIDFILE" "$GLITE_LOCATION/bin/glite-lb-logd \ + -i $LL_PIDFILE $creds $port $sock $fprefix" + + start_daemon "glite-lb-interlogd" "$IL_PIDFILE" "$GLITE_LOCATION/bin/glite-lb-interlogd \ + -i $IL_PIDFILE $creds $sock $fprefix" +} - echo -n Starting glite-lb-interlogd ... - su - $GLITE_USER -c "$GLITE_LOCATION/bin/glite-lb-interlogd \ - $creds $sock $fprefix" && echo " done" || echo " FAILED" +killwait() +{ + pidfile=$1 + if [ -f $pidfile ] && pid=`cat $pidfile` && kill $pid 2>/dev/null; then + cnt=0 + while ps p $pid 2>/dev/null >/dev/null; do + sleep 1; + cnt=`expr $cnt + 1` + if [ $cnt = 120 ]; then break; fi + done + if [ $cnt = 100 ]; then echo " can't stop" + else echo " done"; fi + else + echo " not running" + fi } stop() { - echo -n Stopping glite-lb-logd ... - killall glite-lb-logd - echo " done" - echo -n Stopping glite-lb-interlogd ... - killall glite-lb-interlogd - echo " done" + echo -n Stopping glite-lb-logd ... + killwait $LL_PIDFILE + echo -n Stopping glite-lb-interlogd ... + killwait $IL_PIDFILE + + # for L&B <= 2.0 + LC_ALL=C + if netstat -an --inet | grep "^tcp .* 0.0.0.0:${GLITE_LB_LOGGER_PORT:-9002} .*LISTEN" >/dev/null 2>&1 ;then + killall -9 glite-lb-logd + fi + if netstat -an --unix | grep "^unix .* LISTEN.* ${GLITE_LB_IL_SOCK:-/tmp/interlogger.sock}$" >/dev/null 2>&1 ;then + killall -9 glite-lb-interlogd + fi } status() diff --git a/org.glite.lb.logger/configure b/org.glite.lb.logger/configure new file mode 100755 index 0000000..71ff6f0 --- /dev/null +++ b/org.glite.lb.logger/configure @@ -0,0 +1,843 @@ +#!/usr/bin/perl + +# WARNING: Don't edit this file unless it is the master copy in org.glite.lb +# +# For the purpose of standalone builds of lb/jobid/lbjp-common components +# it is copied on tagging + +# $Header$ +# +# Copyright (c) Members of the EGEE Collaboration. 2004-2010. +# See http://www.eu-egee.org/partners/ for details on the copyright holders. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +use Getopt::Long; + +my $pwd = `pwd`; chomp $pwd; +my $prefix = $pwd.'/stage'; +my $stagedir; +my $staged; +my $module; +my $thrflavour = 'gcc64dbgpthr'; +my $nothrflavour = 'gcc64dbg'; +my $mode = 'build'; +my $help = 0; +my $listmodules; +my $version; +my $branch; +my $output; +my $lb_tag = ''; +my $lbjp_tag = ''; +my $jp_tag = ''; +my $sec_tag = ''; +my $jobid_tag = ''; +my $libdir = getlibdir(); + +my @nodes = qw/client server logger utils client-java doc ws-test db jpprimary jpindex jpclient harvester/; +my %enable_nodes; +my %disable_nodes; + +my %extern_prefix = ( + cares => '/opt/c-ares', + classads => '/opt/classads', + cppunit => '/usr', + expat => '/usr', + globus => '/opt/globus', + gsoap => '/usr', + mysql => '/usr', + 'mysql-devel' => '', + 'mysql-server' => '', + voms => '/opt/glite', + gridsite => '/opt/glite', + lcas => '/opt/glite', + trustmanager => '/opt/glite', + utiljava => '/opt/glite', + ant => '/usr', + jdk => '/usr', + libtar => '/usr', + axis => '/usr', + log4c => '/usr', + postgresql => '/usr' +); + +my %jar = ( + 'commons-codec' => '/usr/share/java/commons-codec.jar', + 'commons-lang' => '/usr/share/java/commons-lang.jar', +); + + +my %glite_prefix; +my %need_externs; +my %need_externs_type; +my %need_jars; +my %extrafull; +my %extranodmod; +my %deps; +my %deps_type; +my %topbuild; + +my %lbmodules = ( + 'lb' => [ qw/client client-java common doc logger server state-machine types utils ws-interface ws-test harvester yaim glite-LB/], + 'security' => [qw/gss gsoap-plugin/], + 'lbjp-common' => [qw/db log maildir server-bones trio jp-interface/], + 'jobid' => [qw/api-c api-cpp api-java/], + 'jp' => [ qw/client doc index primary server-common ws-interface/ ], + ); + + +my @opts = ( + 'prefix=s' => \$prefix, + 'staged=s' => \$staged, + 'module=s' => \$module, + 'thrflavour=s' => \$thrflavour, + 'nothrflavour=s' => \$nothrflavour, + 'mode=s' => \$mode, + 'listmodules=s' => \$listmodules, + 'version=s' => \$version, + 'branch=s' => \$branch, + 'output=s' => \$output, + 'stage=s' => \$stagedir, + 'lb-tag=s' => \$lb_tag, + 'lbjp-common-tag=s' => \$lbjp_tag, + 'jp-tag=s' => \$jp_tag, + 'security-tag=s' => \$sec_tag, + 'jobid-tag=s' => \$jobid_tag, + 'help' => \$help, + 'libdir=s' => \$libdir, +); + +for (@nodes) { + $enable_nodes{$_} = 0; + $disable_nodes{$_} = 0; + + push @opts,"disable-$_",\$disable_nodes{$_}; + push @opts,"enable-$_",\$enable_nodes{$_}; +} + +push @opts,"with-$_=s",\$extern_prefix{$_} for keys %extern_prefix; +push @opts,"with-$_=s",\$jar{$_} for keys %jar; + +my @keeparg = @ARGV; + +GetOptions @opts or die "Errors parsing command line\n"; + +$extern_prefix{'mysql-devel'}=$extern_prefix{mysql} if $extern_prefix{'mysql-devel'} eq ''; +$extern_prefix{'mysql-server'}=$extern_prefix{mysql} if $extern_prefix{'mysql-server'} eq ''; + +if ($help) { usage(); exit 0; } + +if ($listmodules) { + my @m = map "org.glite.$listmodules.$_",@{$lbmodules{$listmodules}}; + print "@m\n"; + exit 0; +} + +warn "$0: --version, --branch and --output make sense only in --mode=etics\n" + if ($version || $output || $branch) && $mode ne 'etics'; + +my $en; +for (keys %enable_nodes) { $en = 1 if $enable_nodes{$_}; } + +my $dis; +for (keys %disable_nodes) { $dis = 1 if $disable_nodes{$_}; } + +die "--enable-* and --disable-* are mutually exclusive\n" + if $en && $dis; + +die "--module cannot be used with --enable-* or --disable-*\n" + if $module && ($en || $dis); + +die "$module: unknown module\n" if $module && ! grep $module,@{$lbmodules{lb}},@{$lbmodules{security}},{$lbmodules{jp}}; + +if ($dis) { + for (@nodes) { + $enable_nodes{$_} = 1 unless $disable_nodes{$_}; + } +} + +if (!$en && !$dis) { $enable_nodes{$_} = 1 for (@nodes) } ; + +for (keys %enable_nodes) { delete $enable_nodes{$_} unless $enable_nodes{$_}; } + +$stagedir = $prefix unless $stagedir; + +if ($mode eq 'build') { + print "Writing config.status\n"; + open CONF,">config.status" or die "config.status: $!\n"; + print CONF "$0 @keeparg\n"; + close CONF; +} + + +my @modules; +my %aux; + +if ($module) { +# push @modules,split(/[,.]+/,$module); + push @modules,$module; +} +else { + @modules = map(($extranodmod{$_} ? $extranodmod{$_} : 'lb.'.$_),(keys %enable_nodes)); + + my $n; + + do { + local $"="\n"; + $n = $#modules; + push @modules,(map @{$deps{$_}},@modules); + + undef %aux; @aux{@modules} = (1) x ($#modules+1); + @modules = keys %aux; + } while ($#modules > $n); +} + +@aux{@modules} = (1) x ($#modules+1); +delete $aux{$_} for (split /,/,$staged); +@modules = keys %aux; + +mode_build() if $mode eq 'build'; +mode_checkout() if $mode eq 'checkout'; +mode_etics($module) if $mode eq 'etics'; + +sub mode_build { + print "\nBuilding modules: @modules\n"; + + my @ext = map @{$need_externs{$_}},@modules; + my @myjars = map @{$need_jars{$_}},@modules; + undef %aux; @aux{@ext} = 1; + @ext = keys %aux; + undef %aux; @aux{@myjars} = (1) x ($#myjars+1); + @myjars = keys %aux; + + print "\nRequired externals:\n"; + print "\t$_: $extern_prefix{$_}\n" for @ext; + print "\t$_: $jar{$_}\n" for @myjars; + print "\nThis is a poor-man configure, it's up to you to have sources and externals there\n\n"; + + mkinc($_) for @modules; + + print "Creating Makefile\n"; + + open MAK,">Makefile" or die "Makefile: $!\n"; + + print MAK "all: @modules\n\nclean:\n"; + + for (@modules) { + my $full = full($_); + my $build = $topbuild{$_} ? '': '/build'; + print MAK "\tcd $full$build && \${MAKE} clean\n" + } + + print MAK "\ndistclean:\n"; + + for (@modules) { + my $full = full($_); + print MAK $topbuild{$_} ? + "\tcd $full$build && \${MAKE} distclean\n" : + "\trm -rf $full$build\n" + } + + print MAK "\n"; + + for (@modules) { + my %ldeps; undef %ldeps; + @ldeps{@{$deps{$_}}} = 1; + for my $x (split /,/,$staged) { delete $ldeps{$x}; } + my @dnames = $module ? () : keys %ldeps; + + my $full = full($_); + my $build = $topbuild{$_} ? '': '/build'; + + print MAK "$_: @dnames\n\tcd $full$build && \${MAKE} && \${MAKE} install\n\n"; + } + + close MAK; +} + +sub mode_checkout() { + for (@modules) { + my $module = $_; + my $tag = ""; + if ($lb_tag){ + for (@{$lbmodules{lb}}){ + if ("lb.".$_ eq $module){ + $tag = '-r '.$lb_tag; + } + } + } + if ($lbjp_tag){ + for (@{$lbmodules{'lbjp-common'}}){ + if ("lbjp-common.".$_ eq $module){ + $tag = '-r '.$lbjp_tag; + } + } + } + if ($jp_tag){ + for (@{$lbmodules{'jp'}}){ + if ("jp.".$_ eq $module){ + $tag = '-r '.$jp_tag; + } + } + } + if ($sec_tag){ + for (@{$lbmodules{security}}){ + if ("security.".$_ eq $module){ + $tag = '-r '.$sec_tag; + } + } + } + if ($jobid_tag){ + for (@{$lbmodules{jobid}}){ + if ("jobid.".$_ eq $module){ + $tag = '-r '.$jobid_tag; + } + } + } + #if (grep {"lb.".$_ eq $module} @{$lbmodules{lb}}){ + # print "found"; + #} + $_ = full($_); + print "\n*** Checking out $_\n"; + system("cvs checkout $tag $_") == 0 or die "cvs checkout $tag $_: $?\n"; + } +} + +BEGIN{ +%need_externs_aux = ( + 'lb.client' => [ qw/cppunit:B classads/ ], + 'lb.client-java' => [ qw/ant:B jdk:B axis:B trustmanager utiljava/ ], + 'lb.common' => [ qw/expat cares:B cppunit:B classads/ ], + 'lb.doc' => [], + 'lb.logger' => [ qw/cppunit:B/ ], + 'lb.server' => [ qw/globus_essentials:R globus:B expat cares mysql:R mysql-server:R mysql-devel:B cppunit:B gsoap:B classads voms lcas gridsite/ ], + 'lb.state-machine' => [ qw/classads/ ], + 'lb.utils' => [ qw/cppunit:B/ ], + 'lb.ws-interface' => [], + 'lb.ws-test' => [ qw/gsoap:B/ ], + 'lb.types' => [ qw// ], + 'lb.harvester' => [ qw// ], + 'lb.yaim' => [ qw/yaim_core:R/ ], + 'lb.glite-LB' => [ qw/fetchcrl:R gpt:R gip_release:R gip_service:R bdii:R glite_version:R glite_info_templates:R glue_schema:R/ ], + 'lbjp-common.db' => [ qw/mysql:B mysql-devel:B postgresql:B/ ], + 'lbjp-common.log' => [ qw/log4c/ ], + 'lbjp-common.maildir' => [ qw// ], + 'lbjp-common.server-bones' => [ qw// ], + 'lbjp-common.trio' => [ qw/cppunit:B/ ], + 'lbjp-common.jp-interface' => [ qw/cppunit:B log4c:B/ ], + 'security.gss' => [ qw/globus_essentials:R globus:B cares cppunit:B/ ], + 'security.gsoap-plugin' => [ qw/cppunit:B globus_essentials:R globus:B cares:B gsoap:B/ ], + 'jobid.api-c' => [ qw/cppunit:B/ ], + 'jobid.api-cpp' => [ qw/cppunit:B/ ], + 'jobid.api-java' => [ qw/ant:B jdk:B/ ], + 'jp.client' => [ qw/gsoap libtar globus_essentials:R globus:B/ ], + 'jp.doc' => [], + 'jp.index' => [ qw/gsoap globus_essentials:R globus:B/ ], + 'jp.primary' => [ qw/classads gsoap libtar globus_essentials:R globus:B/ ], + 'jp.server-common' => [], + 'jp.ws-interface' => [], +); + +for my $ext (keys %need_externs_aux) { + for (@{$need_externs_aux{$ext}}) { + /([^:]*)(?::(.*))?/; + push @{$need_externs{$ext}},$1; + my $type = $2 ? $2 : 'BR'; + $need_externs_type{$ext}->{$1} = $type; + } +} + +%need_jars = ( + 'jobid.api-java' => [ qw/commons-codec/ ], + 'lb.client-java' => [ qw/commons-lang/ ], +); + +for my $jar (keys %need_jars) { + for (@{$need_jars{$jar}}) { + $need_externs_type{$jar}->{$_} = 'BR'; # XXX + } +} + +%deps_aux = ( + 'lb.client' => [ qw/ + lb.types:B lb.common + lbjp-common.trio + jobid.api-cpp:B jobid.api-c + security.gss + / ], + 'lb.client-java' => [ qw/ + lb.types:B + lb.ws-interface:B + jobid.api-java + / ], + 'lb.common' => [ qw/ + jobid.api-cpp:B jobid.api-c + lb.types:B lbjp-common.trio security.gss + / ], + 'lb.doc' => [ qw/lb.types:B/ ], + 'lb.logger' => [ qw/ + lbjp-common.trio + lbjp-common.log + jobid.api-c + lb.common + security.gss + / ], + 'lb.server' => [ qw/ + lb.ws-interface lb.types:B lb.common lb.state-machine + lbjp-common.db lbjp-common.server-bones lbjp-common.trio lbjp-common.maildir lbjp-common.log + jobid.api-c + security.gsoap-plugin security.gss + / ], + 'lb.state-machine' => [ qw/lb.types:B lb.common lbjp-common.jp-interface security.gss/ ], + 'lb.utils' => [ qw/ + lbjp-common.jp-interface + jobid.api-c + lbjp-common.trio lbjp-common.maildir + lb.client lb.state-machine + / ], + 'lb.ws-test' => [ qw/security.gsoap-plugin lb.ws-interface/ ], + 'lb.ws-interface' => [ qw/lb.types:B/ ], + 'lb.types' => [ qw// ], + 'lb.harvester' => [ qw/ + jobid.api-c lbjp-common.trio lbjp-common.db lb.common lb.client + security.gss lbjp-common.log + / ], + 'lb.yaim' => [ qw// ], + 'lb.glite-LB' => [ qw/ + lb.logger:R lb.server:R lb.utils:R lb.doc:R + lb.ws-test:R lb.harvester:R lb.yaim:R + / ], + 'lbjp-common.db' => [ qw/lbjp-common.trio lbjp-common.log/ ], + 'lbjp-common.maildir' => [ qw// ], + 'lbjp-common.server-bones' => [ qw/lbjp-common.log/ ], + 'lbjp-common.trio' => [ qw// ], + 'security.gss' => [ qw// ], + 'security.gsoap-plugin' => [ qw/security.gss/ ], + 'jobid.api-c' => [ qw// ], + 'jobid.api-cpp' => [ qw/jobid.api-c/ ], + 'jobid.api-java' => [ qw// ], + + 'lbjp-common.jp-interface' => [ qw/lbjp-common.db jobid.api-c/ ], + + 'jp.client' => [ qw/ + jp.ws-interface + lbjp-common.jp-interface lbjp-common.maildir + jobid.api-c + security.gsoap-plugin + / ], + 'jp.doc' => [ qw// ], + 'jp.index' => [ qw/ + jp.server-common jp.ws-interface + lbjp-common.jp-interface lbjp-common.trio lbjp-common.db lbjp-common.server-bones + security.gsoap-plugin + / ], + 'jp.primary' => [ qw/ + jobid.api-c + jp.server-common jp.ws-interface + lb.state-machine + lbjp-common.jp-interface lbjp-common.trio lbjp-common.db lbjp-common.server-bones + security.gsoap-plugin + / ], + 'jp.server-common' => [ qw/ + lbjp-common.jp-interface lbjp-common.db + / ], + 'jp.ws-interface' => [ qw// ], +); + +for my $ext (keys %deps_aux) { + for (@{$deps_aux{$ext}}) { + /([^:]*)(?::(.*))?/; + push @{$deps{$ext}},$1; + my $type = $2 ? $2 : 'BR'; + $deps_type{$ext}->{$1} = $type; + } +} + + +%extrafull = ( gridsite=>'org.gridsite.core'); + +#( java => 'client-java' ); +%extranodmod = ( + db => 'lbjp-common.db', + jpprimary => 'jp.primary', + jpindex => 'jp.index', + jpclient => 'jp.client', +); + +%obsoletes = ( + 'lb.yaim' => [ qq/glite-yaim-lb/ ], +); + +my @t = qw/lb.client-java jobid.api-java lb.types/; +@topbuild{@t} = (1) x ($#t+1); +} + +sub full +{ + my $short = shift; + return $extrafull{$short} ? $extrafull{$short} : 'org.glite.'.$short; +} + +sub mkinc +{ + my %aux; + undef %aux; + my @m=qw/ +lb.client lb.doc lb.state-machine lb.ws-interface lb.logger lb.types lb.common lb.server lb.utils lb.ws-test lb.client-java lb.harvester lb.yaim lb.glite-LB +security.gss security.gsoap-plugin +jobid.api-c jobid.api-cpp jobid.api-java +lbjp-common.db lbjp-common.log lbjp-common.maildir lbjp-common.server-bones lbjp-common.trio lbjp-common.jp-interface +jp.client jp.doc jp.index jp.primary jp.server-common jp.ws-interface +/; + @aux{@m} = (1) x ($#m+1); + + my $short = shift; + my $full = full $short; + + unless ($aux{$short}) { + print "Makefile.inc not needed in $full\n"; + return; + } + + my $build = ''; + + unless ($topbuild{$_}) { + $build = '/build'; + unless (-d "$full/build") { + mkdir "$full/build" or die "mkdir $full/build: $!\n"; + } + unlink "$full/build/Makefile"; + symlink "../Makefile","$full/build/Makefile" or die "symlink ../Makefile $full/build/Makefile: $!\n"; + } + + open MKINC,">$full$build/Makefile.inc" + or die "$full$build/Makefile.inc: $!\n"; + + print "Creating $full$build/Makefile.inc\n"; + + print MKINC qq{ +PREFIX = $prefix +stagedir = $stagedir +thrflavour = $thrflavour +nothrflavour = $nothrflavour +libdir = $libdir +}; + + for (@{$need_externs{$short}}) { + print MKINC "${_}_prefix = $extern_prefix{$_}\n" + } + + for (@{$need_jars{$short}}) { + print MKINC "${_}_jar = $jar{$_}\n" + } + + my $need_gsoap = 0; + for (@{$need_externs{$short}}) { $need_gsoap = 1 if $_ eq 'gsoap'; } + + print MKINC "gsoap_default_version=".gsoap_version()."\n" if $need_gsoap; + + close MKINC; +} + +my %etics_externs; +my %etics_projects; +BEGIN{ + %etics_externs = ( + globus_essentials=>'vdt_globus_essentials', + globus=>'globus', + cares=>'c-ares', + voms=>'org.glite.security.voms-api-cpp', + gridsite=>'org.gridsite.shared', + lcas=>'org.glite.security.lcas', + trustmanager=>'org.glite.security.trustmanager', + utiljava=>'org.glite.security.util-java', + gpt=>'gpt', + fetchcrl=>'fetch-crl', + gip_release=>'glite-info-provider-release', + gip_service=>'glite-info-provider-service', + bdii=>'bdii', + glite_version=>'glite-version', + glite_info_templates=>'glite-info-templates', + glue_schema=>'glue-schema', + yaim_core=>'org.glite.yaim.core', + ); + %etics_projects = ( + vdt=>[qw/globus globus_essentials/], + 'org.glite'=>[qw/voms gridsite lcas gpt gip_release gip_service bdii glite_version glite_info_templates glue_schema yaim_core/], + ); +}; + +sub mode_etics { + $fmod = shift; + + die "$0: --module required with --etics\n" unless $fmod; + + my ($subsys,$module) = split /\./,$fmod; + + my ($major,$minor,$rev,$age); + + if ($version) { + $version =~ /([[:digit:]]+)\.([[:digit:]]+)\.([[:digit:]]+)-(.+)/; + ($major,$minor,$rev,$age) = ($1,$2,$3,$4); + } + else { + open V,"org.glite.$subsys.$module/project/version.properties" + or die "org.glite.$subsys.$module/project/version.properties: $!\n"; + + while ($_ = ) { + chomp; + ($major,$minor,$rev) = ($1,$2,$3) if /module\.version\s*=\s*([[:digit:]]+)\.([[:digit:]]+)\.([[:digit:]]+)/; + $age = $1 if /module\.age\s*=\s*([[:digit:]]+)/; + } + close V; + } + + my @copts = (); + my %ge; + @ge{@{$etics_projects{'org.glite'}}} = (1) x ($#{$etics_projects{'org.glite'}}+1); + + for (@{$need_externs{"$subsys.$module"}}) { + if ($need_externs_type{"$subsys.$module"}->{$_}=~/B/) { + my $eext = $etics_externs{$_} ? $etics_externs{$_} : $_; + push @copts,$ge{$_} ? "--with-$_=\${stageDir}" : "--with-$_=\${$eext.location}"; + } + } + + for (@{$need_jars{"$subsys.$module"}}) { + my $eext = $etics_externs{$_} ? $etics_externs{$_} : $_; + + push @copts,"--with-$_ \${$eext.location}/$_*.jar"; + } + + my $conf; + my $conftag; + + if ($branch) { + $conf = "glite-${subsys}-${module}_$branch"; + $conftag = $branch; + $dwpath = ""; } + else { + $conf = "glite-$subsys-${module}_R_${major}_${minor}_${rev}_${age}"; + $conftag = $conf; + $dwpath = "path = \${projectName}/\${moduleName}/\${version}/\${platformName}/\${packageName}-\${version}-\${age}.tar.gz\n"; } +# my $conf = "glite-$subsys-${module}_R_${major}_${minor}_${rev}_${age}"; + my $file = $output ? $output : "$conf.ini"; + open C,">$file" or die "$file: $!\n"; + + my $buildroot = $topbuild{"$subsys.$module"} ? '' : "build.root = build"; + + my $confdir = $topbuild{"$subsys.$module"} ? '..' : '../..'; + + my $package_description = ""; + my $package_summary = ""; + + if (-e "org.glite.$subsys.$module/project/package.description") { + open V, "org.glite.$subsys.$module/project/package.description"; + $package_description = join ("", ); + close V; + chomp $package_description; + $package_description =~ s/\n/\\n/g; + $package_description = "package.description = $package_description"; + } + else { + print STDERR "package.description not found for $subsys.$module!\n"; } + + if (-e "org.glite.$subsys.$module/project/package.summary") { + open V, "org.glite.$subsys.$module/project/package.summary"; + $package_summary = join ("", ); + close V; + chomp $package_summary; + $package_summary =~ s/\n/\\n/g; + $package_summary = "package.summary = $package_summary"; + } + else { + print STDERR "package.summary not found for $subsys.$module!\n"; } + + + print STDERR "Writing $file\n"; + print C qq{ +[Configuration-$conf] +profile = None +moduleName = org.glite.$subsys.$module +displayName = $conf +description = org.glite.$subsys.$module +projectName = org.glite +age = $age +deploymentType = None +tag = $conftag +version = $major.$minor.$rev +$dwpath +[Platform-default:VcsCommand] +displayName = None +description = None +tag = cvs -d \${vcsroot} tag -R \${tag} \${moduleName} +branch = None +commit = None +checkout = cvs -d \${vcsroot} co -r \${tag} \${moduleName} + +[Platform-default:BuildCommand] +postpublish = None +packaging = None +displayName = None +description = None +doc = None +prepublish = None +publish = None +compile = make +init = None +install = make install +clean = make clean +test = make check +configure = cd $confdir && /usr/bin/perl \${moduleName}/configure --thrflavour=\${globus.thr.flavor} --nothrflavour=\${globus.nothr.flavor} --prefix=\${prefix} --stage=\${stageDir} --libdir=\${libdir} --module $subsys.$module @copts +checkstyle = None + +[Platform-default:Property] +$buildroot +$package_description +$package_summary +}; + for (@{$obsoletes{"$subsys.$module"}}) { + print C "package.obsoletes = $_\n"; + print C "package.replaces = $_\n"; + } + + print C qq{ +[Platform-default:DynamicDependency] +}; + for (@{$need_externs{"$subsys.$module"}},@{$need_jars{"$subsys.$module"}}) { + my $eext = $etics_externs{$_} ? $etics_externs{$_} : $_; + + my $proj = 'externals'; + for my $p (keys %etics_projects) { + for $m (@{$etics_projects{$p}}) { + $proj = $p if $m eq $_; + } + } + + my $type = $need_externs_type{"$subsys.$module"}->{$_}; + print C "$proj|$eext = $type\n"; + } + + for (@{$deps{"$subsys.$module"}}) { + my $type = $deps_type{"$subsys.$module"}->{$_}; + print C "org.glite|org.glite.$_ = $type\n"; + } + + close C; +} + +sub gsoap_version { + local $_; + my $gsoap_version; + open S,"$extern_prefix{gsoap}/bin/soapcpp2 -v 2>&1 |" or die "$extern_prefix{gsoap}/bin/soapcpp2: $!\n"; + + while ($_ = ) { + chomp; + + $gsoap_version = $1 if /The gSOAP Stub and Skeleton Compiler for C and C\+\+ ([.[:digit:][:alpha:]]+)$/; + } + close S; + return $gsoap_version; +} + +sub getlibdir { + if ( -e "/etc/debian_version") { # We are on Debian + $lib64="lib"; + $lib32="lib32"; } + else { # Another distribution + $lib64="lib64"; + $lib32="lib"; } + $libdir=$lib32; + + open INP, "uname -s | "; # Check kernel name + $kname= ; + chomp($kname); + close INP; + + if ( $kname == "Linux") { + $arch = ("x86_64\npowerpc\nppc64\n"); + + open INP, "uname -p | "; # Check processor type + $procname= ; + chomp($procname); + close INP; + + if ($arch =~/^$procname\n/) { + return ($lib64); } + + open INP, "uname -m | "; # Check machine hardware + $machname= ; + chomp($machname); + close INP; + + if ($arch =~/^$machname\n/) { + return ($lib64); } + + # special cases (hyperlink lib64, Debian) + if (-l "/usr/lib64") { + $libdir=$lib32; } + + # if /usr/lib64 doesn't exist at all (AIX) + unless ( -e "/usr/lib64" ) { + $libdir=$lib32; } + } + + if ( $kname == "SunOS") { + if (-e "/usr/lib/64") { + $libdir="lib/64"; } + } + + return $libdir; +} + +sub usage { + my @ext = keys %extern_prefix; + my @myjars, keys %jar; + + print STDERR qq{ +usage: $0 options + +General options (defaults in []): + --prefix=PREFIX destination directory [./stage] + --staged=module,module,... what is already in PREFIX (specify without org.glite.) + --thrflavour=flavour + --nothrflavour=flavour threaded and non-treaded flavours [gcc64dbgpthr,gcc64dbg] + --listmodules=subsys list modules of a subsystem + --libdir=libdir typically [lib,lib64] postfix + +Mode of operation: + --mode={checkout|build|etics} what to do [build] + +What to build: + --module=module build this module only (mostly in-Etics operation) + --enable-NODE build this "node" (set of modules) only. Available nodes are + @{$lbmodules{lb}},@{$lbmodules{security}} + --disable-NODE don't build this node + --lb-tag=tag checkout LB modules with specific tag + --jp-tag=tag checkout JP modules with specific tag + --lbjp-common-tag=tag checkout lbjp-common modules with specific tag + --security-tag=tag checkout security modules with specific tag + --jobid-tag=tag checkout jobid modules with specific tag + +Dependencies: + --with-EXTERNAL=PATH where to look for an external. Required externals + (not all for all modules) are: + @ext + --with-JAR=JAR where to look for jars. Required jars are: + @myjars + Summary of what will be used is always printed + +}; + +} diff --git a/org.glite.lb.logger/doc/glite-lb-interlogd.8 b/org.glite.lb.logger/doc/glite-lb-interlogd.8 index 20732a0..68ae914 100644 --- a/org.glite.lb.logger/doc/glite-lb-interlogd.8 +++ b/org.glite.lb.logger/doc/glite-lb-interlogd.8 @@ -1,4 +1,4 @@ -.TH EDG-WL-INTERLOGD 8 "May 2003" "EU DataGrid Project" "Logging&Bookkeeping" +.TH GLITE-LB-INTERLOGD 8 "April 2008" "EU EGEE Project" "Logging&Bookkeeping" .SH NAME glite-lb-interlogd - interlogger daemon @@ -68,6 +68,10 @@ environment variable. Don't run as daemon (do not fork and put itself into background). .TP +.BI \-i " FILE" "\fR,\fP --pidfile " FILE +Store process id into this file rather than default /var/glite/glite-lb-[notif]-interlogd.pid + +.TP .BI \-f " PREFIX" "\fR,\fP --file-prefix " PREFIX .I PREFIX is path prefix of the event files. @@ -120,6 +124,10 @@ Be lazy when closing connections to servers (default, .I TIMEOUT\fR ==0 means turn lazy off). +.TP +.BI "-h\fR,\fP --help" +Print help and exit. + .\".SH USAGE .\" Add any additional description here @@ -130,10 +138,10 @@ Be lazy when closing connections to servers (default, .I /tmp/interlogger.sock Default name of local socket. .TP -.I /tmp/dglogd.log* +.I /var/glite/log/dglogd.log* Default location of event files. -.I /tmp/dglogd.log*.ctl +.I /var/glite/log/dglogd.log*.ctl Interlogger's control files keeping the information on status of the corresponding event file wrt. delivery to the target server. @@ -166,10 +174,10 @@ If is set, it is used to locate proxy certificate file. .SH REPORTING BUGS -Please, report all bugs to EU DataGrid Bug Tracking System located at http://marianne.in2p3.fr/datagrid/bugzilla +Please, report all bugs to EU EGEE Bug Tracking System located at https://savannah.cern.ch .SH SEE ALSO .B te-lb-bkserverd\fR(8),\fP glite-lb-logd\fR(8),\fP glite-lb-logevent\fR(1),\fP .SH AUTHOR -EU DataGrid Work Package 1, CESNET group. +EU EGEE, JRA1. diff --git a/org.glite.lb.logger/doc/glite-lb-logd.8 b/org.glite.lb.logger/doc/glite-lb-logd.8 index c9bf108..2a04be6 100644 --- a/org.glite.lb.logger/doc/glite-lb-logd.8 +++ b/org.glite.lb.logger/doc/glite-lb-logd.8 @@ -1,4 +1,4 @@ -.TH EDG-WL-LOGD 8 "May 2003" "EU DataGrid Project" "Logging&Bookkeeping" +.TH GLITE-LB-LOGD 8 "April 2008" "EU EGEE Project" "Logging&Bookkeeping" .SH NAME glite-lb-logd - local logger daemon @@ -82,10 +82,20 @@ Send the messages to interlogger through the UNIX socket The value has to be same as used in the cooperating glite-lb-interlogd. .TP +.BI \-i " FILE" "\fR,\fP --pidfile " FILE +Store pid into +.I FILE\fR.\fP +Defaults to /var/glite/glite-lb-logd.pid. + +.TP .B "-V\fR,\fP --version" Print version and exit. .TP +.B "-h\fR,\fP --help" +Print help and exit. + +.TP .B --noAuth Don't require valid X509 credentials to run the daemon. Used for debugging only. @@ -111,7 +121,7 @@ Dangerous, for debugging only! Don't use at all. Default name of local socket. .TP -.I /tmp/dglogd.log* +.I /var/glite/log/dglogd.log* Default location of the event storage files. .TP No configuration files needed. @@ -153,10 +163,10 @@ Decrease verbosity of the program. .SH REPORTING BUGS -Please, report all bugs to DataGrid Bug Tracking System located at http://marianne.in2p3.fr/datagrid/bugzilla +Please, report all bugs to EGEE Bug Tracking System located at https://savannah.cern.ch .SH SEE ALSO .B glite-lb-bkserverd\fR(8),\fP glite-lb-interlogd\fR(8),\fP glite-lb-logevent\fR(1),\fP .SH AUTHOR -EU DataGrid Work Package 1, CESNET group. +EU EGEE, JRA1. diff --git a/org.glite.lb.logger/interface/il_error.h b/org.glite.lb.logger/interface/il_error.h new file mode 100644 index 0000000..f150212 --- /dev/null +++ b/org.glite.lb.logger/interface/il_error.h @@ -0,0 +1,49 @@ +#ifndef IL_ERROR_H +#define IL_ERROR_H + +#ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#include + +enum err_code_maj { /* minor = */ + IL_OK, /* 0 */ + IL_SYS, /* errno */ + IL_NOMEM, /* ENOMEM */ + IL_PROTO, /* LB_* */ + IL_LBAPI, /* dgLBErrCode */ + IL_DGGSS, /* EDG_WLL_GSS_* */ + IL_HOST, /* h_errno */ + IL_DL /* dlerror */ +}; + +struct error_inf { + int code_maj; + long code_min; + char *msg; +}; + +int init_errors(); +int set_error(int, long, char *); +int clear_error(); +int error_get_maj(); +long error_get_min(); +char *error_get_msg(); + +#endif diff --git a/org.glite.lb.logger/src/interlogd.h b/org.glite.lb.logger/interface/interlogd.h similarity index 67% rename from org.glite.lb.logger/src/interlogd.h rename to org.glite.lb.logger/interface/interlogd.h index cf4d634..bdf0146 100644 --- a/org.glite.lb.logger/src/interlogd.h +++ b/org.glite.lb.logger/interface/interlogd.h @@ -2,10 +2,32 @@ #define INTERLOGGER_P_H #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#ifdef __cplusplus +extern "C" { +#endif #include "il_error.h" #include "glite/security/glite_gss.h" #include "glite/lb/il_msg.h" +#include "glite/lbu/log.h" #include #include @@ -42,6 +64,7 @@ #define IL_EVENT_GET_UNIQUE(a) edg_wll_NotifIdGetUnique((a)) #define IL_EVENT_ID_FREE(a) edg_wll_NotifIdFree((a)) #define IL_EVENT_ID_PARSE(a,b) edg_wll_NotifIdParse((a),(b)) +#define IL_LOG_CATEGORY LOG_CATEGORY_LB_ILNOTIF #else @@ -52,6 +75,7 @@ #define IL_EVENT_GET_UNIQUE(a) edg_wlc_JobIdGetUnique((a)) #define IL_EVENT_ID_FREE(a) edg_wlc_JobIdFree((a)) #define IL_EVENT_ID_PARSE(a,b) edg_wlc_JobIdParse((a),(b)) +#define IL_LOG_CATEGORY LOG_CATEGORY_LB_IL #endif @@ -60,11 +84,23 @@ // #define TIMEOUT 5 extern int TIMEOUT; -#define INPUT_TIMEOUT (60) +#ifdef LB_PERF +#define INPUT_TIMEOUT (1) +#define EXIT_TIMEOUT (20) +#else +#define INPUT_TIMEOUT (5) #define EXIT_TIMEOUT (1*60) +#endif +#define RECOVER_TIMEOUT (60) + +typedef struct cred_handle { + edg_wll_GssCred creds; + int counter; +} cred_handle_t; +extern cred_handle_t *cred_handle; -extern gss_cred_id_t cred_handle; extern pthread_mutex_t cred_handle_lock; +extern pthread_key_t cred_handle_key; extern char *cert_file; extern char *key_file; extern char *CAcert_dir; @@ -72,6 +108,10 @@ extern int bs_only; extern int killflg; extern int lazy_close; extern int default_close_timeout; +extern size_t max_store_size; +extern size_t queue_size_high; +extern size_t queue_size_low; +extern int parallel; #ifdef LB_PERF extern int nosend, nosync, norecover, noparse; #ifdef PERF_EVENTS_INLINE @@ -84,7 +124,30 @@ extern char *event_source; extern pthread_mutex_t flush_lock; extern pthread_cond_t flush_cond; #endif - + +typedef struct { + /* il_octet_string_t */ + int len; + char *data; + /* http message specific */ + enum { IL_HTTP_OTHER, + IL_HTTP_GET, + IL_HTTP_POST, + IL_HTTP_REPLY + } msg_type; + int reply_code; + char *reply_string; + size_t content_length; + char *host; +} il_http_message_t; + +/* this struct can be passed instead of il_octet_string as parameter */ +typedef union { + il_octet_string_t bin_msg; + il_http_message_t http_msg; +} il_message_t; + + struct event_store { char *event_file_name; /* file with events from local logger */ char *control_file_name; /* file with control information */ @@ -93,8 +156,11 @@ struct event_store { long last_committed_ls; /* -"- LS */ long offset; /* expected file position of next event */ time_t last_modified; /* time of the last file modification */ - int recovering; /* flag for recovery mode */ - pthread_rwlock_t update_lock; /* lock to prevent simultaneous updates */ + int generation; /* cleanup counter, scopes the offset */ + long long rotate_index; /* rotation counter */ + struct event_store_list *le; /* points back to the list */ + pthread_rwlock_t commit_lock; /* lock to prevent simultaneous updates to last_committed_* */ + pthread_rwlock_t offset_lock; /* lock to prevent simultaneous updates offset */ pthread_rwlock_t use_lock; /* lock to prevent struct deallocation */ #if defined(IL_NOTIFICATIONS) char *dest; /* host:port destination */ @@ -109,6 +175,7 @@ struct server_msg { int len; int ev_len; struct event_store *es; /* cache for corresponding event store */ + int generation; /* event store genereation */ long receipt_to; /* receiver (long local-logger id - LLLID) of delivery confirmation (for priority messages) */ #if defined(IL_NOTIFICATIONS) char *dest_name; @@ -123,6 +190,7 @@ struct event_queue { edg_wll_GssConnection gss; /* GSS connection */ char *dest_name; int dest_port; + char *dest; int timeout; /* queue timeout */ struct event_queue_msg *tail; /* last message in the queue */ struct event_queue_msg *head; /* first message in the queue */ @@ -144,8 +212,25 @@ struct event_queue { int times_empty; /* number of times the queue was emptied */ int max_len; /* max queue length */ int cur_len; /* current length */ + int throttling; /* event insertion suspend flag */ + int first_event_sent; /* connection can be preempted by server */ + /* delivery methods */ + int (*event_queue_connect)(struct event_queue *); + int (*event_queue_send)(struct event_queue *); + int (*event_queue_close)(struct event_queue *); + void *plugin_data; /* opaque data used by output plugins */ +}; + +struct il_output_plugin { + int (*event_queue_connect)(struct event_queue *); + int (*event_queue_send)(struct event_queue *); + int (*event_queue_close)(struct event_queue *); + int (*plugin_init)(char *); + int (*plugin_supports_scheme)(const char *); }; +/* credential destructor */ +void cred_handle_destroy(void *); /* server msg methods */ struct server_msg *server_msg_create(il_octet_string_t *, long); @@ -157,7 +242,7 @@ int server_msg_is_priority(struct server_msg *); int server_msg_free(struct server_msg *); /* general event queue methods */ -struct event_queue *event_queue_create(char *); +struct event_queue *event_queue_create(char *, struct il_output_plugin *); int event_queue_free(struct event_queue *); int event_queue_empty(struct event_queue *); int event_queue_insert(struct event_queue *, struct server_msg *); @@ -166,7 +251,7 @@ int event_queue_remove(struct event_queue *); int event_queue_enqueue(struct event_queue *, char *); /* helper */ int enqueue_msg(struct event_queue *, struct server_msg *); -int event_queue_move_events(struct event_queue *, struct event_queue *, int (*)(struct server_msg *, void *), void *); +int event_queue_move_events(struct event_queue *, struct event_queue *, int (*)(struct server_msg *, void *), void *); /* protocol event queue methods */ int event_queue_connect(struct event_queue *); @@ -189,7 +274,7 @@ int event_queue_cond_unlock(struct event_queue *); /* input queue */ int input_queue_attach(); void input_queue_detach(); -int input_queue_get(il_octet_string_t *, long *, int); +int input_queue_get(il_octet_string_t **, long *, int); /* queue management functions */ int queue_list_init(char *); @@ -209,18 +294,33 @@ int notifid_map_set_expiration(const char *, time_t); int event_store_init(char *); int event_store_cleanup(); int event_store_recover_all(void); -struct event_store *event_store_find(char *); +struct event_store *event_store_find(char *, const char *); int event_store_sync(struct event_store *, long); int event_store_next(struct event_store *, long, int); -int event_store_commit(struct event_store *, int, int); +int event_store_commit(struct event_store *, int, int, int); int event_store_recover(struct event_store *); int event_store_release(struct event_store *); /* int event_store_remove(struct event_store *); */ +#if defined(IL_WS) +/* http functions */ +int parse_header(const char *, il_http_message_t *); +int receive_http(void *, int (*)(void *, char *, const int), il_http_message_t *); +#endif + +/* plugin functions */ +int plugin_mgr_init(const char *, char *); +struct il_output_plugin *plugin_get(const char *); + /* master main loop */ int loop(); +void do_handle_signal(); /* recover thread */ void *recover_thread(void*); +#ifdef __cplusplus +} +#endif + #endif diff --git a/org.glite.lb.logger/project/ChangeLog b/org.glite.lb.logger/project/ChangeLog index 2b299cd..a4bee80 100644 --- a/org.glite.lb.logger/project/ChangeLog +++ b/org.glite.lb.logger/project/ChangeLog @@ -22,16 +22,57 @@ - fixed sending empty events - do not syslog "error reading server reply" unnecessarily -1.4.11-1 -- Support chconfig in startup scripts (#27055) -- Proper kill signal handling (#36470) +2.0.0-1 +- LB 2.0 release -1.4.11-2 -- L&B server export to MSG +2.0.0-2 +- fixed configure to work in etics -1.4.11-3 -- Module Repacked +2.0.0-3 +- Fixed typos in the Makefile -1.4.11-4 -- Module rebuilt +2.0.0-4 +- configure script update (globus flavors added to configure call) + +2.0.1-1 +- (from 1.4.11-1) Support chconfig in startup scripts (#27055) +- (from 1.4.11-1) Proper kill signal handling (#36470) + +2.0.2-1 +- implemented multi-file event store, avoiding ever-growing files + in the case of heavy traffic notifications + +2.0.3-1 +- Fixed handling messages with destination not set +- Additional logging output + +2.0.4-1 +- Man page update + +2.0.4-2 +- install libraries into $libdir + +2.1.0-1 +- Compliance with the Common Logging Format +- Fixed startup script (Savannah Bug #29081) +- Addressed memory consumption (Savannah Bug #48164) +- Improved portability +- IPv6 fixes +- SIGHUP handling +- Warnings on expected server connection disconnections removed +- Database and permission errors from server handled by wait&retry + +2.1.1-1 +- Startup script update + +2.1.2-1 +- Startup script update: log4c config file name hardcoded to 'log4crc' + +2.1.3-1 +- Configuration files moved from /etc to /etc/lb +- LCAS logging temporarily disabled + +2.1.4-1 +- Introduce a separate logging category for notification interlogger +- Fix problem with dropping unused notoifications diff --git a/org.glite.lb.logger/project/package.description b/org.glite.lb.logger/project/package.description new file mode 100644 index 0000000..cd0621b --- /dev/null +++ b/org.glite.lb.logger/project/package.description @@ -0,0 +1 @@ +glite-lb-logger is the gLite LB local-logger and inter-logger. This package contains the local-logger (glite-lb-logd), inter-logger (glite-lb-interlogd) and notification inter-logger (glite-lb-notif-interlogd) daemons. diff --git a/org.glite.lb.logger/project/package.summary b/org.glite.lb.logger/project/package.summary new file mode 100644 index 0000000..089b630 --- /dev/null +++ b/org.glite.lb.logger/project/package.summary @@ -0,0 +1 @@ +gLite Logging and Bookkeeping local-logger and inter-logger diff --git a/org.glite.lb.logger/project/version.properties b/org.glite.lb.logger/project/version.properties index 8a32c13..6e8c734 100644 --- a/org.glite.lb.logger/project/version.properties +++ b/org.glite.lb.logger/project/version.properties @@ -1,3 +1,3 @@ # $Header$ -module.version=1.4.11 -module.age=4 +module.version=2.1.4 +module.age=1 diff --git a/org.glite.lb.logger/src-nt/Connection.H b/org.glite.lb.logger/src-nt/Connection.H index 692c019..0690174 100644 --- a/org.glite.lb.logger/src-nt/Connection.H +++ b/org.glite.lb.logger/src-nt/Connection.H @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #ifndef _CONNECTION_H #define _CONNECTION_H @@ -8,6 +25,8 @@ public: public: virtual Connection *newConnection(int fd) const = 0; virtual Connection *accept(int fd) const = 0; + + virtual ~Factory() {} }; class Endpoint { diff --git a/org.glite.lb.logger/src-nt/Connection.cpp b/org.glite.lb.logger/src-nt/Connection.cpp new file mode 100644 index 0000000..2d0938d --- /dev/null +++ b/org.glite.lb.logger/src-nt/Connection.cpp @@ -0,0 +1,21 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "Connection.H" + +Connection::Factory::~Factory() { +} diff --git a/org.glite.lb.logger/src-nt/EventManager.H b/org.glite.lb.logger/src-nt/EventManager.H index 1fa4cab..840343b 100644 --- a/org.glite.lb.logger/src-nt/EventManager.H +++ b/org.glite.lb.logger/src-nt/EventManager.H @@ -1,58 +1,108 @@ -#ifndef _EVENT_MANAGER_H -#define _EVENT_MANAGER_H +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -class EventManager { -public: - // type for return code of event handler - typedef enum { - NOT_HANDLED, // the event was not handled at all - HANDLED, // the event was handled succesfully - HANDLED_FINAL // the event was handled, - // no other handlers should be called - } eventstatus_t; + http://www.apache.org/licenses/LICENSE-2.0 - - static EventManager* getEventManager() { return &theEventManager; }; +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ - class Event { - public: - }; +#ifndef _EVENT_MANAGER_H +#define _EVENT_MANAGER_H - template - class EventHandler { - public: +#include - virtual eventstatus_t handleEvent(T *&e); - eventstatus_t dispatchEvent(Event *&e) { - T *event = dynamic_cast(e); - - if(event) - return(handleEvent(event)); - else - return(NOT_HANDLED); - } - }; +// interface +/** + * Base class of event hierarchy. + */ +class Event { +public: + virtual ~Event() {} +}; - void postEvent(Event &); - template - bool registerHandler(EventHandler *); +/** + * Base class for event handler address. + */ +class EventHandler { +public: + // constants for event handler return codes + static const int NOT_HANDLED = 0; + static const int HANDLED = 1; + static const int HANDLED_FINAL = 2; + static const int HANDLED_NEW = 3; + + virtual int handleEvent(Event* &e) { return NOT_HANDLED; } + virtual ~EventHandler() {} +}; - template - bool registerHandlerFirst(EventHandler *); +/** + * Holds addres of event handler, ie. pointer to member function of T + * that takes E* & as an argument. + */ +template +class TypedEventHandler: public EventHandler { +public: + typedef int (T::*handlerType)(E* &); + + TypedEventHandler(T *handler, handlerType method) + : m_handler(handler), m_handleEvent(method) { + } + + virtual int handleEvent(Event* &e) { + E *ne = dynamic_cast(e); + int result = EventHandler::NOT_HANDLED; + if(ne) { + result = (m_handler->*m_handleEvent)(ne); + if((result == EventHandler::HANDLED_NEW) && + !(ne == e)) { + delete e; + e = ne; + } + } + return result; + } + private: - - // the event manager - static EventManager theEventManager; + T *m_handler; + handlerType m_handleEvent; +}; + - // private default constructor for singleton instance - EventManager() - {}; +class EventManager { +public: + + int postEvent(Event* &event); + + template + EventHandler& registerHandler(T *handler, int (T::*method)(E* &)) { + EventHandler *h = new TypedEventHandler(handler, method); + addHandler(h); + return *h; + } + + template + EventHandler& registerHandler(T *handler) { + return registerHandler(handler, &T::handleEvent); + } + +private: + std::list handlers; + void addHandler(EventHandler*); + void removeHandler(EventHandler *); }; diff --git a/org.glite.lb.logger/src-nt/EventManager.cpp b/org.glite.lb.logger/src-nt/EventManager.cpp new file mode 100644 index 0000000..16b577b --- /dev/null +++ b/org.glite.lb.logger/src-nt/EventManager.cpp @@ -0,0 +1,40 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "EventManager.H" + +int +EventManager::postEvent(Event* &e) +{ + for(std::list::iterator i = handlers.begin(); + i != handlers.end(); + i++) { + (*i)->handleEvent(e); + } + return 0; +} + +void +EventManager::addHandler(EventHandler *handler) +{ + handlers.push_back(handler); +} + +void +EventManager::removeHandler(EventHandler *handler) +{ +} diff --git a/org.glite.lb.logger/src-nt/Exception.H b/org.glite.lb.logger/src-nt/Exception.H index 0fbac3e..678e258 100644 --- a/org.glite.lb.logger/src-nt/Exception.H +++ b/org.glite.lb.logger/src-nt/Exception.H @@ -1,7 +1,30 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #ifndef _EXCEPTION_H #define _EXCEPTION_H class Exception { }; +class FatalException { +}; + + +#define E_ASSERT(a) if(!(a)) { throw new FatalException; } + #endif diff --git a/org.glite.lb.logger/src-nt/HTTPTransport.H b/org.glite.lb.logger/src-nt/HTTPTransport.H index 417deea..f56d50e 100644 --- a/org.glite.lb.logger/src-nt/HTTPTransport.H +++ b/org.glite.lb.logger/src-nt/HTTPTransport.H @@ -1,8 +1,26 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #ifndef _HTTP_TRANSPORT_H #define _HTTP_TRANSPORT_H #include "ThreadPool.H" #include "Transport.H" +#include "Singleton.H" #include @@ -10,20 +28,18 @@ class HTTPTransport: public Transport { public: - class Factory: public Transport::Factory { + + // factory class + class Factory: public Transport::Factory, + public Singleton { public: - virtual Transport *newTransport(Connection *conn) const { - if(conn) - return(new HTTPTransport(conn)); - else - return NULL; + virtual Transport *newTransport() const { + return(new HTTPTransport()); } }; - static Factory theFactory; - - HTTPTransport(Connection *conn) - : Transport(conn), + HTTPTransport() + : Transport(), state(NONE), request(), headers(), body(NULL), pos(NULL), content_length(0) @@ -31,12 +47,9 @@ public: virtual ~HTTPTransport(); - -protected: - // from ThreadPool::WorkDescription - virtual void onReady(); - virtual void onTimeout(); - virtual void onError(); + virtual int receive(Connection *conn, Message* &msg); + virtual int send(Connection *conn, Message* msg); + virtual void reset(); private: enum { NONE, @@ -51,6 +64,7 @@ private: unsigned int content_length; int parseHeader(const char *s, unsigned int len); + void serializeHeaders(Message *msg); }; diff --git a/org.glite.lb.logger/src-nt/HTTPTransport.cpp b/org.glite.lb.logger/src-nt/HTTPTransport.cpp index 8f495c3..ca3d378 100644 --- a/org.glite.lb.logger/src-nt/HTTPTransport.cpp +++ b/org.glite.lb.logger/src-nt/HTTPTransport.cpp @@ -1,21 +1,39 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include "HTTPTransport.H" #include "Exception.H" +#include "EventManager.H" #include #include -HTTPTransport::Factory HTTPTransport::theFactory; - - HTTPTransport::~HTTPTransport() { if(body) free(body); } -void -HTTPTransport::onReady() +// read what is available and parse what can be parsed +// returns the result of read operation of the underlying connection, +// ie. the number of bytes read or error code +int +HTTPTransport::receive(Connection *conn, Message* &msg) { int len; @@ -29,10 +47,12 @@ HTTPTransport::onReady() len = conn->read(pos, sizeof(buffer) - (pos - buffer)); if(len < 0) { // error during request - state = NONE; + // state = NONE; + return len; } else if(len == 0) { // other side closed connection - state = NONE; + // state = NONE; + return len; } else { char *cr = NULL, *p = buffer, *s = buffer; bool crlf_seen = false; @@ -114,6 +134,7 @@ HTTPTransport::onReady() } } else { // report error + // XXX - this may happen, do not handle using exceptions std::cout << "Wrong content length" << std::endl; throw new Exception(); } @@ -131,13 +152,15 @@ HTTPTransport::onReady() len = conn->read(pos, content_length - (pos - body)); if(len < 0) { // error reading - state = NONE; + // state = NONE; + return len; } else if(len == 0) { // no more data - state = NONE; + // state = NONE; + return len; } else { pos += len; - if(pos - body == content_length) { + if(pos == content_length + body) { // finished reading state = NONE; } @@ -146,40 +169,104 @@ HTTPTransport::onReady() } if(state != NONE) - ThreadPool::instance()->queueWorkRead(this); + msg = NULL; else { - std::cout << request << std::endl << headers << std::endl; - std::cout.write(body, content_length); - std::cout.flush(); + // we have a new message + // XXX - or we have an error, must handle it + msg = new Message(body, content_length); + msg->setProperties( } - + return len; } -void -HTTPTransport::onTimeout() +int +HTTPTransport::parseHeader(const char *s, unsigned int len) { + char *p; + + p = (char*)memccpy((void*)s, (void*)s, ':', len); + + if(!strncasecmp(s, "Content-Length", 14)) { + content_length = p ? atoi(p) : 0 ; + } + return(0); } -void -HTTPTransport::onError() +int +HTTPTransport::send(Connection *conn, Message* msg) { + int len; + switch(state) { + case NONE: + state = IN_REQUEST; + request = "POST " + msg->path() + "HTTP/1.1\r\n"; + pos = request.c_str(); + content_length = msg->getContent(body); + + case IN_REQUEST: + len = conn->send(pos, request.length() - pos + request.c_str()); + if(len < 0) { + return len; + } + pos += len; + if(request.c_str() + request.length() == pos) { + state = IN_HEADERS; + prepareHeaders(msg); + pos = headers.c_str(); + } else { + break; + } + + case IN_HEADERS: + len = conn->send(pos, headers.length() - pos + headers.c_str()); + if(len < 0) { + return len; + } + pos += len; + if(headers.c_str() + headers.length() == pos) { + state = IN_BODY; + pos = body; + } else { + break; + } + + case IN_BODY: + len = conn->send(pos, body, content_length - pos + body); + if(len < 0) { + return len; + } + pos += len; + if(body + content_length == pos) { + state = NONE; + return 0; + } + break; + + default: + } + return len; } -int -HTTPTransport::parseHeader(const char *s, unsigned int len) +void +HTTPTransport::reset() { - char *p; - - std::cout << "header: "; - std::cout.write(s, len); - std::cout << std::endl; - std::cout.flush(); - if(!strncasecmp(s, "Content-Length", 14)) { - p = (char*)memccpy((void*)s, (void*)s, ':', len); - content_length = p ? atoi(p) : 0 ; + state = NONE; + request.clear(); + headers.clear(); + if(body) { + free(body); + body = NULL; } - return(0); + content_length = 0; + pos = buffer; +} + + +void +HTTPTransport::serializeHeaders(Message *msg); +{ + for(Properties::iterator i = msg-> } diff --git a/org.glite.lb.logger/src-nt/InputChannel.H b/org.glite.lb.logger/src-nt/InputChannel.H new file mode 100644 index 0000000..5f6434f --- /dev/null +++ b/org.glite.lb.logger/src-nt/InputChannel.H @@ -0,0 +1,46 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef _INPUT_CHANNEL_H_ +#define _INPUT_CHANNEL_H_ + +#include "ThreadPool.H" +#include "Connection.H" +#include "Transport.H" + +class InputChannel + : public ThreadPool::WorkDescription { +public: + + InputChannel(Connection *conn, Transport *trans) + : ThreadPool::WorkDescription(conn->getFD()), + m_connection(conn), m_transport(trans) + {} + + void start(); + +protected: + virtual void onReady(); + virtual void onTimeout(); + virtual void onError(); + +private: + Connection *m_connection; + Transport *m_transport; +}; + +#endif diff --git a/org.glite.lb.logger/src-nt/InputChannel.cpp b/org.glite.lb.logger/src-nt/InputChannel.cpp new file mode 100644 index 0000000..99d5999 --- /dev/null +++ b/org.glite.lb.logger/src-nt/InputChannel.cpp @@ -0,0 +1,54 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "InputChannel.H" +#include "ThreadPool.H" +#include "EventManager.H" + +extern EventManager theEventManager; + +void +InputChannel::start() +{ + ThreadPool::instance()->queueWorkRead(this); +} + +void +InputChannel::onReady() +{ + Transport::Message *msg = NULL; + int ret = m_transport->receive(m_connection, msg); + if(ret <= 0) { + // no new data read + } else if(msg) { + // we have a new message + + } else { + // still need more data + ThreadPool::instance()->queueWorkRead(this); + } +} + +void +InputChannel::onTimeout() +{ +} + +void +InputChannel::onError() +{ +} diff --git a/org.glite.lb.logger/src-nt/Makefile b/org.glite.lb.logger/src-nt/Makefile index 2ff9420..8ebe707 100644 --- a/org.glite.lb.logger/src-nt/Makefile +++ b/org.glite.lb.logger/src-nt/Makefile @@ -10,9 +10,9 @@ LINK = libtool --mode=link g++ $(LDFLAGS) THREAD_LIB = -lpthread -CPPUNIT_ROOT = /afs/ruk.cuni.cz/home/michal/egee/repository/externals/cppunit/1.10.2/slc3_ia32_gcc323 -CPPUNIT_LIB = -L$(CPPUNIT_ROOT)/lib -lcppunit -ldl -CPPUNIT_INCLUDE = -I$(CPPUNIT_ROOT)/include +CPPUNIT_ROOT = +CPPUNIT_LIB = -lcppunit -ldl +CPPUNIT_INCLUDE = TEST_OBJS= \ test/ThreadPoolTest.o \ @@ -21,13 +21,24 @@ TEST_OBJS= \ test/SingletonTest.o \ test/test_main.o -plain: SocketInput.o PlainConnection.o HTTPTransport.o ThreadPool.o main.o +OBJS = \ + PluginManager.o \ + SocketInput.o \ + Connection.o \ + PlainConnection.o \ + Transport.o \ + HTTPTransport.o \ + ThreadPool.o \ + EventManager.o \ + InputChannel.cpp + +plain: main.o $(OBJS) $(LINK) -o $@ $+ $(THREAD_LIB) utest: ThreadPool.o PluginManager.o EventManager.o $(TEST_OBJS) $(LINK) -o $@ $+ $(CPPUNIT_LIB) $(THREAD_LIB) -stest: test/SingletonTest.o test/test_main.o +stest: EventManager.o test/EventManagerTest.o test/test_main.o $(LINK) -o $@ $+ $(CPPUNIT_LIB) $(THREAD_LIB) $(TEST_OBJS): %.o: %.cpp diff --git a/org.glite.lb.logger/src-nt/Message.H b/org.glite.lb.logger/src-nt/Message.H new file mode 100644 index 0000000..9f6fcc4 --- /dev/null +++ b/org.glite.lb.logger/src-nt/Message.H @@ -0,0 +1,83 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef _MESSAGE_H_ +#define _MESSAGE_H + +#include "Properties.H" +#include "MessageStore.H" + +#include + +class Message: public MessageStore::Storable { +public: + + /** class that holds message state + * + */ + class State : public MessageStore::Storable { + public: + + /** Get size needed for storage (from Storable). + */ + virtual int getStorageSize() const; + + /** Save State (from Storable) + */ + virtual int save(void* data, int len) const; + + /** Load State (from Storable) + */ + virtual int load(void* data, int len); + }; + + + Message(); + + Message(void * data, unsigned int length) + : m_length(length), + m_data(data) + {} + + + int getContent(void* &data) const + { data = m_data; return m_length; } + + int getContentLength() const + { return m_length; } + + std::string getProperty(const std::string &name, std::string &val) + { return m_properties.getProperty(name); } + + void setProperty(const std::string &name, std::string &val) + { m_properties.setProperty(name, val); } + + Properties& getProperties() + { return m_properties; } + + void setProperties(Properties &) + {} + +private: + MessageStore::ID m_id; + unsigned int m_length; + void * m_data; + Properties m_properties; +}; + + +#endif diff --git a/org.glite.lb.logger/src-nt/MessageStore.H b/org.glite.lb.logger/src-nt/MessageStore.H new file mode 100644 index 0000000..7e47718 --- /dev/null +++ b/org.glite.lb.logger/src-nt/MessageStore.H @@ -0,0 +1,101 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef _MESSAGE_STORE_H_ +#define _MESSAGE_STORE_H_ + +#include + +/** Permanent storage for messages and their states. + */ + +class MessageStore { +public: + + /** Base class for everything that can be stored here. + */ + class Storable { + public: + /** Get size needed for object storage. + */ + virtual int getStorageSize() const = 0; + + /** Save state of object into binary data. + */ + virtual int save(void* data, int len) const = 0; + + /** Load state of object from binary data. + */ + virtual int load(void* data, int len) = 0; + + virtual ~Storable() {} + }; + + + /** Class that uniquely identifies stored content. + */ + class ID: public Storable { + public: + /** Default constructor. + * + * Creates new unique ID. + */ + ID(); + + /** Copy constructor. + */ + ID(const ID& src); + + /** Destructor. + */ + ~ID() {}; + + /** Assignment operator. + */ + ID& operator=(const ID& src); + + /** Return the string suitable for printing. + */ + std::string toString() const; + + /** Comparison operator + */ + int operator==(const ID& second); + + /** Get size needed for storage (from Storable). + */ + virtual int getStorageSize() const; + + /** Save ID (from Storable) + */ + virtual int save(void* data, int len) const; + + /** Load ID (from Storable) + */ + virtual int load(void* data, int len); + + protected: + unsigned long long getID() {return id;} + + private: + static pthread_mutex_t counterLock; + static unsigned counter; + unsigned long long id; + }; +}; + +#endif diff --git a/org.glite.lb.logger/src-nt/MessageStore.cpp b/org.glite.lb.logger/src-nt/MessageStore.cpp new file mode 100644 index 0000000..e90fa44 --- /dev/null +++ b/org.glite.lb.logger/src-nt/MessageStore.cpp @@ -0,0 +1,41 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include +#include + +#include "MessageStore.H" + +pthread_mutex_t MessageStore::ID::counterLock = PTHREAD_MUTEX_INITIALIZER; +unsigned MessageStore::ID::counter = 0; + +MessageStore::ID::ID(){ + time_t t; + time(&t); + pthread_mutex_lock(&counterLock); + counter++; + id = ((unsigned long long) counter << 32) + t; + pthread_mutex_unlock(&counterLock); +} + +std::string MessageStore::ID::toString() const{ + std::ostringstream oss; + oss << id; + return oss.str(); +} + diff --git a/org.glite.lb.logger/src-nt/PlainConnection.H b/org.glite.lb.logger/src-nt/PlainConnection.H index 3551286..63fba33 100644 --- a/org.glite.lb.logger/src-nt/PlainConnection.H +++ b/org.glite.lb.logger/src-nt/PlainConnection.H @@ -1,23 +1,41 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #ifndef _PLAIN_CONNECTION_H #define _PLAIN_CONNECTION_H #include "Connection.H" - +#include "Singleton.H" class PlainConnection: public Connection { public: - class Factory: public Connection::Factory { + class Factory: public Connection::Factory, + public Singleton { public: virtual Connection *newConnection(int fd) const { return new PlainConnection(fd); } virtual Connection *accept(int fd) const; - }; - static Factory theFactory; + virtual ~Factory() {} + }; PlainConnection(int a_fd): Connection(a_fd) {} diff --git a/org.glite.lb.logger/src-nt/PlainConnection.cpp b/org.glite.lb.logger/src-nt/PlainConnection.cpp index 156ec6e..79fe74b 100644 --- a/org.glite.lb.logger/src-nt/PlainConnection.cpp +++ b/org.glite.lb.logger/src-nt/PlainConnection.cpp @@ -1,12 +1,26 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include "PlainConnection.H" #include "ThreadPool.H" #include #include -PlainConnection::Factory PlainConnection::theFactory; - - PlainConnection::~PlainConnection() { } @@ -35,4 +49,8 @@ PlainConnection::read(char *buf, unsigned int len) int PlainConnection::write(char *buf, unsigned int len) { + int ret; + + ret = ::write(fd, buf, len); + return ret; } diff --git a/org.glite.lb.logger/src-nt/PluginManager.H b/org.glite.lb.logger/src-nt/PluginManager.H index 7b5aa74..98c0a52 100644 --- a/org.glite.lb.logger/src-nt/PluginManager.H +++ b/org.glite.lb.logger/src-nt/PluginManager.H @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #ifndef _PLUGIN_MANAGER_H #define _PLUGIN_MANAGER_H @@ -21,6 +38,8 @@ public: virtual bool initialize() = 0; virtual bool cleanup () = 0; + + virtual ~Plugin(); }; // add plugin with given name to the list of registered plugins diff --git a/org.glite.lb.logger/src-nt/PluginManager.cpp b/org.glite.lb.logger/src-nt/PluginManager.cpp index df53043..e294d61 100644 --- a/org.glite.lb.logger/src-nt/PluginManager.cpp +++ b/org.glite.lb.logger/src-nt/PluginManager.cpp @@ -1,3 +1,23 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include "PluginManager.H" +PluginManager::Plugin::~Plugin() { +} + diff --git a/org.glite.lb.logger/src-nt/Properties.H b/org.glite.lb.logger/src-nt/Properties.H new file mode 100644 index 0000000..662b636 --- /dev/null +++ b/org.glite.lb.logger/src-nt/Properties.H @@ -0,0 +1,53 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef _PROPERTIES_H_ +#define _PROPERTIES_H_ + +#include +#include + +class Properties { +public: + + // default constructor + Properties() + : properties() + {} + + // accessors + std::string& getProperty(const std::string &key) + { return properties[key]; } + + void setProperty(const std::string &key, std::string &val) + { properties[key] = val; } + + // iterators + typedef std::map::iterator iterator; + + iterator begin() + { return properties.begin(); } + + iterator end() + { return properties.end(); } + + +private: + std::map properties; +}; + +#endif diff --git a/org.glite.lb.logger/src-nt/Singleton.H b/org.glite.lb.logger/src-nt/Singleton.H index ce03525..1dccd07 100644 --- a/org.glite.lb.logger/src-nt/Singleton.H +++ b/org.glite.lb.logger/src-nt/Singleton.H @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #ifndef _SINGLETON_H #define _SINGLETON_H diff --git a/org.glite.lb.logger/src-nt/SocketInput.H b/org.glite.lb.logger/src-nt/SocketInput.H index 0021816..db84f9b 100644 --- a/org.glite.lb.logger/src-nt/SocketInput.H +++ b/org.glite.lb.logger/src-nt/SocketInput.H @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #ifndef _SOCKET_INPUT_H #define _SOCKET_INPUT_H diff --git a/org.glite.lb.logger/src-nt/SocketInput.cpp b/org.glite.lb.logger/src-nt/SocketInput.cpp index f38cabb..e8fc966 100644 --- a/org.glite.lb.logger/src-nt/SocketInput.cpp +++ b/org.glite.lb.logger/src-nt/SocketInput.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include #include @@ -6,7 +23,8 @@ #include "ThreadPool.H" #include "SocketInput.H" - +#include "InputChannel.H" +#include "Exception.H" // create unix domain socket for input @@ -21,6 +39,7 @@ SocketInput::SocketInput(const char *path, saddr.sun_family = AF_UNIX; strcpy(saddr.sun_path, path); fd = socket(PF_UNIX, SOCK_STREAM, 0); + if(fd < 0) throw new Exception; if(connect(fd, (struct sockaddr*)&saddr, sizeof(saddr.sun_path)) < 0) { if(errno == ECONNREFUSED) { unlink(saddr.sun_path); @@ -29,9 +48,10 @@ SocketInput::SocketInput(const char *path, // another instance running // throw new Exception } - bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); - listen(fd, SOCK_QUEUE_MAX); - ThreadPool::instance()->setWorkAccept(this); + if(bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) + throw new Exception; + if(listen(fd, SOCK_QUEUE_MAX) < 0) + throw new Exception; } @@ -48,8 +68,9 @@ void SocketInput::onReady() { Connection *conn = cFactory->accept(fd); - Transport *trans = tFactory->newTransport(conn); - ThreadPool::instance()->queueWorkRead(trans); + Transport *trans = tFactory->newTransport(); + InputChannel *channel = new InputChannel(conn, trans); + channel->start(); } diff --git a/org.glite.lb.logger/src-nt/ThreadPool.H b/org.glite.lb.logger/src-nt/ThreadPool.H index b03d7e5..8e26927 100644 --- a/org.glite.lb.logger/src-nt/ThreadPool.H +++ b/org.glite.lb.logger/src-nt/ThreadPool.H @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #ifndef _THREAD_POOL_H #define _THREAD_POOL_H @@ -23,6 +40,8 @@ public: : fd(afd), event(NONE) {} + virtual ~WorkDescription(); + protected: enum Event { NONE, READY, TIMEOUT, ERROR } event; void doWork(); diff --git a/org.glite.lb.logger/src-nt/ThreadPool.cpp b/org.glite.lb.logger/src-nt/ThreadPool.cpp index 763e930..8c3aa22 100644 --- a/org.glite.lb.logger/src-nt/ThreadPool.cpp +++ b/org.glite.lb.logger/src-nt/ThreadPool.cpp @@ -1,9 +1,27 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include #include #include #include #include +#include #include @@ -69,8 +87,12 @@ ThreadPool::WaitDesc::adjustTimeout(const struct timeval &delta) } +ThreadPool::WorkDescription::~WorkDescription() { +} + + ThreadPool::ThreadPool() - : work_count(0), wait_count(0), ufds_size(0), ufds(NULL), f_exit(false) + : f_exit(false), work_count(0), wait_count(0), ufds_size(0), ufds(NULL) { pthread_mutex_init(&wait_queue_mutex, NULL); pthread_mutex_init(&work_queue_mutex, NULL); @@ -79,6 +101,9 @@ ThreadPool::ThreadPool() pthread_cond_init(&wait_queue_cond_ready, NULL); pipe(pd); ufds = static_cast(malloc(sizeof(struct pollfd))); + if(ufds == NULL) { + throw new Exception; + } ufds->fd = pd[0]; ufds->events = POLLIN; ufds_size = 1; @@ -102,6 +127,7 @@ ThreadPool::startWorkers(unsigned int n) num_workers = n; for(unsigned int i = 0; i < n; i++) { + // XXX check return pthread_create(&workers[i], NULL, ThreadPool::threadMain, NULL); } } @@ -121,11 +147,11 @@ ThreadPool::stopWorkers() void ThreadPool::postWork(WorkDescription *work_unit) { - pthread_mutex_lock(&work_queue_mutex); + E_ASSERT(pthread_mutex_lock(&work_queue_mutex) >= 0); work_queue.push_back(work_unit); work_count++; - pthread_cond_signal(&work_queue_cond_ready); - pthread_mutex_unlock(&work_queue_mutex); + E_ASSERT(pthread_cond_signal(&work_queue_cond_ready) >= 0); + E_ASSERT(pthread_mutex_unlock(&work_queue_mutex) >= 0); } @@ -133,12 +159,14 @@ inline void ThreadPool::queueWork(WaitDesc *wd) { - pthread_mutex_lock(&wait_queue_mutex); + E_ASSERT(pthread_mutex_lock(&wait_queue_mutex) >= 0); wait_queue.push_back(wd); wait_count++; - pthread_cond_signal(&wait_queue_cond_ready); - pthread_mutex_unlock(&wait_queue_mutex); - write(pd[1], "1", 1); + E_ASSERT(pthread_cond_signal(&wait_queue_cond_ready) >= 0); + E_ASSERT(pthread_mutex_unlock(&wait_queue_mutex) >= 0); + if(write(pd[1], "1", 1) != 1) { + throw new Exception; + } } @@ -211,19 +239,19 @@ ThreadPool::getWork() WorkDescription *work_unit = NULL; struct timespec timeout; - pthread_mutex_lock(&work_queue_mutex); + E_ASSERT(pthread_mutex_lock(&work_queue_mutex) >= 0); if(work_count == 0) { timeout.tv_sec = 1; timeout.tv_nsec = 0; // pthread_cond_timedwait(&work_queue_cond_ready, &work_queue_mutex, &timeout); - pthread_cond_wait(&work_queue_cond_ready, &work_queue_mutex); + E_ASSERT(pthread_cond_wait(&work_queue_cond_ready, &work_queue_mutex) == 0); } if(work_count > 0) { work_count--; work_unit = work_queue.front(); work_queue.pop_front(); } - pthread_mutex_unlock(&work_queue_mutex); + E_ASSERT(pthread_mutex_unlock(&work_queue_mutex) >= 0); return work_unit; } @@ -232,7 +260,7 @@ ThreadPool::threadCleanup(void *data) { ThreadPool *pool = ThreadPool::instance(); - pthread_mutex_unlock(&(pool->work_queue_mutex)); + E_ASSERT(pthread_mutex_unlock(&(pool->work_queue_mutex)) >= 0); } @@ -263,12 +291,12 @@ ThreadPool::removeWaitDesc(std::list::iterator &i) std::list::iterator j = i; // actually this is safe even for the first element - pthread_mutex_lock(&wait_queue_mutex); + E_ASSERT(pthread_mutex_lock(&wait_queue_mutex) >= 0); j--; wait_queue.erase(i); wait_count--; i = j; - pthread_mutex_unlock(&wait_queue_mutex); + E_ASSERT(pthread_mutex_unlock(&wait_queue_mutex) >= 0); } @@ -278,18 +306,18 @@ ThreadPool::prepareDescriptorArray() std::list::iterator theIterator; struct pollfd *p; - pthread_mutex_lock(&wait_queue_mutex); + E_ASSERT(pthread_mutex_lock(&wait_queue_mutex) >= 0); if(wait_count == 0) { - pthread_cond_wait(&wait_queue_cond_ready, &wait_queue_mutex); + E_ASSERT(pthread_cond_wait(&wait_queue_cond_ready, &wait_queue_mutex) != 0); } if(wait_count == 0) { - pthread_mutex_unlock(&wait_queue_mutex); + E_ASSERT(pthread_mutex_unlock(&wait_queue_mutex) >= 0); return; } if(ufds_size != wait_count + 1) { ufds = static_cast(realloc(ufds, (1 + wait_count) * sizeof(struct pollfd))); if(ufds == NULL) { -// throw new Exception(); + throw new Exception(); } ufds_size = wait_count + 1; } @@ -305,7 +333,7 @@ ThreadPool::prepareDescriptorArray() min_timeout = w->timeout; } } - pthread_mutex_unlock(&wait_queue_mutex); + E_ASSERT(pthread_mutex_unlock(&wait_queue_mutex) >= 0); } @@ -338,9 +366,9 @@ ThreadPool::run() } // at least we have to adjust timeouts - pthread_mutex_lock(&wait_queue_mutex); + E_ASSERT(pthread_mutex_lock(&wait_queue_mutex) >= 0); i = wait_queue.begin(); - pthread_mutex_unlock(&wait_queue_mutex); + E_ASSERT(pthread_mutex_unlock(&wait_queue_mutex) >= 0); // the wait queue mutex is unlocked inside the loop // to allow handlers to add queue new // WorkDescriptions - these are added at the @@ -352,7 +380,7 @@ ThreadPool::run() // check for consistency if(p->fd != w->get_fd()) { // mismatch, what shall we do? - abort(); + throw new Exception; } // subtract the time passed from timeout @@ -389,12 +417,13 @@ ThreadPool::run() w->timeout.tv_usec = 0; } } - pthread_mutex_lock(&wait_queue_mutex); + E_ASSERT(pthread_mutex_lock(&wait_queue_mutex) >= 0); i++; - pthread_mutex_unlock(&wait_queue_mutex); + E_ASSERT(pthread_mutex_unlock(&wait_queue_mutex) >= 0); } } else { // some nasty error + throw new Exception; } } } diff --git a/org.glite.lb.logger/src-nt/Transport.H b/org.glite.lb.logger/src-nt/Transport.H index 974b8ac..09cb777 100644 --- a/org.glite.lb.logger/src-nt/Transport.H +++ b/org.glite.lb.logger/src-nt/Transport.H @@ -1,26 +1,50 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners/ for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #ifndef _TRANSPORT_H #define _TRANSPORT_H #include "Connection.H" +#include "Message.H" - -class Transport: public ThreadPool::WorkDescription { +// Transport implements transport protocol +// - reads/writes messages using Connection interface +// - +class Transport { public: + + // class Factory { public: - virtual Transport *newTransport(Connection *conn) const = 0; + virtual Transport *newTransport() const = 0; + + virtual ~Factory() + {} }; - Transport(Connection *a_conn) - : conn(a_conn), - ThreadPool::WorkDescription(a_conn ? a_conn->getFD() : -1) + // + Transport() {} - virtual ~Transport() - { if(conn) delete conn; } - -protected: - Connection *conn; + virtual ~Transport(); + // + virtual int receive(Connection *conn, Message* &msg) = 0; + virtual int send(Connection *conn, Message* msg) = 0; + virtual void reset() = 0; }; #endif diff --git a/org.glite.lb.logger/src-nt/Transport.cpp b/org.glite.lb.logger/src-nt/Transport.cpp new file mode 100644 index 0000000..ec12ec4 --- /dev/null +++ b/org.glite.lb.logger/src-nt/Transport.cpp @@ -0,0 +1,22 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "Transport.H" + +Transport::~Transport() +{ +} diff --git a/org.glite.lb.logger/src-nt/main.cpp b/org.glite.lb.logger/src-nt/main.cpp index aa7ac45..59cb0dd 100644 --- a/org.glite.lb.logger/src-nt/main.cpp +++ b/org.glite.lb.logger/src-nt/main.cpp @@ -1,12 +1,32 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include "PluginManager.H" #include "ThreadPool.H" #include "SocketInput.H" #include "PlainConnection.H" #include "HTTPTransport.H" +#include "EventManager.H" const int num_threads = 2; const char *sock_path = "/tmp/il_sock"; +EventManager theEventManager(); + int main(int argc, char *argv[]) { SocketInput *input; @@ -16,8 +36,10 @@ int main(int argc, char *argv[]) // create unix socket with plain IO and HTTP transport input = new SocketInput(sock_path, - &PlainConnection::theFactory, - &HTTPTransport::theFactory); + PlainConnection::Factory::instance(), + HTTPTransport::Factory::instance()); + // and add the socket to pool + ThreadPool::instance()->setWorkAccept(input); // start worker threads ThreadPool::instance()->startWorkers(num_threads); diff --git a/org.glite.lb.logger/src-nt/test/EventManagerTest.cpp b/org.glite.lb.logger/src-nt/test/EventManagerTest.cpp index bedaa03..1660af7 100644 --- a/org.glite.lb.logger/src-nt/test/EventManagerTest.cpp +++ b/org.glite.lb.logger/src-nt/test/EventManagerTest.cpp @@ -1,18 +1,62 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include "EventManager.H" +class EventA : public Event { +}; + +class EventB : public Event { +}; + +class EventAA : public EventA { +}; + + class EventManagerTest: public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(EventManagerTest); + CPPUNIT_TEST(handleEventTest); CPPUNIT_TEST_SUITE_END(); public: void setUp() { + handled = false; + manager.registerHandler(this); } void tearDown() { } + void handleEventTest() { + Event *e = new EventAA(); + manager.postEvent(e); + CPPUNIT_ASSERT(handled); + } + + int handleEvent(EventA* &e) { + handled = true; + return 0; + } + +private: + EventManager manager; + bool handled; }; CPPUNIT_TEST_SUITE_REGISTRATION( EventManagerTest ); diff --git a/org.glite.lb.logger/src-nt/test/PluginManagerTest.cpp b/org.glite.lb.logger/src-nt/test/PluginManagerTest.cpp index 629bbcb..cc97d98 100644 --- a/org.glite.lb.logger/src-nt/test/PluginManagerTest.cpp +++ b/org.glite.lb.logger/src-nt/test/PluginManagerTest.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include "PluginManager.H" diff --git a/org.glite.lb.logger/src-nt/test/SingletonTest.cpp b/org.glite.lb.logger/src-nt/test/SingletonTest.cpp index 734db17..4bc1346 100644 --- a/org.glite.lb.logger/src-nt/test/SingletonTest.cpp +++ b/org.glite.lb.logger/src-nt/test/SingletonTest.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include "Singleton.H" diff --git a/org.glite.lb.logger/src-nt/test/ThreadPoolTest.cpp b/org.glite.lb.logger/src-nt/test/ThreadPoolTest.cpp index a4be75e..fd9b955 100644 --- a/org.glite.lb.logger/src-nt/test/ThreadPoolTest.cpp +++ b/org.glite.lb.logger/src-nt/test/ThreadPoolTest.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include #include @@ -134,7 +151,7 @@ public: class ThreadPoolTest: public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ThreadPoolTest ); -// CPPUNIT_TEST( testWorkQueue ); + CPPUNIT_TEST( testWorkQueue ); CPPUNIT_TEST( testPoll ); CPPUNIT_TEST( testAccept ); CPPUNIT_TEST_SUITE_END(); diff --git a/org.glite.lb.logger/src-nt/test/test_main.cpp b/org.glite.lb.logger/src-nt/test/test_main.cpp index 1ae6d6a..83c15ef 100644 --- a/org.glite.lb.logger/src-nt/test/test_main.cpp +++ b/org.glite.lb.logger/src-nt/test/test_main.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include diff --git a/org.glite.lb.logger/src/activemq_cpp_plugin.cpp b/org.glite.lb.logger/src/activemq_cpp_plugin.cpp new file mode 100644 index 0000000..5e4c762 --- /dev/null +++ b/org.glite.lb.logger/src/activemq_cpp_plugin.cpp @@ -0,0 +1,400 @@ +#ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +/* + * activemq_cpp_plugin.cpp + * + * Created on: Jan 20, 2010 + * Author: michal + */ + +#include "interlogd.h" +#include "glite/lb/events_parse.h" +#include "glite/lb/context.h" +#include "glite/lbu/escape.h" +#include "glite/lb/jobstat.h" +#include "glite/lb/xml_parse.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +class OutputPlugin : public cms::ExceptionListener { + +public: + + OutputPlugin() : session(NULL), destination(NULL), producer(NULL) {}; + + virtual void onException(const cms::CMSException &ex); + + void connect(const std::string &topic); + void send(cms::Message *msg); + void close(); + void cleanup(); + +public: + + cms::Session *session; + cms::Topic *destination; + cms::MessageProducer *producer; + + static cms::Connection *connection; + static cms::ConnectionFactory *connectionFactory; + + static const char *SCHEME; +}; + + +void +OutputPlugin::onException(const cms::CMSException &ex) +{ + this->cleanup(); +} + + +void +OutputPlugin::connect(const std::string &topic) +{ + if(this->session == NULL) { + this->session = connection->createSession(/* TODO: ackMode */); + this->destination = this->session->createTopic(topic); + this->producer = this->session->createProducer(this->destination); + } + connection->start(); + connection->setExceptionListener(this); +} + + +void +OutputPlugin::send(cms::Message *msg) +{ + if(this->producer != NULL) { + this->producer->send(this->destination, msg); + } +} + + +void +OutputPlugin::close() +{ + this->cleanup(); + connection->stop(); +} + + +void +OutputPlugin::cleanup() +{ + if(this->producer != NULL) { + delete this->producer; + this->producer = NULL; + } + if(this->destination != NULL) { + delete this->destination; + this->destination = NULL; + } + if(this->session != NULL) { + this->session->close(); + delete this->session; + this->session = NULL; + } +} + + +static +void timeval2str(struct timeval *t, char **str) { + struct tm *tm; + + tm = gmtime(&t->tv_sec); + asprintf(str,"%4d-%02d-%02dT%02d:%02d:%02dZ",tm->tm_year+1900,tm->tm_mon+1, + tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec); +} + + +extern "C" +int +event_queue_connect(struct event_queue *eq) +{ + OutputPlugin *output; + std::string topicName; + + if(eq->plugin_data == NULL) { + output = new OutputPlugin(); + eq->plugin_data = (void*)output; + } else { + output = (OutputPlugin*)eq->plugin_data; + } + + try { + output->connect(topicName); + } catch(cms::CMSException &e) { + output->cleanup(); + eq->timeout = TIMEOUT; + return 0; + } + eq->first_event_sent = 0; + return 1; +} + + +extern "C" +int +event_queue_send(struct event_queue *eq) +{ + OutputPlugin *output = (OutputPlugin*)eq->plugin_data; + edg_wll_Context context; + edg_wll_Event *notif_event; + edg_wll_JobStat *state_out; + il_octet_string_t event; + char *jobstat_char; + int ret; + + assert(output != NULL); + + edg_wll_InitContext(&context); + + while(!event_queue_empty(eq)) { + struct server_msg *msg; + cms::TextMessage *cms_msg; + char *s; + unsigned int i; + std::string val; + + if(event_queue_get(eq, &msg) < 0) { + goto err; + } + + try { + if(decode_il_msg(&event, msg->msg) < 0) { + set_error(IL_LBAPI, EINVAL, "event_queue_send: error parsing notification event data"); + goto err; + } + ret=edg_wll_ParseNotifEvent(context, event.data, ¬if_event); + if(ret) { + set_error(IL_LBAPI, ret, "event_queue_send: error parsing notification event"); + goto err; + } + jobstat_char = glite_lbu_UnescapeXML((const char *) notif_event->notification.jobstat); + if (jobstat_char == NULL) { + set_error(IL_LBAPI, EINVAL, "event_queue_send: error unescaping job status"); + goto err; + } + if ( edg_wll_ParseJobStat(context, jobstat_char, strlen(jobstat_char), state_out)) { + set_error(IL_LBAPI, EINVAL, "event_queue_send: error parsing job status"); + goto err; + } + + + cms_msg = output->session->createTextMessage(); + /* ownerDn */ + val.assign(state_out->owner); + cms_msg->setStringProperty("ownerDn", val); + /* voname */ + s = edg_wll_JDLField(state_out,"VirtualOrganisation"); + val.assign(s); + free(s); + cms_msg->setStringProperty("voname", val); + /* bkHost */ + glite_jobid_getServerParts(state_out->jobId, &s, &i); + val.assign(s); + free(s); + cms_msg->setStringProperty("bkHost", val); + /* networkServer */ + /* TODO: XXX cut out hostname */ + val.assign(state_out->network_server); + cms_msg->setStringProperty("networkHost", val); + timeval2str(&state_out->lastUpdateTime, &s); + val.assign(s); + if(s) free(s); + cms_msg->setStringProperty("lastUpdateTime", val); + /* stateName */ + s = edg_wll_StatToString(state_out->state); + val.assign(s); + if(s) free(s); + cms_msg->setStringProperty("stateName", val); + timeval2str(&state_out->stateEnterTime, &s); + val.assign(s); + if(s) free(s); + cms_msg->setStringProperty("stateStartTime", val); + /* condorId */ + val.assign(state_out->condorId); + cms_msg->setStringProperty("condorId", val); + /* destSite */ + val.assign(state_out->destination); + cms_msg->setStringProperty("destSite", val); + /* exitCode */ + cms_msg->setIntProperty("exitCode", state_out->exit_code); + /* doneCode */ + cms_msg->setIntProperty("doneCode", state_out->done_code); + /* statusReason */ + val.assign(state_out->reason); + cms_msg->setStringProperty("statusReason", val); + + free(event.data); + edg_wll_FreeEvent(notif_event); + free(notif_event); + edg_wll_FreeStatus(state_out); + free(state_out); + free(jobstat_char); + } catch(cms::CMSException &e) { + goto err; + } + + try { + output->send(cms_msg); + delete cms_msg; + if(event_store_commit(msg->es, msg->ev_len, queue_list_is_log(eq), msg->generation) < 0) { + /* failure committing message, this is bad */ + goto err; + } + event_queue_remove(eq); + eq->first_event_sent = 1; + } catch(cms::CMSException &e) { + delete cms_msg; + output->cleanup(); + eq->timeout = TIMEOUT; + edg_wll_FreeContext(context); + return 0; + } + } + edg_wll_FreeContext(context); + return 1; + +err: + if(event.data) { + free(event.data); + } + if(notif_event) { + edg_wll_FreeEvent(notif_event); + free(notif_event); + } + if(jobstat_char) { + free(jobstat_char); + } + if(state_out) { + edg_wll_FreeStatus(state_out); + free(state_out); + } + return -1; +} + + +extern "C" +int +event_queue_close(struct event_queue *eq) +{ + OutputPlugin *output = (OutputPlugin*)eq->plugin_data; + + assert(output != NULL); + + try { + output->close(); + } catch(cms::CMSException &e) { + return -1; + } + eq->first_event_sent = 0; + return 0; +} + + +extern "C" +int +plugin_init(char *config) +{ + char *s, *p; + char key[MAXPATHLEN], val[MAXPATHLEN]; + int ret; + std::string brokerURI; + + s = strstr(config, "[msg]"); + if(s == NULL) { + set_error(IL_DL, ENOENT, "plugin_init: missing required configuration section [msg]\n"); + return -1; + } + s = strchr(s, '\n'); + if(s) s++; + while(s) { + if(*s == 0 || *s == '[') + break; + p = strchr(s, '\n'); + if(p) *p = 0; + ret = sscanf(s, " %s =%s", key, val); + if(p) *p = '\n'; + if(ret == 2) { + if(strcmp(key, "broker") == 0) { + brokerURI.assign(val); + } + } + s = p; + } + if(brokerURI.length() == 0) { + set_error(IL_DL, ENOENT, "plugin_init: broker uri not configured\n"); + return -1; + } + + try { + activemq::library::ActiveMQCPP::initializeLibrary(); + + OutputPlugin::connectionFactory = + cms::ConnectionFactory::createCMSConnectionFactory(brokerURI); + OutputPlugin::connection = OutputPlugin::connectionFactory->createConnection(); + } catch (cms::CMSException &e) { + try { + if(OutputPlugin::connection != NULL) { + delete OutputPlugin::connection; + OutputPlugin::connection = NULL; + } + if(OutputPlugin::connectionFactory != NULL) { + delete OutputPlugin::connectionFactory; + OutputPlugin::connectionFactory = NULL; + } + } catch(cms::CMSException &e) { + } + set_error(IL_DL, 0, (char*)e.what()); + return -1; + } + + return 0; +} + + +extern "C" +int +plugin_supports_scheme(const char *scheme) +{ + return strncmp(scheme, OutputPlugin::SCHEME, strlen(OutputPlugin::SCHEME)) == 0; +} + + +cms::Connection *OutputPlugin::connection = NULL; +cms::ConnectionFactory *OutputPlugin::connectionFactory = NULL; +const char *OutputPlugin::SCHEME = "x-msg:"; diff --git a/org.glite.lb.logger/src/event_queue.c b/org.glite.lb.logger/src/event_queue.c index fcfcfbc..726666c 100644 --- a/org.glite.lb.logger/src/event_queue.c +++ b/org.glite.lb.logger/src/event_queue.c @@ -1,6 +1,23 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. -/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +/* * - general queue handling routines (insert, get) */ @@ -12,7 +29,7 @@ #include #include -#include "glite/wmsutils/jobid/cjobid.h" +#include "glite/jobid/cjobid.h" #include "interlogd.h" @@ -22,15 +39,10 @@ struct event_queue_msg { }; struct event_queue * -event_queue_create(char *server_name) +event_queue_create(char *server_name, struct il_output_plugin *output) { struct event_queue *eq; - char *p; - - p = strchr(server_name, ':'); - - if(p) - *p++ = 0; + char *p,*s, c; if((eq = malloc(sizeof(*eq))) == NULL) { set_error(IL_NOMEM, ENOMEM, "event_queue_create: error allocating event queue"); @@ -39,16 +51,50 @@ event_queue_create(char *server_name) memset(eq, 0, sizeof(*eq)); - eq->dest_name = strdup(server_name); + eq->dest = strdup(server_name); + s = strstr(server_name, "://"); + if(s == NULL) { + s = server_name; + } else { + s = s + 3; + } + p = strchr(s, ':'); + if(p) { + *p++ = 0; + c = ':'; + } else { + p = strchr(s, '/'); + if(p) { + *p++ = 0; + c = '/'; + } + } + eq->dest_name = strdup(s); if(p) - *(p-1) = ':'; - -#if defined(IL_NOTIFICATIONS) - eq->dest_port = atoi(p); + *(p-1) = c; + +#if defined(IL_NOTIFICATIONS) || defined(IL_WS) + if(p && c == ':') { + eq->dest_port = atoi(p); + } else { + eq->dest_port = 0; // use whatever default there is for given url scheme + } #else - eq->dest_port = p ? atoi(p)+1 : GLITE_WMSC_JOBID_DEFAULT_PORT+1; + eq->dest_port = (p && c == ':') ? atoi(p)+1 : GLITE_JOBID_DEFAULT_PORT+1; #endif + + /* setup output functions */ + if(output != NULL) { + eq->event_queue_connect = output->event_queue_connect; + eq->event_queue_send = output->event_queue_send; + eq->event_queue_close = output->event_queue_close; + } else { + eq->event_queue_connect = event_queue_connect; + eq->event_queue_send = event_queue_send; + eq->event_queue_close = event_queue_close; + } + /* create all necessary locks */ if(pthread_rwlock_init(&eq->update_lock, NULL)) { set_error(IL_SYS, errno, "event_queue_create: error creating update lock"); @@ -96,6 +142,11 @@ event_queue_free(struct event_queue *eq) #if defined(INTERLOGD_HANDLE_CMD) && defined(INTERLOGD_FLUSH) pthread_cond_destroy(&eq->flush_cond); #endif + + if(eq->dest_name) + free(eq->dest_name); + if(eq->dest) + free(eq->dest); free(eq); return(0); @@ -124,10 +175,15 @@ event_queue_insert(struct event_queue *eq, struct server_msg *msg) #if defined(INTERLOGD_EMS) struct event_queue_msg *tail; #endif - + assert(eq != NULL); - if((el = malloc(sizeof(*el))) == NULL) + if(queue_size_high > 0 && (eq->cur_len >= queue_size_high || eq->throttling)) { + eq->throttling = 1; + return 1; + } + + if((el = malloc(sizeof(*el))) == NULL) return(set_error(IL_NOMEM, ENOMEM, "event_queue_insert: not enough room for queue element")); el->msg = server_msg_copy(msg); @@ -154,9 +210,9 @@ event_queue_insert(struct event_queue *eq, struct server_msg *msg) eq->tail = el; } eq->tail_ems = el; - } else + } else #endif - { + { /* normal messages */ if(eq->tail) eq->tail->prev = el; @@ -168,7 +224,7 @@ event_queue_insert(struct event_queue *eq, struct server_msg *msg) #if defined(INTERLOGD_EMS) /* if we are inserting message between mark_prev and mark_this, we have to adjust mark_prev accordingly */ - if(eq->mark_this && (el->prev == eq->mark_this)) + if(eq->mark_this && (el->prev == eq->mark_this)) eq->mark_prev = el; #endif @@ -189,7 +245,7 @@ event_queue_get(struct event_queue *eq, struct server_msg **msg) assert(eq != NULL); assert(msg != NULL); - + event_queue_lock(eq); el = eq->head; #if defined(INTERLOGD_EMS) @@ -208,7 +264,7 @@ event_queue_get(struct event_queue *eq, struct server_msg **msg) } -int +int event_queue_remove(struct event_queue *eq) { struct event_queue_msg *el; @@ -258,12 +314,16 @@ event_queue_remove(struct event_queue *eq) eq->tail = NULL; } #endif - if(--eq->cur_len == 0) + if(--eq->cur_len == 0) eq->times_empty++; + if(eq->cur_len <= queue_size_low) { + eq->throttling = 0; + } + event_queue_unlock(eq); /* end of critical section */ - + server_msg_free(el->msg); free(el); @@ -271,14 +331,15 @@ event_queue_remove(struct event_queue *eq) } int -event_queue_move_events(struct event_queue *eq_s, - struct event_queue *eq_d, - int (*cmp_func)(struct server_msg *, void *), +event_queue_move_events(struct event_queue *eq_s, + struct event_queue *eq_d, + int (*cmp_func)(struct server_msg *, void *), void *data) { struct event_queue_msg *p, **source_prev, **dest_tail; assert(eq_s != NULL); + assert(data != NULL); event_queue_lock(eq_s); if(eq_d) { @@ -290,20 +351,29 @@ event_queue_move_events(struct event_queue *eq_s, p = *source_prev; eq_s->tail = NULL; while(p) { - if((*cmp_func)(p->msg, data)) { - il_log(LOG_DEBUG, " moving event at offset %d from %s:%d to %s:%d\n", - p->msg->offset, eq_s->dest_name, eq_s->dest_port, - eq_d ? eq_d->dest_name : "trash", eq_d ? eq_d->dest_port : -1); - il_log(LOG_DEBUG, " current: %x, next: %x\n", p, p->prev); + if((*cmp_func)(p->msg, data)) { + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " moving event at offset %d(%d) from %s:%d to %s:%d", + p->msg->offset, p->msg->generation, eq_s->dest_name, eq_s->dest_port, + eq_d ? eq_d->dest_name : "trash", eq_d ? eq_d->dest_port : -1); + /* il_log(LOG_DEBUG, " current: %x, next: %x\n", p, p->prev); */ /* remove the message from the source list */ *source_prev = p->prev; + assert(eq_s->cur_len > 0); + eq_s->cur_len--; if(eq_d) { /* append the message at the end of destination list */ p->prev = NULL; *dest_tail = p; dest_tail = &(p->prev); eq_d->tail = p; + if(++eq_d->cur_len > eq_d->max_len) { + eq_d->max_len = eq_d->cur_len; + } } else { + /* signal that the message was 'delivered' */ + event_store_commit(p->msg->es, p->msg->ev_len, queue_list_is_log(eq_s), + p->msg->generation); /* free the message */ server_msg_free(p->msg); free(p); @@ -315,6 +385,9 @@ event_queue_move_events(struct event_queue *eq_s, } p = *source_prev; } + if(eq_s->cur_len <= queue_size_low) { + eq_s->throttling = 0; + } if(eq_d) event_queue_unlock(eq_d); event_queue_unlock(eq_s); return(0); diff --git a/org.glite.lb.logger/src/event_store.c b/org.glite.lb.logger/src/event_store.c index d919945..1824899 100644 --- a/org.glite.lb.logger/src/event_store.c +++ b/org.glite.lb.logger/src/event_store.c @@ -1,19 +1,35 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include #include #include #include +#include #include #include #include -#ifdef HAVE_UNISTD_H #include -#endif #include +#include -#include "glite/lb/consumer.h" #include "glite/lb/events_parse.h" #include "interlogd.h" @@ -29,7 +45,9 @@ static char *file_prefix = NULL; struct event_store_list { struct event_store *es; - struct event_store_list *next; + struct event_store_list *next; // LL of event_store's + struct event_store_list *jobid_next; /* double LL of rotated stores - forward */ + struct event_store_list *jobid_prev; /* double LL of rotated stores - backward */ }; @@ -43,6 +61,20 @@ static pthread_rwlock_t store_list_lock = PTHREAD_RWLOCK_INITIALIZER; */ static char * +astrcat(const char *s1, const char *s2) +{ + char *s = malloc(strlen(s1) + strlen(s2) + 1); + if(s == NULL) + return NULL; + *s = 0; + strcat(s, s1); + strcat(s, s2); + return s; +} + + +static +char * jobid2eventfile(IL_EVENT_ID_T job_id) { char *buffer; @@ -52,9 +84,9 @@ jobid2eventfile(IL_EVENT_ID_T job_id) hash = IL_EVENT_GET_UNIQUE(job_id); asprintf(&buffer, "%s.%s", file_prefix, hash); free(hash); - } else + } else asprintf(&buffer, "%s.default", file_prefix); - + return(buffer); } @@ -70,12 +102,33 @@ jobid2controlfile(IL_EVENT_ID_T job_id) hash = IL_EVENT_GET_UNIQUE(job_id); snprintf(buffer, 256, "%s.%s.ctl", file_prefix, hash); free(hash); - } else + } else snprintf(buffer, 256, "%s.default.ctl", file_prefix); - + return(strdup(buffer)); } +static +long long +fname2index(const char *filename) +{ + char *p = rindex(filename, '.'); + char *s; + long long ret; + + if(p == NULL) + return 0; + + for(s = p+1; *s != 0; s++) { + if(*s < '0' || *s > '9') { + return 0; + } + } + + sscanf(p+1,"%lld",&ret); + return ret+1; +} + static char * @@ -93,7 +146,7 @@ read_event_string(FILE *file) len = 1024; while((c=fgetc(file)) != EOF) { - + /* we have to have free room for one byte */ /* if(len - (p - buffer) < 1) */ if(p - buffer >= len) { @@ -112,7 +165,7 @@ read_event_string(FILE *file) *p++ = 0; break; } else - *p++ = (char) c; + *p++ = (char) c; } if(c != EVENT_SEPARATOR) { @@ -139,7 +192,8 @@ event_store_free(struct event_store *es) if(es->event_file_name) free(es->event_file_name); if(es->control_file_name) free(es->control_file_name); pthread_rwlock_destroy(&es->use_lock); - pthread_rwlock_destroy(&es->update_lock); + pthread_rwlock_destroy(&es->commit_lock); + pthread_rwlock_destroy(&es->offset_lock); free(es); return(0); @@ -148,7 +202,7 @@ event_store_free(struct event_store *es) static struct event_store * -event_store_create(char *job_id_s) +event_store_create(char *job_id_s, const char *filename) { struct event_store *es; IL_EVENT_ID_T job_id; @@ -161,8 +215,6 @@ event_store_create(char *job_id_s) memset(es, 0, sizeof(*es)); - il_log(LOG_DEBUG, " creating event store for id %s\n", job_id_s); - job_id = NULL; if(strcmp(job_id_s, "default") && IL_EVENT_ID_PARSE(job_id_s, &job_id)) { set_error(IL_LBAPI, EDG_WLL_ERROR_PARSE_BROKEN_ULM, "event_store_create: error parsing id"); @@ -171,13 +223,20 @@ event_store_create(char *job_id_s) } es->job_id_s = strdup(job_id_s); - es->event_file_name = jobid2eventfile(job_id); - es->control_file_name = jobid2controlfile(job_id); + es->event_file_name = filename ? strdup(filename) : jobid2eventfile(job_id); + es->control_file_name = filename ? astrcat(filename, ".ctl") : jobid2controlfile(job_id); + es->rotate_index = filename ? fname2index(filename) : 0; IL_EVENT_ID_FREE(job_id); - if(pthread_rwlock_init(&es->update_lock, NULL)) + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " creating event store for id %s, filename %s, rotate index %lld", + job_id_s, es->event_file_name, es->rotate_index); + + if(pthread_rwlock_init(&es->commit_lock, NULL)) abort(); - if(pthread_rwlock_init(&es->use_lock, NULL)) + if(pthread_rwlock_init(&es->offset_lock, NULL)) + abort(); + if(pthread_rwlock_init(&es->use_lock, NULL)) abort(); return(es); @@ -186,24 +245,11 @@ event_store_create(char *job_id_s) static int -event_store_lock_ro(struct event_store *es) -{ - assert(es != NULL); - - if(pthread_rwlock_rdlock(&es->update_lock)) - abort(); - - return(0); -} - - -static -int event_store_lock(struct event_store *es) { assert(es != NULL); - if(pthread_rwlock_wrlock(&es->update_lock)) + if(pthread_rwlock_wrlock(&es->commit_lock)) abort(); return(0); @@ -216,7 +262,7 @@ event_store_unlock(struct event_store *es) { assert(es != NULL); - if(pthread_rwlock_unlock(&es->update_lock)) + if(pthread_rwlock_unlock(&es->commit_lock)) abort(); return(0); } @@ -262,8 +308,8 @@ event_store_write_ctl(struct event_store *es) return(-1); } - if(fprintf(ctl, "%s\n%ld\n%ld\n", - es->job_id_s, + if(fprintf(ctl, "%s\n%ld\n%ld\n", + es->job_id_s, es->last_committed_ls, es->last_committed_bs) < 0) { set_error(IL_SYS, errno, "event_store_write_ctl: error writing control record"); @@ -280,20 +326,23 @@ event_store_write_ctl(struct event_store *es) /* - * event_store_qurantine() - * - rename damaged event store file - * - essentially does the same actions as cleanup, but the event store + * event_store_qurantine() + * - rename damaged event store file + * - essentially does the same actions as cleanup, but the event store * does not have to be empty * returns 0 on success, -1 on error */ static int -event_store_quarantine(struct event_store *es) +event_store_quarantine(struct event_store *es) { + // TODO enable cleanup of quarantined event_store struct + // TODO handle file rotation + int num; char newname[MAXPATHLEN+1]; - /* find available qurantine name */ + /* find available quarantine name */ /* we give it at most 1024 tries */ for(num = 0; num < 1024; num++) { struct stat st; @@ -306,9 +355,9 @@ event_store_quarantine(struct event_store *es) break; } else { /* some other error with name, probably permanent */ - set_error(IL_SYS, errno, "event_store_qurantine: error looking for qurantine filename"); + set_error(IL_SYS, errno, "event_store_qurantine: error looking for quarantine filename"); return(-1); - + } } else { /* the filename is used already */ @@ -322,8 +371,9 @@ event_store_quarantine(struct event_store *es) } /* actually rename the file */ - il_log(LOG_DEBUG, " renaming damaged event file from %s to %s\n", - es->event_file_name, newname); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, + " renaming damaged event file from %s to %s", + es->event_file_name, newname); if(rename(es->event_file_name, newname) < 0) { set_error(IL_SYS, errno, "event_store_quarantine: error renaming event file"); return(-1); @@ -334,11 +384,142 @@ event_store_quarantine(struct event_store *es) es->last_committed_bs = 0; es->offset = 0; + /* increase cleanup count, this will invalidate all commits from previous generation */ + es->generation++; + + return(0); +} + + +/* + * event_store_rotate_file() + * returns 0 on success, -1 on error + */ +static +int +event_store_rotate_file(struct event_store *es) +{ + int num; + time_t timestamp = time(NULL); + char newname[MAXPATHLEN+1]; + + /* do not rotate already rotated files */ + if(es->rotate_index > 0) + return 0; + + /* find available name */ + /* we give it at most 256 tries */ + for(num = 0; num < 256; num++) { + struct stat st; + + snprintf(newname, MAXPATHLEN, "%s.%d%03d", es->event_file_name, (int) timestamp, num); + newname[MAXPATHLEN] = 0; + if(stat(newname, &st) < 0) { + if(errno == ENOENT) { + /* file not found */ + break; + } else { + /* some other error with name, probably permanent */ + set_error(IL_SYS, errno, "event_store_rotate_file: error looking for available filename"); + return(-1); + + } + } else { + /* the filename is used already */ + } + } + if(num >= 1024) { + /* new name not found */ + /* XXX - is there more suitable error? */ + set_error(IL_SYS, ENOSPC, "event_store_quarantine: exhausted number of retries looking for quarantine filename"); + return(-1); + } + + /* actually rename the file */ + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_INFO, + " renaming too large event file from %s to %s", + es->event_file_name, newname); + if(rename(es->event_file_name, newname) < 0) { + set_error(IL_SYS, errno, "event_store_rotate_file: error renaming event file"); + return(-1); + } + + /* change names in event_store */ + es->event_file_name = strdup(newname); + es->control_file_name = astrcat(newname, ".ctl"); + es->rotate_index = 1000*timestamp + num + 1; + return(0); } /* + * event_store_recover_jobid() + * - recover all event stores for given jobid + */ +static +int +event_store_recover_jobid(struct event_store *es) +{ + // es is locked for use already + struct event_store_list *p = es->le; + + do { + event_store_recover(p->es); + if(p != es->le ) { + event_store_release(p->es); + } + + if(pthread_rwlock_rdlock(&store_list_lock)) + abort(); + p = p->jobid_next; + if(p != es->le) { + if(pthread_rwlock_rdlock(&p->es->use_lock)) + abort(); + } + if(pthread_rwlock_unlock(&store_list_lock)) + abort(); + + + } while(p != es->le); + + return 0; +} + +#if defined(IL_NOTIFICATIONS) +static +int +cmp_jobid(struct server_msg *msg, void *data) +{ + assert(msg != NULL); + assert(data != NULL); + + char *job_id_s = (char*)data; + return strcmp(msg->job_id_s, job_id_s) == 0; +} + +struct cmp_exp_data { + char *job_id_s; + time_t expires; +}; + +static +int +cmp_jobid_set_exp(struct server_msg *msg, void *data) +{ + struct cmp_exp_data *m = (struct cmp_exp_data *)data; + + assert(msg != NULL); + assert(data != NULL); + + if(strcmp(msg->job_id_s, m->job_id_s) == 0) { + msg->expires = m->expires; + } + return 0; +} +#endif + +/* * event_store_recover() * - recover after restart or catch up when events missing in IPC * - if offset > 0, read everything behind it @@ -351,40 +532,51 @@ event_store_recover(struct event_store *es) struct server_msg *msg; char *event_s; int fd, ret; - long last; + int throttle; + long fpos, last; FILE *ef; struct flock efl; char err_msg[128]; struct stat stbuf; +#if defined(IL_NOTIFICATIONS) + char *last_dest = NULL; + time_t last_exp = 0; +#endif assert(es != NULL); - + #if defined(IL_NOTIFICATIONS) - /* destination queue has to be found for each message separately */ + /* destination queue has to be found for each message separately, */ + /* this is current known destination for our notification id (may be NULL!) */ + eq_b = notifid_map_get_dest(es->job_id_s); #else - /* find bookkepping server queue */ - eq_b = queue_list_get(es->job_id_s); - if(eq_b == NULL) - return(-1); -#endif - -#if !defined(IL_NOTIFICATIONS) /* get log server queue */ eq_l = queue_list_get(NULL); + /* find bookkeeping server queue */ + eq_b = queue_list_get(es->job_id_s); + if(eq_b == NULL) + return(-1); #endif + /* lock the event_store and offset locks */ event_store_lock(es); + if(pthread_rwlock_wrlock(&es->offset_lock)) + abort(); - il_log(LOG_DEBUG, " reading events from %s\n", es->event_file_name); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " reading events from %s", + es->event_file_name); /* open event file */ ef = fopen(es->event_file_name, "r"); if(ef == NULL) { - snprintf(err_msg, sizeof(err_msg), + snprintf(err_msg, sizeof(err_msg), "event_store_recover: error opening event file %s", es->event_file_name); set_error(IL_SYS, errno, err_msg); event_store_unlock(es); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); return(-1); } @@ -395,11 +587,13 @@ event_store_recover(struct event_store *es) efl.l_start = 0; efl.l_len = 0; if(fcntl(fd, F_SETLKW, &efl) < 0) { - snprintf(err_msg, sizeof(err_msg), + snprintf(err_msg, sizeof(err_msg), "event_store_recover: error locking event file %s", es->event_file_name); set_error(IL_SYS, errno, err_msg); event_store_unlock(es); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); fclose(ef); return(-1); } @@ -407,19 +601,31 @@ event_store_recover(struct event_store *es) /* check the file modification time and size to avoid unnecessary operations */ memset(&stbuf, 0, sizeof(stbuf)); if(fstat(fd, &stbuf) < 0) { - il_log(LOG_ERR, " could not stat event file %s: %s\n", es->event_file_name, strerror(errno)); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + " could not stat event file %s: %s", + es->event_file_name, strerror(errno)); fclose(ef); event_store_unlock(es); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); return -1; } else { if((es->offset == stbuf.st_size) && (es->last_modified == stbuf.st_mtime)) { - il_log(LOG_DEBUG, " event file not modified since last visit, skipping\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " event file not modified since last visit, skipping"); fclose(ef); event_store_unlock(es); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); return(0); } } + /* check the file size, rename it if it is bigger than max_store_size */ + if(max_store_size > 0 && stbuf.st_size > max_store_size) { + event_store_rotate_file(es); + } + while(1) { /* try, try, try */ /* get the position in file to be sought */ @@ -427,7 +633,7 @@ event_store_recover(struct event_store *es) last = es->offset; else { #if !defined(IL_NOTIFICATIONS) - if(eq_b == eq_l) + if(eq_b == eq_l) last = es->last_committed_ls; else #endif @@ -440,9 +646,12 @@ event_store_recover(struct event_store *es) last = es->last_committed_bs; } - il_log(LOG_DEBUG, " setting starting file position to %ld\n", last); - il_log(LOG_DEBUG, " bytes sent to logging server: %d\n", es->last_committed_ls); - il_log(LOG_DEBUG, " bytes sent to bookkeeping server: %d\n", es->last_committed_bs); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " setting starting file position to %ld", last); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " bytes sent to logging server: %d", es->last_committed_ls); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " bytes sent to bookkeeping server: %d", es->last_committed_bs); if(last > 0) { int c; @@ -454,15 +663,17 @@ event_store_recover(struct event_store *es) set_error(IL_SYS, errno, "event_store_recover: error setting position for read"); event_store_unlock(es); fclose(ef); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); return(-1); } /* the last enqueued event MUST end with EVENT_SEPARATOR, even if the offset points at EOF */ if((c=fgetc(ef)) != EVENT_SEPARATOR) { /* Houston, we have got a problem */ - il_log(LOG_WARNING, - " file position %ld does not point at the beginning of event string, backing off!\n", - last); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, + " file position %ld does not point at the beginning of event string, backing off!", + last); /* now, where were we? */ if(es->offset) { /* next try will be with @@ -484,19 +695,39 @@ event_store_recover(struct event_store *es) set_error(IL_SYS, errno, "event_store_recover: error setting position for read"); event_store_unlock(es); fclose(ef); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); return(-1); } break; } } + /* now we have: + * - event file opened at position 'last' + * - offset and last_committed_* potentially reset to zero + */ + + /* release lock on commits, offset remains locked; + * other threads are allowed to send/remove events, but not insert + */ + event_store_unlock(es); + /* enqueue all remaining events */ ret = 1; msg = NULL; + throttle = 0; + fpos = last; while((event_s=read_event_string(ef)) != NULL) { - - /* last holds the starting position of event_s in file */ - il_log(LOG_DEBUG, " reading event at %ld\n", last); + long last_ls, last_bs; + int r; + + /* fpos holds the starting position of event_s in file */ + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " reading event at %ld", fpos); + + last_ls = es->last_committed_ls; + last_bs = es->last_committed_bs; /* break from now on means there was some error */ ret = -1; @@ -511,62 +742,155 @@ event_store_recover(struct event_store *es) free(event_s); } if(msg == NULL) { - il_log(LOG_ALERT, " event file corrupted! I will try to move it to quarantine (ie. rename it).\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, + " event file corrupted! I will try to move it to quarantine (ie. rename it)."); /* actually do not bother if quarantine succeeded or not - we could not do more */ event_store_quarantine(es); fclose(ef); - event_store_unlock(es); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); return(-1); } msg->es = es; + msg->generation = es->generation; + +#ifdef IL_NOTIFICATIONS + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + "message dest %s, last dest %s, known dest %s", + msg->dest, last_dest, eq_b ? eq_b->dest : "none"); + /* check message destination */ + if(msg->dest == NULL) { + /* the message does not have destination itself, use destination cached for notification id */ + if(eq_b == NULL) { + /* no destination is known for notification id, commit it immediately */ + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " message has no known destination, will not be sent"); + event_store_commit(es, msg->ev_len, 0, msg->generation); + } + } else { + /* check if we know destination for notification id */ + if(eq_b == NULL) { + eq_b = queue_list_get(msg->dest); + if(notifid_map_set_dest(es->job_id_s, eq_b) < 0) { + break; + } + } + /* remember last message destination */ + if(last_dest == NULL || strcmp(msg->dest, last_dest) != 0) { + /* destination changed */ + if(last_dest) { + free(last_dest); + } + last_dest = strdup(msg->dest); + } + } + /* check message expiration */ + if(last_exp == 0 || last_exp != msg->expires) { + last_exp = msg->expires; + } +#else /* first enqueue to the LS */ - if(!bs_only && (last >= es->last_committed_ls)) { - - il_log(LOG_DEBUG, " queueing event at %ld to logging server\n", last); + if(!bs_only && (last >= last_ls)) { -#if !defined(IL_NOTIFICATIONS) - if(enqueue_msg(eq_l, msg) < 0) - break; -#endif - } + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " queuing event at %ld to logging server", last); -#ifdef IL_NOTIFICATIONS - eq_b = queue_list_get(msg->dest); + /* TODO: throttling for the log server queue? */ + if(enqueue_msg(eq_l, msg) < 0) { + break; + } + } #endif - /* now enqueue to the BS, if neccessary */ - if((eq_b != eq_l) && - (last >= es->last_committed_bs)) { - - il_log(LOG_DEBUG, " queueing event at %ld to bookkeeping server\n", last); - - if(enqueue_msg(eq_b, msg) < 0) - break; + /* now enqueue to the BS, if necessary */ + if(!throttle && (eq_b != eq_l) && (last >= last_bs)) { + + if((r=enqueue_msg(eq_b, msg)) < 0) { + break; + } else if(r > 0) { + throttle = 1; + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_INFO, + " queue max length limit reached, event at %ld throttled", fpos); + } else { + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " queuing event at %ld to bookkeeping server", last); + } } server_msg_free(msg); msg = NULL; + fpos = ftell(ef); /* now last is also the offset behind the last successfully queued event */ - last = ftell(ef); + if(!throttle) { + last = fpos; + } /* ret == 0 means EOF or incomplete event found */ ret = 0; } /* while */ - /* due to this little assignment we had to lock the event_store for writing */ +#if defined(IL_NOTIFICATIONS) + /* check if we have to move events to new destination */ + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " last destination %s, last known destination %s", + last_dest, eq_b ? eq_b->dest : "none"); + if(last_dest && strcmp(last_dest, eq_b->dest)) { + struct event_queue *eq_dest = queue_list_get(last_dest); + + /* set new destination */ + if(notifid_map_set_dest(es->job_id_s, eq_dest) < 0) { + ret = -1; + } else { + + /* move all events with this notif_id from eq_b to eq_dest */ + event_queue_move_events(eq_b, eq_dest, cmp_jobid, es->job_id_s); + eq_b = eq_dest; + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_INFO, + " all messages for notif id %s are now destined to %s", + es->job_id_s, eq_b->dest); + if(event_queue_create_thread(eq_b) < 0) { + ret = -1; + } else { + event_queue_cond_lock(eq_b); + event_queue_signal(eq_b); + event_queue_cond_unlock(eq_b); + } + } + } + if(last_dest) { + free(last_dest); + last_dest = NULL; + } + + /* if the expiration changed, set new one */ + if(eq_b && last_exp != notifid_map_get_expiration(es->job_id_s)) { + struct cmp_exp_data data; + + notifid_map_set_expiration(es->job_id_s, last_exp); + /* set expiration for all events with this notif id */ + data.job_id_s = es->job_id_s; + data.expires = last_exp; + event_queue_move_events(eq_b, NULL, cmp_jobid_set_exp, &data); + } +#endif + es->offset = last; es->last_modified = stbuf.st_mtime; - il_log(LOG_DEBUG, " event store offset set to %ld\n", last); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " event store offset set to %ld", last); - if(msg) + if(msg) server_msg_free(msg); fclose(ef); - il_log(LOG_DEBUG, " finished reading events with %d\n", ret); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " finished reading events with %d", ret); + + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); - event_store_unlock(es); return(ret); } @@ -590,51 +914,9 @@ event_store_sync(struct event_store *es, long offset) * event will be read from file, socket now serves only to notify * about possible event file change. */ - ret = event_store_recover(es); + ret = event_store_recover_jobid(es); ret = (ret < 0) ? ret : 0; return(ret); - -#if 0 - event_store_lock_ro(es); - if(es->offset == offset) - /* we are up to date */ - ret = 1; - else if(es->offset > offset) - /* we have already seen this event */ - ret = 0; - else { - /* es->offset < offset, i.e. we have missed some events */ - event_store_unlock(es); - ret = event_store_recover(es); - /* XXX possible room for intervention by another thread - is there - * any other thread messing with us? - * 1) After recover() es->offset is set at the end of file. - * 2) es->offset is set only by recover() and next(). - * 3) Additional recover can not do much harm. - * 4) And next() is only called by the same thread as sync(). - * 5) use_lock is in place, so no cleanup possible - * => no one is messing with us right now */ - event_store_lock_ro(es); - if(ret < 0) - ret = -1; - else - if(es->offset <= offset) { - /* Apparently there is something wrong - we are receiving an event - * which is beyond the end of file. Someone must have removed the file - * when we were not looking. The question is - what should we do with the event? - * We have to send it, as this is the only one occasion when we see it. - * However, we must not allow the es->offset to be set using this event, - * as it would point after the end of file. Sort this out in event_store_next(). - */ - ret = 1; - } else if(es->offset > offset) { - /* we have seen at least this event */ - ret = 0; - } - } - event_store_unlock(es); - return(ret); -#endif } @@ -642,39 +924,32 @@ int event_store_next(struct event_store *es, long offset, int len) { assert(es != NULL); - - /* Commented out due to the fact that offset as received on socket + + /* offset as received on socket * has little to do with real event file at the moment. es->offset * handling is left solely to the event_store_recover(). */ - -#if 0 - event_store_lock(es); - /* Whoa, be careful now. The es->offset points right after the last enqueued event, - * but it may not be the offset of the event WE have just enqueued, because:! - * 1) someone could have removed the event file behind our back - * 2) the file could have been recover()ed and more events read - * In either case the offset should not be moved. - */ - if(es->offset == offset) { - es->offset += len; - } - event_store_unlock(es); -#endif return(0); } -/* +/* * event_store_commit() * */ int -event_store_commit(struct event_store *es, int len, int ls) +event_store_commit(struct event_store *es, int len, int ls, int generation) { assert(es != NULL); + /* do not move counters if event store with this message was cleaned up + * (this can happen only when moving to quarantine) + */ + /* XXX - assume int access is atomic */ + if(generation != es->generation) + return 0; + event_store_lock(es); if(ls) @@ -704,7 +979,7 @@ event_store_commit(struct event_store *es, int len, int ls) * Q: How do we know that we can safely remove the files? * A: When all events from file have been committed both by LS and BS. */ -static +static int event_store_clean(struct event_store *es) { @@ -717,20 +992,28 @@ event_store_clean(struct event_store *es) /* prevent sender threads from updating */ event_store_lock(es); - - il_log(LOG_DEBUG, " trying to cleanup event store %s\n", es->job_id_s); - il_log(LOG_DEBUG, " bytes sent to logging server: %d\n", es->last_committed_ls); - il_log(LOG_DEBUG, " bytes sent to bookkeeping server: %d\n", es->last_committed_bs); + + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " trying to cleanup event store %s", es->job_id_s); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " bytes sent to logging server: %d", es->last_committed_ls); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " bytes sent to bookkeeping server: %d", es->last_committed_bs); /* preliminary check to avoid opening event file */ /* if the positions differ, some events still have to be sent */ if(es->last_committed_ls != es->last_committed_bs) { event_store_unlock(es); - il_log(LOG_DEBUG, " not all events sent, cleanup aborted\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " not all events sent, cleanup aborted"); return(0); } - /* the file can only be removed when all the events were succesfully sent + if((fd = pthread_rwlock_wrlock(&es->offset_lock)) != 0) { + abort(); + } + + /* the file can only be removed when all the events were succesfully sent (ie. committed both by LS and BS */ /* That also implies that the event queues are 'empty' at the moment. */ ef = fopen(es->event_file_name, "r+"); @@ -738,21 +1021,27 @@ event_store_clean(struct event_store *es) /* if we can not open the event store, it is an error and the struct should be removed */ /* XXX - is it true? */ event_store_unlock(es); - il_log(LOG_ERR, " event_store_clean: error opening event file: %s\n", strerror(errno)); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + " event_store_clean: error opening event file: %s", strerror(errno)); return(1); } - + fd = fileno(ef); - + /* prevent local-logger from writing into event file */ efl.l_type = F_WRLCK; efl.l_whence = SEEK_SET; efl.l_start = 0; efl.l_len = 0; if(fcntl(fd, F_SETLK, &efl) < 0) { - il_log(LOG_DEBUG, " could not lock event file, cleanup aborted\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, + " could not lock event file, cleanup aborted"); fclose(ef); event_store_unlock(es); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); if(errno != EACCES && errno != EAGAIN) { set_error(IL_SYS, errno, "event_store_clean: error locking event file"); @@ -760,47 +1049,63 @@ event_store_clean(struct event_store *es) } return(0); } - + /* now the file should not contain partially written event, so it is safe to get offset behind last event by seeking the end of file */ if(fseek(ef, 0, SEEK_END) < 0) { set_error(IL_SYS, errno, "event_store_clean: error seeking the end of file"); event_store_unlock(es); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); fclose(ef); return(-1); } - + last = ftell(ef); - il_log(LOG_DEBUG, " total bytes in file: %d\n", last); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " total bytes in file: %d", last); if(es->last_committed_ls < last) { fclose(ef); event_store_unlock(es); - il_log(LOG_DEBUG, " events still waiting in queue, cleanup aborted\n"); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " events still waiting in queue, cleanup aborted"); return(0); } else if( es->last_committed_ls > last) { - il_log(LOG_WARNING, " warning: event file seems to shrink!\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, + " warning: event file seems to shrink!"); /* XXX - in that case we can not continue because there may be some undelivered events referring to that event store */ fclose(ef); event_store_unlock(es); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); return(0); } - + /* now we are sure that all events were sent and the event queues are empty */ - il_log(LOG_INFO, " removing event file %s\n", es->event_file_name); - + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_INFO, + " removing event file %s", es->event_file_name); + /* remove the event file */ unlink(es->event_file_name); unlink(es->control_file_name); - + /* clear the counters */ es->last_committed_ls = 0; es->last_committed_bs = 0; es->offset = 0; + /* increasing the generation count is rather pointless here, because there + are no messages waiting in the queue that would be invalidated */ + /* es->generation++ */ + /* unlock the event_store even if it is going to be removed */ event_store_unlock(es); + if(pthread_rwlock_unlock(&es->offset_lock)) + abort(); /* close the event file (that unlocks it as well) */ fclose(ef); @@ -815,9 +1120,9 @@ event_store_clean(struct event_store *es) * -------------------------------- */ struct event_store * -event_store_find(char *job_id_s) +event_store_find(char *job_id_s, const char *filename) { - struct event_store_list *q, *p; + struct event_store_list *q, *p, *d; struct event_store *es; if(pthread_rwlock_wrlock(&store_list_lock)) { @@ -825,27 +1130,31 @@ event_store_find(char *job_id_s) } es = NULL; - - q = NULL; + + d = NULL; p = store_list; - + while(p) { if(strcmp(p->es->job_id_s, job_id_s) == 0) { - es = p->es; - if(pthread_rwlock_rdlock(&es->use_lock)) - abort(); - if(pthread_rwlock_unlock(&store_list_lock)) - abort(); - return(es); + es = p->es; + d = p; + // if filename was given, compare it as well + if((filename == NULL && p->es->rotate_index == 0) || + (filename != NULL && strcmp(p->es->event_file_name, filename) == 0)) { + if(pthread_rwlock_rdlock(&es->use_lock)) + abort(); + if(pthread_rwlock_unlock(&store_list_lock)) + abort(); + return(es); + } } - - q = p; p = p->next; } - es = event_store_create(job_id_s); + // event store for given jobid and filename was not found, create one + es = event_store_create(job_id_s, filename); if(es == NULL) { - if(pthread_rwlock_unlock(&store_list_lock)) + if(pthread_rwlock_unlock(&store_list_lock)) abort(); return(NULL); } @@ -853,20 +1162,66 @@ event_store_find(char *job_id_s) p = malloc(sizeof(*p)); if(p == NULL) { set_error(IL_NOMEM, ENOMEM, "event_store_find: no room for new event store"); - if(pthread_rwlock_unlock(&store_list_lock)) + if(pthread_rwlock_unlock(&store_list_lock)) abort(); return(NULL); } - - p->next = store_list; - store_list = p; - p->es = es; + p->jobid_next = p; + p->jobid_prev = p; + es->le = p; + + if(filename != NULL && d != NULL) { + // there is another event store for this jobid; + // d points to the last event store for this jobid in LL + // find proper place to insert new event store + if(p->es->rotate_index == 0) { + // insert behind d in LL + p->next = d->next; + d->next = p; + // insert behind d in jobid LL + p->jobid_next = d->jobid_next; + p->jobid_prev = d; + d->jobid_next->jobid_prev = p; + d->jobid_next = p; + } else { + struct event_store_list *r; + q = NULL; + for(r = d->jobid_next; r != d->jobid_next; r = r->jobid_next) { + if(p->es->rotate_index < r->es->rotate_index) + break; + if(r->es->rotate_index > 0) + q = r; + } + // q has the last lesser non-zero index than p + if(q == NULL) { + p->next = store_list; + store_list = p; + // insert behind d + p->jobid_next = d->jobid_next; + p->jobid_prev = d; + d->jobid_next->jobid_prev = p; + d->jobid_next = p; + } else { + p->next = q->next; + q->next = p; + // insert behind q + p->jobid_next = q->jobid_next; + p->jobid_prev = q; + q->jobid_next->jobid_prev = p; + q->jobid_next = p; + } + } + } else { + // insert at the beginning + p->next = store_list; + store_list = p; + } if(pthread_rwlock_rdlock(&es->use_lock)) abort(); - if(pthread_rwlock_unlock(&store_list_lock)) + if(pthread_rwlock_unlock(&store_list_lock)) abort(); return(es); @@ -880,7 +1235,8 @@ event_store_release(struct event_store *es) if(pthread_rwlock_unlock(&es->use_lock)) abort(); - il_log(LOG_DEBUG, " released lock on %s\n", es->job_id_s); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " released lock on %s (%s)", es->job_id_s, es->event_file_name); return(0); } @@ -896,15 +1252,13 @@ event_store_from_file(char *filename) #if defined(IL_NOTIFICATIONS) edg_wll_Event *notif_event; edg_wll_Context context; - char *dest_name = NULL; - - edg_wll_InitContext(&context); #endif - - il_log(LOG_INFO, " attaching to event file: %s\n", filename); - + + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_INFO, + " attaching to event file: %s", filename); + if(strstr(filename, "quarantine") != NULL) { - il_log(LOG_INFO, " file name belongs to quarantine, not touching that.\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, " file name belongs to quarantine, not touching that."); return(0); } @@ -915,17 +1269,20 @@ event_store_from_file(char *filename) } event_s = read_event_string(event_file); fclose(event_file); - if(event_s == NULL) + if(event_s == NULL) return(0); - + #if defined(IL_NOTIFICATIONS) - if((ret=edg_wll_ParseNotifEvent(context, event_s, ¬if_event))) { + edg_wll_InitContext(&context); + ret=edg_wll_ParseNotifEvent(context, event_s, ¬if_event); + edg_wll_FreeContext(context); + if(ret) { set_error(IL_LBAPI, ret, "event_store_from_file: could not parse event"); ret = -1; goto out; } if(notif_event->notification.notifId == NULL) { - set_error(IL_LBAPI, EDG_WLL_ERROR_PARSE_BROKEN_ULM, + set_error(IL_LBAPI, EDG_WLL_ERROR_PARSE_BROKEN_ULM, "event_store_from_file: parse error - no notif id"); ret = -1; goto out; @@ -935,23 +1292,28 @@ event_store_from_file(char *filename) ret = -1; goto out; } - if(notif_event->notification.dest_host && + /* XXX: what was that good for? + if(notif_event->notification.dest_host && (strlen(notif_event->notification.dest_host) > 0)) { + char *dest_name = NULL; asprintf(&dest_name, "%s:%d", notif_event->notification.dest_host, notif_event->notification.dest_port); } - + */ + #else job_id_s = edg_wll_GetJobId(event_s); #endif - il_log(LOG_DEBUG, " event id: '%s'\n", job_id_s); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " event id: '%s'", job_id_s); if(job_id_s == NULL) { - il_log(LOG_NOTICE, " skipping file, could not parse event\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " skipping file, could not parse event"); ret = 0; goto out; } - - es=event_store_find(job_id_s); - + + es = event_store_find(job_id_s, filename); + if(es == NULL) { ret = -1; goto out; @@ -961,9 +1323,9 @@ event_store_from_file(char *filename) (es->last_committed_bs == 0) && (es->offset == 0)) { ret = event_store_read_ctl(es); - } else + } else ret = 0; - + event_store_release(es); out: @@ -973,7 +1335,7 @@ out: free(notif_event); } #endif - if(event_s) free(event_s); + if(event_s) free(event_s); if(job_id_s) free(job_id_s); return(ret); } @@ -1015,12 +1377,12 @@ event_store_init(char *prefix) set_error(IL_SYS, errno, "event_store_init: error opening event directory"); return(-1); } - + while((entry=readdir(event_dir))) { char *s; /* skip all files that do not match prefix */ - if(strncmp(entry->d_name, p, len) != 0) + if(strncmp(entry->d_name, p, len) != 0) continue; /* skip all control files */ @@ -1058,12 +1420,12 @@ event_store_init(char *prefix) set_error(IL_SYS, errno, "event_store_init: error opening event directory"); return(-1); } - + while((entry=readdir(event_dir))) { char *s; /* skip all files that do not match prefix */ - if(strncmp(entry->d_name, p, len) != 0) + if(strncmp(entry->d_name, p, len) != 0) continue; /* find all control files */ @@ -1093,10 +1455,12 @@ event_store_init(char *prefix) } else { /* could not stat file, remove ctl */ strcat(ef, s); - il_log(LOG_DEBUG, " removing stale file %s\n", ef); - if(unlink(ef)) - il_log(LOG_ERR, " could not remove file %s: %s\n", ef, strerror(errno)); - + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " removing stale file %s", ef); + if(unlink(ef)) + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + " could not remove file %s: %s\n", ef, strerror(errno)); + } free(ef); @@ -1116,7 +1480,7 @@ event_store_recover_all() struct event_store_list *sl; - if(pthread_rwlock_rdlock(&store_list_lock)) + if(pthread_rwlock_rdlock(&store_list_lock)) abort(); /* recover all event stores */ @@ -1126,20 +1490,22 @@ event_store_recover_all() /* recover this event store */ /* no need to lock use_lock in event_store, the store_list_lock is in place */ if(event_store_recover(sl->es) < 0) { - il_log(LOG_ERR, " error recovering event store %s:\n %s\n", sl->es->event_file_name, error_get_msg()); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + " error recovering event store %s: %s", + sl->es->event_file_name, error_get_msg()); clear_error(); } sl = sl->next; } - - if(pthread_rwlock_unlock(&store_list_lock)) + + if(pthread_rwlock_unlock(&store_list_lock)) abort(); return(0); } -#if 0 +#if 0 int event_store_remove(struct event_store *es) { @@ -1149,9 +1515,10 @@ event_store_remove(struct event_store *es) switch(event_store_clean(es)) { case 0: - il_log(LOG_DEBUG, " event store not removed, still used\n"); - return(0); - + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " event store not removed, still used"); + return(0); + case 1: if(pthread_rwlock_wrlock(&store_list_lock) < 0) { set_error(IL_SYS, errno, " event_store_remove: error locking event store list"); @@ -1195,7 +1562,7 @@ event_store_cleanup() /* try to remove event files */ - if(pthread_rwlock_wrlock(&store_list_lock)) + if(pthread_rwlock_wrlock(&store_list_lock)) abort(); sl = store_list; @@ -1205,11 +1572,12 @@ event_store_cleanup() int ret; slnext = sl->next; - + /* one event store at time */ ret = pthread_rwlock_trywrlock(&sl->es->use_lock); if(ret == EBUSY) { - il_log(LOG_DEBUG, " event_store %s is in use by another thread\n", + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, + " event_store %s is in use by another thread", sl->es->job_id_s); sl = slnext; continue; @@ -1217,33 +1585,39 @@ event_store_cleanup() abort(); switch(event_store_clean(sl->es)) { - + case 1: - /* remove this event store */ + /* remove this event store from LL */ (*prev) = slnext; + /* remove this event store from jobid's LL */ + if(sl->jobid_next != sl) { + sl->jobid_prev->jobid_next = sl->jobid_next; + sl->jobid_next->jobid_prev = sl->jobid_prev; + } event_store_free(sl->es); free(sl); break; - + case -1: - il_log(LOG_ERR, " error removing event store %s (file %s):\n %s\n", - sl->es->job_id_s, sl->es->event_file_name, error_get_msg()); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + " error removing event store %s (file %s): %s", + sl->es->job_id_s, sl->es->event_file_name, error_get_msg()); /* event_store_release(sl->es); */ clear_error(); /* go on to the next */ - + default: event_store_release(sl->es); prev = &(sl->next); break; } - + sl = slnext; } - - if(pthread_rwlock_unlock(&store_list_lock)) + + if(pthread_rwlock_unlock(&store_list_lock)) abort(); - + return(0); } diff --git a/org.glite.lb.logger/src/event_store_http.c b/org.glite.lb.logger/src/event_store_http.c new file mode 100644 index 0000000..4f09b26 --- /dev/null +++ b/org.glite.lb.logger/src/event_store_http.c @@ -0,0 +1,1130 @@ +#ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "glite/lb/events_parse.h" + +#include "interlogd.h" + +#ifdef __GNUC__ +#define UNUSED_VAR __attribute__((unused)) +#else +#define UNUSED_VAR +#endif + +static char *file_prefix = NULL; + + +struct event_store_list { + struct event_store *es; + struct event_store_list *next; +}; + + +static struct event_store_list *store_list; +static pthread_rwlock_t store_list_lock = PTHREAD_RWLOCK_INITIALIZER; + + +/* ---------------- + * helper functions + * ---------------- + */ +static +char * +jobid2eventfile(const char *job_id_s) +{ + char *buffer; + + if(job_id_s) { + asprintf(&buffer, "%s.%s", file_prefix, job_id_s); + } else + asprintf(&buffer, "%s.default", file_prefix); + + return(buffer); +} + + +static +char * +jobid2controlfile(char *job_id_s) +{ + char *buffer; + char *hash; + + if(job_id_s) { + asprintf(&buffer, "%s.%s.ctl", file_prefix, job_id_s); + } else + asprintf(&buffer, "%s.default.ctl", file_prefix); + + return(buffer); +} + +static +int +file_reader(void *user_data, char *buffer, const int len) +{ + size_t ret = 0; + + if(len > 0) { + ret = fread(buffer, 1, len, (FILE*)user_data); + if(ret == 0 && ferror((FILE*)user_data)) { + return -1; + } + } + return ret; +} + + +static +int +read_event_string(FILE *file, il_http_message_t *msg) +{ + int len, ret; + int fd = fileno(file); + long start; + + /* remember the start position */ + start = ftell(file); + ret = receive_http(file, file_reader, msg); + if(ret < 0) return ret; + /* seek at the end of message in case the reader read ahead */ + len = fseek(file, start + msg->len, SEEK_SET); + len = fgetc(file); + if(len != '\n') { + il_log(LOG_ERR, "error reading event from file, missing terminator character at %d, found %c(%d))\n", + start+msg->len, len, len); + if(msg->data) { free(msg->data); msg->data = NULL; } + if(msg->host) { free(msg->host); msg->host = NULL; } + return EINVAL; + } + return ret; +} + + + +/* ------------------------------ + * event_store 'member' functions + * ------------------------------ + */ +static +int +event_store_free(struct event_store *es) +{ + assert(es != NULL); + + if(es->job_id_s) free(es->job_id_s); + if(es->event_file_name) free(es->event_file_name); + if(es->control_file_name) free(es->control_file_name); + pthread_rwlock_destroy(&es->use_lock); + pthread_rwlock_destroy(&es->commit_lock); + free(es); + + return(0); +} + + +static +struct event_store * +event_store_create(char *job_id_s) +{ + struct event_store *es; + + es = malloc(sizeof(*es)); + if(es == NULL) { + set_error(IL_NOMEM, ENOMEM, "event_store_create: error allocating room for structure"); + return(NULL); + } + + memset(es, 0, sizeof(*es)); + + il_log(LOG_DEBUG, " creating event store for id %s\n", job_id_s); + + es->job_id_s = strdup(job_id_s); + es->event_file_name = jobid2eventfile(job_id_s); + es->control_file_name = jobid2controlfile(job_id_s); + + if(pthread_rwlock_init(&es->commit_lock, NULL)) + abort(); + if(pthread_rwlock_init(&es->use_lock, NULL)) + abort(); + + return(es); +} + + +static +int +event_store_lock_ro(struct event_store *es) +{ + assert(es != NULL); + + if(pthread_rwlock_rdlock(&es->commit_lock)) + abort(); + + return(0); +} + + +static +int +event_store_lock(struct event_store *es) +{ + assert(es != NULL); + + if(pthread_rwlock_wrlock(&es->commit_lock)) + abort(); + + return(0); +} + + +static +int +event_store_unlock(struct event_store *es) +{ + assert(es != NULL); + + if(pthread_rwlock_unlock(&es->commit_lock)) + abort(); + return(0); +} + + +static +int +event_store_read_ctl(struct event_store *es) +{ + FILE *ctl_file; + + assert(es != NULL); + + event_store_lock(es); + if((ctl_file = fopen(es->control_file_name, "r")) == NULL) { + /* no control file, new event file */ + es->last_committed_ls = 0; + es->last_committed_bs = 0; + } else { + /* read last seen and last committed counts */ + fscanf(ctl_file, "%*s\n%ld\n%ld\n", + &es->last_committed_ls, + &es->last_committed_bs); + fclose(ctl_file); + } + event_store_unlock(es); + + return(0); +} + + +static +int +event_store_write_ctl(struct event_store *es) +{ + FILE *ctl; + + assert(es != NULL); + + ctl = fopen(es->control_file_name, "w"); + if(ctl == NULL) { + set_error(IL_SYS, errno, "event_store_write_ctl: error opening control file"); + return(-1); + } + + if(fprintf(ctl, "%s\n%ld\n%ld\n", + es->job_id_s, + es->last_committed_ls, + es->last_committed_bs) < 0) { + set_error(IL_SYS, errno, "event_store_write_ctl: error writing control record"); + return(-1); + } + + if(fclose(ctl) < 0) { + set_error(IL_SYS, errno, "event_store_write_ctl: error closing control file"); + return(-1); + } + + return(0); +} + + +/* + * event_store_qurantine() + * - rename damaged event store file + * - essentially does the same actions as cleanup, but the event store + * does not have to be empty + * returns 0 on success, -1 on error + */ +static +int +event_store_quarantine(struct event_store *es) +{ + int num; + char newname[MAXPATHLEN+1]; + + /* find available qurantine name */ + /* we give it at most 1024 tries */ + for(num = 0; num < 1024; num++) { + struct stat st; + + snprintf(newname, MAXPATHLEN, "%s.quarantine.%d", es->event_file_name, num); + newname[MAXPATHLEN] = 0; + if(stat(newname, &st) < 0) { + if(errno == ENOENT) { + /* file not found */ + break; + } else { + /* some other error with name, probably permanent */ + set_error(IL_SYS, errno, "event_store_qurantine: error looking for qurantine filename"); + return(-1); + + } + } else { + /* the filename is used already */ + } + } + if(num >= 1024) { + /* new name not found */ + /* XXX - is there more suitable error? */ + set_error(IL_SYS, ENOSPC, "event_store_quarantine: exhausted number of retries looking for quarantine filename"); + return(-1); + } + + /* actually rename the file */ + il_log(LOG_DEBUG, " renaming damaged event file from %s to %s\n", + es->event_file_name, newname); + if(rename(es->event_file_name, newname) < 0) { + set_error(IL_SYS, errno, "event_store_quarantine: error renaming event file"); + return(-1); + } + + /* clear the counters */ + es->last_committed_ls = 0; + es->last_committed_bs = 0; + es->offset = 0; + + return(0); +} + + +/* + * event_store_recover() + * - recover after restart or catch up when events missing in IPC + * - if offset > 0, read everything behind it + * - if offset == 0, read everything behind min(last_committed_bs, last_committed_es) + */ +int +event_store_recover(struct event_store *es) +{ + struct event_queue *eq_l = NULL, *eq_b = NULL; + struct server_msg *msg; + il_http_message_t hmsg; + char *event_s; + int fd, ret; + long last; + FILE *ef; + struct flock efl; + char err_msg[128]; + struct stat stbuf; + + assert(es != NULL); + +#if defined(IL_NOTIFICATIONS) + /* destination queue has to be found for each message separately */ +#else + /* find bookkepping server queue */ + eq_b = queue_list_get(es->job_id_s); + if(eq_b == NULL) + return(-1); +#endif + +#if !defined(IL_NOTIFICATIONS) + /* get log server queue */ + eq_l = queue_list_get(NULL); +#endif + + event_store_lock(es); + + il_log(LOG_DEBUG, " reading events from %s\n", es->event_file_name); + + /* open event file */ + ef = fopen(es->event_file_name, "r"); + if(ef == NULL) { + snprintf(err_msg, sizeof(err_msg), + "event_store_recover: error opening event file %s", + es->event_file_name); + set_error(IL_SYS, errno, err_msg); + event_store_unlock(es); + return(-1); + } + + /* lock the file for reading (we should not read while dglogd is writing) */ + fd = fileno(ef); + efl.l_type = F_RDLCK; + efl.l_whence = SEEK_SET; + efl.l_start = 0; + efl.l_len = 0; + if(fcntl(fd, F_SETLKW, &efl) < 0) { + snprintf(err_msg, sizeof(err_msg), + "event_store_recover: error locking event file %s", + es->event_file_name); + set_error(IL_SYS, errno, err_msg); + event_store_unlock(es); + fclose(ef); + return(-1); + } + + /* check the file modification time and size to avoid unnecessary operations */ + memset(&stbuf, 0, sizeof(stbuf)); + if(fstat(fd, &stbuf) < 0) { + il_log(LOG_ERR, " could not stat event file %s: %s\n", es->event_file_name, strerror(errno)); + fclose(ef); + event_store_unlock(es); + return -1; + } else { + if((es->offset == stbuf.st_size) && (es->last_modified == stbuf.st_mtime)) { + il_log(LOG_DEBUG, " event file not modified since last visit, skipping\n"); + fclose(ef); + event_store_unlock(es); + return(0); + } + } + + while(1) { /* try, try, try */ + + /* get the position in file to be sought */ + if(es->offset) + last = es->offset; + else { + last = es->last_committed_bs; + } + + il_log(LOG_DEBUG, " setting starting file position to %ld\n", last); + il_log(LOG_DEBUG, " bytes sent to destination: %d\n", es->last_committed_bs); + + if(last > 0) { + int c; + + /* skip all committed or already enqueued events */ + /* be careful - check, if the offset really points to the + beginning of event string */ + if(fseek(ef, last - 1, SEEK_SET) < 0) { + set_error(IL_SYS, errno, "event_store_recover: error setting position for read"); + event_store_unlock(es); + fclose(ef); + return(-1); + } + /* the last enqueued event MUST end with \n */ + if((c=fgetc(ef)) != '\n') { + /* Houston, we have got a problem */ + il_log(LOG_WARNING, + " file position %ld does not point at the beginning of event string, backing off!\n", + last); + /* now, where were we? */ + if(es->offset) { + /* next try will be with + last_commited_bs */ + es->offset = 0; + } else { + /* this is really weird... back off completely */ + es->last_committed_ls = es->last_committed_bs = 0; + } + } else { + /* OK, break out of the loop */ + break; + } + } else { + /* this breaks out of the loop, we are starting at + * the beginning of file + */ + if(fseek(ef, 0, SEEK_SET) < 0) { + set_error(IL_SYS, errno, "event_store_recover: error setting position for read"); + event_store_unlock(es); + fclose(ef); + return(-1); + } + break; + } + } + + /* enqueue all remaining events */ + ret = 1; + msg = NULL; + while(read_event_string(ef, &hmsg) >= 0) { + + /* last holds the starting position of event_s in file */ + il_log(LOG_DEBUG, " reading event at %ld\n", last); + + /* break from now on means there was some error */ + ret = -1; + + /* create message for server */ + msg = server_msg_create((il_octet_string_t*)&hmsg, last); + if(msg == NULL) { + il_log(LOG_ALERT, " event file corrupted! I will try to move it to quarantine (ie. rename it).\n"); + /* actually do not bother if quarantine succeeded or not - we could not do more */ + event_store_quarantine(es); + fclose(ef); + event_store_unlock(es); + return(-1); + } + msg->es = es; + + /* first enqueue to the LS */ + if(!bs_only && (last >= es->last_committed_ls)) { + + il_log(LOG_DEBUG, " queueing event at %ld to server %s\n", last, eq_l->dest_name); + +#if !defined(IL_NOTIFICATIONS) + if(enqueue_msg(eq_l, msg) < 0) + break; +#endif + } + +#ifdef IL_NOTIFICATIONS + eq_b = queue_list_get(msg->dest); +#endif + + /* now enqueue to the BS, if neccessary */ + if((eq_b != eq_l) && + (last >= es->last_committed_bs)) { + + il_log(LOG_DEBUG, " queueing event at %ld to server %s\n", last, eq_b->dest_name); + + if(enqueue_msg(eq_b, msg) < 0) + break; + } + server_msg_free(msg); + msg = NULL; + + /* now last is also the offset behind the last successfully queued event */ + last = ftell(ef); + + /* ret == 0 means EOF or incomplete event found */ + ret = 0; + + } /* while */ + + /* due to this little assignment we had to lock the event_store for writing */ + es->offset = last; + es->last_modified = stbuf.st_mtime; + il_log(LOG_DEBUG, " event store offset set to %ld\n", last); + + if(msg) + server_msg_free(msg); + + fclose(ef); + il_log(LOG_DEBUG, " finished reading events with %d\n", ret); + + event_store_unlock(es); + return(ret); +} + + +/* + * event_store_sync() + * - check the position of event and fill holes from file + * - return 1 if the event is new, + * 0 if it was seen before, + * -1 if there was an error + */ +int +event_store_sync(struct event_store *es, long offset) +{ + int ret; + + assert(es != NULL); + + /* all events are actually read from file, the event on socket + * is ignored and serves just to notify us about file change + */ + ret = event_store_recover(es); + ret = (ret < 0) ? ret : 0; + return(ret); +} + + +int +event_store_next(struct event_store *es, long offset, int len) +{ + assert(es != NULL); + + /* offsets are good only to detect losses (differences between socket and file), + which is not possible now */ + return 0; +} + + +/* + * event_store_commit() + * + */ +int +event_store_commit(struct event_store *es, int len, int ls) +{ + assert(es != NULL); + + event_store_lock(es); + + if(ls) + es->last_committed_ls += len; + else { + es->last_committed_bs += len; + if (bs_only) es->last_committed_ls += len; + } + + if(event_store_write_ctl(es) < 0) { + event_store_unlock(es); + return(-1); + } + + event_store_unlock(es); + + + return(0); +} + + +/* + * event_store_clean() + * - remove the event files (event and ctl), if they are not needed anymore + * - returns 0 if event_store is in use, 1 if it was removed and -1 on error + * + * Q: How do we know that we can safely remove the files? + * A: When all events from file have been committed both by LS and BS. + */ +static +int +event_store_clean(struct event_store *es) +{ + long last; + int fd; + FILE *ef; + struct flock efl; + + assert(es != NULL); + + /* prevent sender threads from updating */ + event_store_lock(es); + + il_log(LOG_DEBUG, " trying to cleanup event store %s\n", es->job_id_s); + il_log(LOG_DEBUG, " bytes sent to logging server: %d\n", es->last_committed_ls); + il_log(LOG_DEBUG, " bytes sent to bookkeeping server: %d\n", es->last_committed_bs); + + /* preliminary check to avoid opening event file */ + /* if the positions differ, some events still have to be sent */ + if(es->last_committed_ls != es->last_committed_bs) { + event_store_unlock(es); + il_log(LOG_DEBUG, " not all events sent, cleanup aborted\n"); + return(0); + } + + /* the file can only be removed when all the events were succesfully sent + (ie. committed both by LS and BS */ + /* That also implies that the event queues are 'empty' at the moment. */ + ef = fopen(es->event_file_name, "r+"); + if(ef == NULL) { + /* if we can not open the event store, it is an error and the struct should be removed */ + /* XXX - is it true? */ + event_store_unlock(es); + il_log(LOG_ERR, " event_store_clean: error opening event file: %s\n", strerror(errno)); + return(1); + } + + fd = fileno(ef); + + /* prevent local-logger from writing into event file */ + efl.l_type = F_WRLCK; + efl.l_whence = SEEK_SET; + efl.l_start = 0; + efl.l_len = 0; + if(fcntl(fd, F_SETLK, &efl) < 0) { + il_log(LOG_DEBUG, " could not lock event file, cleanup aborted\n"); + fclose(ef); + event_store_unlock(es); + if(errno != EACCES && + errno != EAGAIN) { + set_error(IL_SYS, errno, "event_store_clean: error locking event file"); + return(-1); + } + return(0); + } + + /* now the file should not contain partially written event, so it is safe + to get offset behind last event by seeking the end of file */ + if(fseek(ef, 0, SEEK_END) < 0) { + set_error(IL_SYS, errno, "event_store_clean: error seeking the end of file"); + event_store_unlock(es); + fclose(ef); + return(-1); + } + + last = ftell(ef); + il_log(LOG_DEBUG, " total bytes in file: %d\n", last); + + if(es->last_committed_ls < last) { + fclose(ef); + event_store_unlock(es); + il_log(LOG_DEBUG, " events still waiting in queue, cleanup aborted\n"); + return(0); + } else if( es->last_committed_ls > last) { + il_log(LOG_WARNING, " warning: event file seems to shrink!\n"); + /* XXX - in that case we can not continue because there may be + some undelivered events referring to that event store */ + fclose(ef); + event_store_unlock(es); + return(0); + } + + /* now we are sure that all events were sent and the event queues are empty */ + il_log(LOG_INFO, " removing event file %s\n", es->event_file_name); + + /* remove the event file */ + unlink(es->event_file_name); + unlink(es->control_file_name); + + /* clear the counters */ + es->last_committed_ls = 0; + es->last_committed_bs = 0; + es->offset = 0; + + /* unlock the event_store even if it is going to be removed */ + event_store_unlock(es); + + /* close the event file (that unlocks it as well) */ + fclose(ef); + + /* indicate that it is safe to remove this event_store */ + return(1); +} + + +/* -------------------------------- + * event store management functions + * -------------------------------- + */ +struct event_store * +event_store_find(char *job_id_s) +{ + struct event_store_list *q, *p; + struct event_store *es; + + if(pthread_rwlock_wrlock(&store_list_lock)) { + abort(); + } + + es = NULL; + + q = NULL; + p = store_list; + + while(p) { + if(strcmp(p->es->job_id_s, job_id_s) == 0) { + es = p->es; + if(pthread_rwlock_rdlock(&es->use_lock)) + abort(); + if(pthread_rwlock_unlock(&store_list_lock)) + abort(); + return(es); + } + + q = p; + p = p->next; + } + + es = event_store_create(job_id_s); + if(es == NULL) { + if(pthread_rwlock_unlock(&store_list_lock)) + abort(); + return(NULL); + } + + p = malloc(sizeof(*p)); + if(p == NULL) { + set_error(IL_NOMEM, ENOMEM, "event_store_find: no room for new event store"); + if(pthread_rwlock_unlock(&store_list_lock)) + abort(); + return(NULL); + } + + p->next = store_list; + store_list = p; + + p->es = es; + + if(pthread_rwlock_rdlock(&es->use_lock)) + abort(); + + if(pthread_rwlock_unlock(&store_list_lock)) + abort(); + + return(es); +} + + +int +event_store_release(struct event_store *es) +{ + assert(es != NULL); + + if(pthread_rwlock_unlock(&es->use_lock)) + abort(); + il_log(LOG_DEBUG, " released lock on %s\n", es->job_id_s); + return(0); +} + + +event_store_from_file(char *filename) +{ + struct event_store *es; + FILE *event_file; + char *job_id_s = NULL, *p; + il_http_message_t hmsg; + int ret; + + il_log(LOG_INFO, " attaching to event file: %s\n", filename); + + if(strstr(filename, "quarantine") != NULL) { + il_log(LOG_INFO, " file name belongs to quarantine, not touching that.\n"); + return(0); + } + + event_file = fopen(filename, "r"); + if(event_file == NULL) { + set_error(IL_SYS, errno, "event_store_from_file: error opening event file"); + return(-1); + } + ret = read_event_string(event_file, &hmsg); + fclose(event_file); + if(ret < 0) + return(0); + + /* get id aka dest */ + job_id_s = hmsg.host; + + il_log(LOG_DEBUG, " message dest: '%s'\n", job_id_s); + if(job_id_s == NULL) { + il_log(LOG_NOTICE, " skipping file, could not parse event\n"); + ret = 0; + goto out; + } + + es=event_store_find(job_id_s); + + if(es == NULL) { + ret = -1; + goto out; + } + + if((es->last_committed_ls == 0) && + (es->last_committed_bs == 0) && + (es->offset == 0)) { + ret = event_store_read_ctl(es); + } else + ret = 0; + + event_store_release(es); + +out: + if(hmsg.data) free(hmsg.data); + if(job_id_s) free(job_id_s); + return(ret); +} + + +int +event_store_init(char *prefix) +{ + if(file_prefix == NULL) { + file_prefix = strdup(prefix); + store_list = NULL; + } + + /* read directory and get a list of event files */ + { + int len; + + char *p, *dir; + DIR *event_dir; + struct dirent *entry; + + + /* get directory name */ + p = strrchr(file_prefix, '/'); + if(p == NULL) { + dir = strdup("."); + p = ""; + len = 0; + } else { + *p = '\0'; + dir = strdup(file_prefix); + *p++ = '/'; + len = strlen(p); + } + + event_dir = opendir(dir); + if(event_dir == NULL) { + free(dir); + set_error(IL_SYS, errno, "event_store_init: error opening event directory"); + return(-1); + } + + while((entry=readdir(event_dir))) { + char *s; + + /* skip all files that do not match prefix */ + if(strncmp(entry->d_name, p, len) != 0) + continue; + + /* skip all control files */ + if((s=strstr(entry->d_name, ".ctl")) != NULL && + s[4] == '\0') + continue; + + s = malloc(strlen(dir) + strlen(entry->d_name) + 2); + if(s == NULL) { + free(dir); + set_error(IL_NOMEM, ENOMEM, "event_store_init: no room for file name"); + return(-1); + } + + *s = '\0'; + strcat(s, dir); + strcat(s, "/"); + strcat(s, entry->d_name); + + if(event_store_from_file(s) < 0) { + free(dir); + free(s); + closedir(event_dir); + return(-1); + } + + free(s); + } + closedir(event_dir); + + /* one more pass - this time remove stale .ctl files */ + event_dir = opendir(dir); + if(event_dir == NULL) { + free(dir); + set_error(IL_SYS, errno, "event_store_init: error opening event directory"); + return(-1); + } + + while((entry=readdir(event_dir))) { + char *s; + + /* skip all files that do not match prefix */ + if(strncmp(entry->d_name, p, len) != 0) + continue; + + /* find all control files */ + if((s=strstr(entry->d_name, ".ctl")) != NULL && + s[4] == '\0') { + char *ef; + struct stat st; + + /* is there corresponding event file? */ + ef = malloc(strlen(dir) + strlen(entry->d_name) + 2); + if(ef == NULL) { + free(dir); + set_error(IL_NOMEM, ENOMEM, "event_store_init: no room for event file name"); + return(-1); + } + + s[0] = 0; + *ef = '\0'; + strcat(ef, dir); + strcat(ef, "/"); + strcat(ef, entry->d_name); + s[0] = '.'; + + if(stat(ef, &st) == 0) { + /* something is there */ + /* XXX - it could be something else than event file, but do not bother now */ + } else { + /* could not stat file, remove ctl */ + strcat(ef, s); + il_log(LOG_DEBUG, " removing stale file %s\n", ef); + if(unlink(ef)) + il_log(LOG_ERR, " could not remove file %s: %s\n", ef, strerror(errno)); + + } + free(ef); + + } + } + closedir(event_dir); + free(dir); + } + + return(0); +} + + +int +event_store_recover_all() +{ + struct event_store_list *sl; + + + if(pthread_rwlock_rdlock(&store_list_lock)) + abort(); + + /* recover all event stores */ + sl = store_list; + while(sl != NULL) { + + /* recover this event store */ + /* no need to lock use_lock in event_store, the store_list_lock is in place */ + if(event_store_recover(sl->es) < 0) { + il_log(LOG_ERR, " error recovering event store %s:\n %s\n", sl->es->event_file_name, error_get_msg()); + clear_error(); + } + sl = sl->next; + } + + if(pthread_rwlock_unlock(&store_list_lock)) + abort(); + + return(0); +} + + +#if 0 +int +event_store_remove(struct event_store *es) +{ + struct event_store_list *p, **q; + + assert(es != NULL); + + switch(event_store_clean(es)) { + case 0: + il_log(LOG_DEBUG, " event store not removed, still used\n"); + return(0); + + case 1: + if(pthread_rwlock_wrlock(&store_list_lock) < 0) { + set_error(IL_SYS, errno, " event_store_remove: error locking event store list"); + return(-1); + } + + p = store_list; + q = &store_list; + + while(p) { + if(p->es == es) { + (*q) = p->next; + event_store_free(es); + free(p); + break; + } + q = &(p->next); + p = p->next; + } + + if(pthread_rwlock_unlock(&store_list_lock) < 0) { + set_error(IL_SYS, errno, " event_store_remove: error unlocking event store list"); + return(-1); + } + return(1); + + default: + return(-1); + } + /* not reached */ + return(0); +} +#endif + +int +event_store_cleanup() +{ + struct event_store_list *sl; + struct event_store_list *slnext; + struct event_store_list **prev; + + /* try to remove event files */ + + if(pthread_rwlock_wrlock(&store_list_lock)) + abort(); + + sl = store_list; + prev = &store_list; + + while(sl != NULL) { + int ret; + + slnext = sl->next; + + /* one event store at time */ + ret = pthread_rwlock_trywrlock(&sl->es->use_lock); + if(ret == EBUSY) { + il_log(LOG_DEBUG, " event_store %s is in use by another thread\n", + sl->es->job_id_s); + sl = slnext; + continue; + } else if (ret < 0) + abort(); + + switch(event_store_clean(sl->es)) { + + case 1: + /* remove this event store */ + (*prev) = slnext; + event_store_free(sl->es); + free(sl); + break; + + case -1: + il_log(LOG_ERR, " error removing event store %s (file %s):\n %s\n", + sl->es->job_id_s, sl->es->event_file_name, error_get_msg()); + /* event_store_release(sl->es); */ + clear_error(); + /* go on to the next */ + + default: + event_store_release(sl->es); + prev = &(sl->next); + break; + } + + sl = slnext; + } + + if(pthread_rwlock_unlock(&store_list_lock)) + abort(); + + return(0); +} + diff --git a/org.glite.lb.logger/src/http.c b/org.glite.lb.logger/src/http.c new file mode 100644 index 0000000..2480872 --- /dev/null +++ b/org.glite.lb.logger/src/http.c @@ -0,0 +1,214 @@ +#ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#include +#include + +#include "interlogd.h" + + +int +parse_request(const char *s, il_http_message_t *msg) +{ + if(!strncasecmp(s, "HTTP", 4)) { + msg->msg_type = IL_HTTP_REPLY; + } else if(!strncasecmp(s, "POST", 4)) { + msg->msg_type = IL_HTTP_POST; + } else if(!strncasecmp(s, "GET", 3)) { + msg->msg_type = IL_HTTP_GET; + } else { + msg->msg_type = IL_HTTP_OTHER; + } + if(msg->msg_type == IL_HTTP_REPLY) { + char *p = strchr(s, ' '); + + if(!p) goto parse_end; + p++; + msg->reply_code=atoi(p); + p = strchr(p, ' '); + if(!p) goto parse_end; + p++; + msg->reply_string = strdup(p); + + parse_end: + ; + } +} + + +int +parse_header(const char *s, il_http_message_t *msg) +{ + if(!strncasecmp(s, "Content-Length:", 15)) { + msg->content_length = atoi(s + 15); + } else if(!strncasecmp(s, "Host:", 5)) { + const char *p = s + 4; + while(*++p == ' '); /* skip spaces */ + msg->host = strdup(p); + } + return(0); +} + + +#define DEFAULT_CHUNK_SIZE 1024 + +// read what is available and parse what can be parsed +// returns the result of read operation of the underlying connection, +// ie. the number of bytes read or error code +int +receive_http(void *user_data, int (*reader)(void *, char *, const int), il_http_message_t *msg) +{ + static enum { NONE, IN_REQUEST, IN_HEADERS, IN_BODY } state = NONE; + int len, alen, clen, i, buffer_free, min_buffer_free = DEFAULT_CHUNK_SIZE; + char *buffer, *p, *s, *cr; + + memset(msg, 0, sizeof(*msg)); + // msg->data = NULL; + // msg->len = 0; + state = IN_REQUEST; + alen = 0; + buffer = NULL; + buffer_free = 0; + p = NULL; + s = NULL; + + do { + /* p - first empty position in buffer + alen - size of allocated buffer + len - number of bytes received in last read + s - points behind last scanned CRLF or at buffer start + buffer_free = alen - (p - buffer) + */ + + /* prepare at least chunk_size bytes for next data */ + if(buffer_free < min_buffer_free) { + char *n; + + alen += min_buffer_free; + n = realloc(buffer, alen); + if(n == NULL) { + free(buffer); + set_error(IL_NOMEM, ENOMEM, "read_event: no room for event"); + return(-1); + } + buffer_free += min_buffer_free; + p = n + (p - buffer); + s = n + (s - buffer); + buffer = n; + } + + if(buffer_free > 0) { + len = (*reader)(user_data, p, buffer_free); + if(len < 0) { + // error + free(buffer); + // set_error(IL_SYS, errno, "receive_http: error reading data"); + return -1; + } else if(len == 0) { + // EOF + free(buffer); + set_error(IL_PROTO, errno, "receive_http: error reading data - premature EOF"); + return -1; + } + buffer_free -= len; + p+= len; + } + + + switch(state) { + + // parse buffer, look for CRLFs + // s - start scan position + // p - start of current token + // cr - current CRLF position + + case IN_REQUEST: + if((s < p - 1) && + (cr = (char*)memchr(s, '\r', p - s - 1)) && + (cr[1] == '\n')) { + *cr = 0; + parse_request(s, msg); + *cr = '\r'; + // change state + state = IN_HEADERS; + // start new tokens (cr < p - 1 -> s < p + 1 <-> s <= p) + s = cr + 2; + } else { + break; + } + + case IN_HEADERS: + while((state != IN_BODY) && + (s < p - 1) && + (cr = (char*)memchr(s, '\r', p - s - 1)) && + (cr[1] == '\n')) { + if(s == cr) { /* do not consider request starting with CRLF */ + // found CRLFCRLF + state = IN_BODY; + } else { + *cr = 0; + parse_header(s, msg); + *cr = '\r'; + } + // next scan starts after CRLF + s = cr + 2; + } + if(state == IN_BODY) { + // we found body + // content-length should be set at the moment + if(msg->content_length > 0) { + int need_free = msg->content_length - (p - s); + char *n; + + alen += need_free - buffer_free + 1; + n = realloc(buffer, alen); + if(n == NULL) { + free(buffer); + set_error(IL_NOMEM, ENOMEM, "read_event: no room for event"); + return(-1); + } + buffer_free = need_free; + min_buffer_free = 0; + p = n + (p - buffer); + s = n + (s - buffer); + buffer = n; + } else { + // report error + free(buffer); + set_error(IL_PROTO, EINVAL, "receive_http: error reading data - no content length specified\n"); + return -1; + } + } + break; + + case IN_BODY: + if(buffer_free == 0) { + // finished reading + *p = 0; + state = NONE; + } + break; + } + } while(state != NONE); + + msg->data = buffer; + msg->len = p - buffer; + + return 0; +} diff --git a/org.glite.lb.logger/src/il_error.c b/org.glite.lb.logger/src/il_error.c index 1fe9bb9..b9a5647 100644 --- a/org.glite.lb.logger/src/il_error.c +++ b/org.glite.lb.logger/src/il_error.c @@ -1,4 +1,21 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include @@ -13,16 +30,10 @@ extern void _start (void), etext (void); #endif -/* XXX DK: */ -#include // SSL header file - #include "glite/security/glite_gss.h" - #include "il_error.h" -extern int log_level; - static pthread_key_t err_key; static int IL_ERR_MSG_LEN = 1024; @@ -31,6 +42,8 @@ static void error_key_delete(void *err) { + if(((struct error_inf*)err)->msg) + free(((struct error_inf*)err)->msg); free(err); } @@ -56,7 +69,7 @@ error_get_err () int -init_errors(int level) +init_errors() { static pthread_once_t error_once = PTHREAD_ONCE_INIT; struct error_inf *err; @@ -80,9 +93,6 @@ init_errors(int level) if(err->msg == NULL) return(-1); - if(level) - log_level = level; - #ifdef LB_PROF monstartup((u_long)&_start, (u_long)&etext); #endif @@ -110,11 +120,6 @@ set_error(int code, long minor, char *msg) snprintf(err->msg, IL_ERR_MSG_LEN, "%s: %s", msg, hstrerror(err->code_min)); break; - /* XXX DK: je tahle hodnota k necemu potreba? */ - case IL_AUTH: - snprintf(err->msg, IL_ERR_MSG_LEN, "%s: %s", msg, ERR_error_string(err->code_min, NULL)); - break; - case IL_DGGSS: switch(err->code_min) { diff --git a/org.glite.lb.logger/src/il_error.h b/org.glite.lb.logger/src/il_error.h deleted file mode 100644 index 120e7ed..0000000 --- a/org.glite.lb.logger/src/il_error.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef IL_ERROR_H -#define IL_ERROR_H - -#ident "$Header$" - -#include - -enum err_code_maj { /* minor = */ - IL_OK, /* 0 */ - IL_SYS, /* errno */ - IL_NOMEM, /* ENOMEM */ - IL_AUTH, /* 0 (SSL error) */ - IL_PROTO, /* LB_* */ - IL_LBAPI, /* dgLBErrCode */ - IL_DGGSS, /* EDG_WLL_GSS_* */ - IL_HOST /* h_errno */ -}; - -struct error_inf { - int code_maj; - long code_min; - char *msg; -}; - -int init_errors(int); -int set_error(int, long, char *); -int clear_error(); -int error_get_maj(); -long error_get_min(); -char *error_get_msg(); - -int il_log(int, char *, ...); - -#endif diff --git a/org.glite.lb.logger/src/il_master.c b/org.glite.lb.logger/src/il_master.c index e394e5a..2cc1018 100644 --- a/org.glite.lb.logger/src/il_master.c +++ b/org.glite.lb.logger/src/il_master.c @@ -1,10 +1,28 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include #include +#include -#include "glite/wmsutils/jobid/cjobid.h" +#include "glite/jobid/cjobid.h" #include "glite/lb/context.h" #include "glite/lb/events_parse.h" #include "glite/lb/il_string.h" @@ -15,66 +33,21 @@ #include "glite/lb/lb_perftest.h" #endif -static int -cmp_jobid(struct server_msg *msg, void *data) -{ - char *job_id_s = (char*)data; - return strcmp(msg->job_id_s, job_id_s) == 0; -} - -static -int -cmp_jobid_set_exp(struct server_msg *msg, void *data) -{ - struct server_msg *m = (struct server_msg *)data; - - if(strcmp(msg->job_id_s, m->job_id_s) == 0) { - msg->expires = m->expires; - } - return 0; -} - - -int enqueue_msg(struct event_queue *eq, struct server_msg *msg) { -#if defined(IL_NOTIFICATIONS) - struct event_queue *eq_known; - - /* now we have a new event with possibly changed destination, - so check for the already known destination and possibly move - events from the original output queue to a new one */ - eq_known = notifid_map_get_dest(msg->job_id_s); - if(eq != eq_known) { - /* client has changed delivery address for this notification */ - if(notifid_map_set_dest(msg->job_id_s, eq) < 0) - return(-1); - /* move all events with this notif_id from eq_known to eq */ - if(eq_known != NULL) { - event_queue_move_events(eq_known, eq, cmp_jobid, msg->job_id_s); - /* XXX - we should kill the old queue too */ - } - } - - /* if the expiration changed, set new one */ - if(msg->expires != notifid_map_get_expiration(msg->job_id_s)) { - notifid_map_set_expiration(msg->job_id_s, msg->expires); - /* set expiration for all events with this notif id */ - event_queue_move_events(eq, NULL, cmp_jobid_set_exp, msg); - } -#endif + int ret; /* fire thread to take care of this queue */ - if(event_queue_create_thread(eq) < 0) + if(event_queue_create_thread(eq) < 0) return(-1); - + #if defined(IL_NOTIFICATIONS) - /* if there are no data to send, do not send anything + /* if there are no data to send, do not send anything (messsage was just to change the delivery address) */ /* CORRECTION - let the message pass through the output queue to commit it properly and keep event_store in sync */ - /* if(msg->len == 0) + /* if(msg->len == 0) return(0); */ #endif @@ -82,18 +55,18 @@ enqueue_msg(struct event_queue *eq, struct server_msg *msg) event_queue_cond_lock(eq); /* insert new event */ - if(event_queue_insert(eq, msg) < 0) { + if((ret = event_queue_insert(eq, msg)) < 0) { event_queue_cond_unlock(eq); - return(-1); + return ret; } - + /* signal thread that we have a new message */ event_queue_signal(eq); /* allow thread to continue */ event_queue_cond_unlock(eq); - return(0); + return ret; } @@ -103,7 +76,7 @@ pthread_cond_t flush_cond = PTHREAD_COND_INITIALIZER; #endif /* INTERLOGD_FLUSH */ #ifdef INTERLOGD_HANDLE_CMD -static +static int parse_cmd(char *event, char **job_id_s, long *receipt, int *timeout) { @@ -125,10 +98,11 @@ parse_cmd(char *event, char **job_id_s, long *receipt, int *timeout) continue; } if(strncmp(token, "DG.COMMAND", r - token) == 0) { -#if defined(INTERLOGD_FLUSH) +#if defined(INTERLOGD_FLUSH) if(strcmp(++r, "\"flush\"")) { #endif - il_log(LOG_WARNING, " command %s not implemented\n", r); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, "command %s not implemented", + r); ret = -1; continue; #if defined(INTERLOGD_FLUSH) @@ -136,7 +110,7 @@ parse_cmd(char *event, char **job_id_s, long *receipt, int *timeout) #endif } else if(strncmp(token, "DG.JOBID", r - token) == 0) { char *p; - + r += 2; /* skip =" */ p = index(r, '"'); if(p == NULL) { ret = -1; continue; } @@ -147,7 +121,7 @@ parse_cmd(char *event, char **job_id_s, long *receipt, int *timeout) } else if(strncmp(token, "DG.LLLID", r - token) == 0) { sscanf(++r, "%ld", receipt); } - + } return(0); } @@ -159,8 +133,8 @@ parse_cmd(char *event, char **job_id_s, long *receipt, int *timeout) * -1 - failure */ -static -int +static +int handle_cmd(il_octet_string_t *event, long offset) { char *job_id_s; @@ -172,15 +146,15 @@ handle_cmd(il_octet_string_t *event, long offset) struct timeval tv; /* parse command */ - if(parse_cmd(event->data, &job_id_s, &receipt, &timeout) < 0) + if(parse_cmd(event->data, &job_id_s, &receipt, &timeout) < 0) return(0); #if defined(INTERLOGD_FLUSH) - il_log(LOG_DEBUG, " received FLUSH command\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, "received FLUSH command"); /* catchup with all neccessary event files */ if(job_id_s) { - struct event_store *es = event_store_find(job_id_s); + struct event_store *es = event_store_find(job_id_s, NULL); if(es == NULL) { goto cmd_error; @@ -190,15 +164,16 @@ handle_cmd(il_octet_string_t *event, long offset) no need to lock the event_store at all */ event_store_release(es); if(result < 0) { - il_log(LOG_ERR, " error trying to catch up with event file: %s\n", - error_get_msg()); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + " error trying to catch up with event file: %s", + error_get_msg()); clear_error(); } - } else + } else /* this call does not fail :-) */ event_store_recover_all(); - il_log(LOG_DEBUG, " alerting threads to report status\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, " alerting threads to report status"); /* prevent threads from reporting too early */ if(pthread_mutex_lock(&flush_lock) < 0) { @@ -254,11 +229,13 @@ handle_cmd(il_octet_string_t *event, long offset) while(num_replies < num_threads) { int ret; if((ret=pthread_cond_timedwait(&flush_cond, &flush_lock, &endtime)) < 0) { - il_log(LOG_ERR, " error waiting for thread reply: %s\n", strerror(errno)); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + " error waiting for thread reply: %s", + strerror(errno)); result = (ret == ETIMEDOUT) ? 0 : -1; break; } - + /* collect results from reporting threads */ if(job_id_s) { /* find appropriate queue */ @@ -269,7 +246,7 @@ handle_cmd(il_octet_string_t *event, long offset) if(eq->flushing == 2) { eq->flushing = 0; num_replies++; - result = ((result == 1) || (eq->flush_result < 0)) ? + result = ((result == 1) || (eq->flush_result < 0)) ? eq->flush_result : result; } event_queue_cond_unlock(eq); @@ -282,8 +259,10 @@ handle_cmd(il_octet_string_t *event, long offset) if(eq->flushing == 2) { eq->flushing = 0; num_replies++; - il_log(LOG_DEBUG, " thread reply: %d\n", eq->flush_result); - result = ((result == 1) || (eq->flush_result < 0)) ? + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " thread reply: %d", + eq->flush_result); + result = ((result == 1) || (eq->flush_result < 0)) ? eq->flush_result : result; } event_queue_cond_unlock(eq); @@ -297,7 +276,7 @@ handle_cmd(il_octet_string_t *event, long offset) if(eq->flushing == 2) { eq->flushing = 0; num_replies++; - result = ((result == 1) || (eq->flush_result < 0)) ? + result = ((result == 1) || (eq->flush_result < 0)) ? eq->flush_result : result; } event_queue_cond_unlock(eq); @@ -305,7 +284,7 @@ handle_cmd(il_octet_string_t *event, long offset) } /* prevent deadlock in next flush */ - if(pthread_mutex_unlock(&flush_lock) < 0) + if(pthread_mutex_unlock(&flush_lock) < 0) abort(); @@ -320,8 +299,10 @@ handle_cmd(il_octet_string_t *event, long offset) } if(job_id_s) free(job_id_s); result = send_confirmation(receipt, result); - if(result <= 0) - il_log(LOG_ERR, "handle_cmd: error sending status: %s\n", error_get_msg()); + if(result <= 0) + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + "handle_cmd: error sending status: %s", + error_get_msg()); return(1); @@ -335,10 +316,10 @@ cmd_error: #endif /* INTERLOGD_HANDLE_CMD */ -static +static int handle_msg(il_octet_string_t *event, long offset) -{ +{ struct server_msg *msg = NULL; #if !defined(IL_NOTIFICATIONS) struct event_queue *eq_l; @@ -350,25 +331,31 @@ handle_msg(il_octet_string_t *event, long offset) /* convert event to message for server */ if((msg = server_msg_create(event, offset)) == NULL) { - il_log(LOG_ERR, " handle_msg: error parsing event '%s':\n %s\n", event, error_get_msg()); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, + " handle_msg: error parsing event '%s': %s", + event, error_get_msg()); return(0); } - + /* sync event store with IPC (if neccessary) * This MUST be called before inserting event into output queue! */ - if((es = event_store_find(msg->job_id_s)) == NULL) + if((es = event_store_find(msg->job_id_s, NULL)) == NULL) return(-1); msg->es = es; #ifdef LB_PERF - if(nosync) + if(nosync) ret = 1; - else + else #endif ret = event_store_sync(es, offset); + /* no longer informative: il_log(LOG_DEBUG, " syncing event store at %d with event at %d, result %d\n", es->offset, offset, ret); + */ if(ret < 0) { - il_log(LOG_ERR, " handle_msg: error syncing event store:\n %s\n", error_get_msg()); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + " handle_msg: error syncing event store: %s", + error_get_msg()); /* XXX should error during event store recovery cause us to drop the message? */ /* Probably no, because the attempt to recover means we have missed some events, and delivery of this one will not move offset ahead. So try our best and deliver it @@ -391,8 +378,10 @@ handle_msg(il_octet_string_t *event, long offset) #else eq_s = queue_list_get(msg->job_id_s); #endif - if(eq_s == NULL) { - il_log(LOG_ERR, " handle_msg: apropriate queue not found: %s\n", error_get_msg()); + if(eq_s == NULL) { + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + " handle_msg: apropriate queue not found: %s", + error_get_msg()); clear_error(); } else { if(enqueue_msg(eq_s, msg) < 0) @@ -426,29 +415,31 @@ err: -int +int loop() { /* receive events */ while(1) { - il_octet_string_t msg; + il_octet_string_t *msg; long offset; int ret; - + + do_handle_signal(); if(killflg) - exit(0); + return (0); clear_error(); - if((ret = input_queue_get(&msg, &offset, INPUT_TIMEOUT)) < 0) + if((ret = input_queue_get(&msg, &offset, INPUT_TIMEOUT)) < 0) { if(error_get_maj() == IL_PROTO) { - il_log(LOG_DEBUG, " premature EOF while receiving event\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " premature EOF while receiving event"); /* problems with socket input, try to catch up from files */ #ifndef PERF_EMPTY event_store_recover_all(); #endif continue; - } else + } else return(-1); } else if(ret == 0) { @@ -456,25 +447,27 @@ loop() } #ifdef PERF_EMPTY - glite_wll_perftest_consumeEventString(msg.data); - free(msg.data); + glite_wll_perftest_consumeEventString(msg->data); + free(msg->data); continue; #endif -#ifdef INTERLOGD_HANDLE_CMD - ret = handle_cmd(&msg, offset); +#ifdef INTERLOGD_HANDLE_CMD + ret = handle_cmd(msg, offset); if(ret == 0) #endif - ret = handle_msg(&msg, offset); - free(msg.data); + ret = handle_msg(msg, offset); + if(msg->data) free(msg->data); if(ret < 0) switch (error_get_maj()) { case IL_SYS: case IL_NOMEM: return (ret); break; - default: - il_log(LOG_ERR, "Error: %s\n", error_get_msg()); + default: + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + "Error: %s", + error_get_msg()); break; } } /* while */ diff --git a/org.glite.lb.logger/src/input_queue_socket.c b/org.glite.lb.logger/src/input_queue_socket.c index bf3c7a2..ffcca81 100644 --- a/org.glite.lb.logger/src/input_queue_socket.c +++ b/org.glite.lb.logger/src/input_queue_socket.c @@ -1,4 +1,21 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include @@ -36,7 +53,9 @@ input_queue_attach() if(connect(sock, (struct sockaddr *)&saddr, sizeof(saddr.sun_path)) < 0) { if(errno == ECONNREFUSED) { /* socket present, but no one at the other end; remove it */ - il_log(LOG_WARNING, " removing stale input socket %s\n", socket_path); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, + " removing stale input socket %s", + socket_path); unlink(socket_path); } /* ignore other errors for now */ @@ -76,7 +95,6 @@ read_event(int sock, long *offset, il_octet_string_t *msg) { char *buffer, *p, *n; int len, alen, i, chunk_size = DEFAULT_CHUNK_SIZE; - static char buf[1024]; msg->data = NULL; msg->len = 0; @@ -109,7 +127,6 @@ read_event(int sock, long *offset, il_octet_string_t *msg) (alen - (p - buffer)) is the free space, */ -#if 1 /* Reading events - optimized version. Attempts to increase chunks read by recv * when there are more data, reads directly into destination memory (instead of * copying from static buffer) etc. @@ -153,55 +170,6 @@ read_event(int sock, long *offset, il_octet_string_t *msg) } } while ( (len > 0) && (n == NULL) ); -#else - /* Reading events - original version. - * Appears to behave quite good, anyway. - */ - while((len=recv(sock, buf, sizeof(buf), MSG_PEEK | MSG_NOSIGNAL)) > 0) { - - /* we have to be prepared for sizeof(buf) bytes */ - if(alen - (p - buffer) < (int)sizeof(buf)) { - alen += 8192; - n = realloc(buffer, alen); - if(n == NULL) { - free(buffer); - set_error(IL_NOMEM, ENOMEM, "read_event: no room for event"); - return(-1); - } - p = p - buffer + n; - buffer = n; - } - - /* copy all relevant bytes from buffer */ - n = (char*)memccpy(p, buf, EVENT_SEPARATOR, len); - if(n) { - /* separator found */ - n--; /* but do not preserve it */ - i = n - p; - p = n; - } else { - /* separator not found */ - i = len; - p += len; - } - /* This was definitely slowing us down: - * for(i=0; (i < len) && (buf[i] != EVENT_SEPARATOR); i++) - * *p++ = buf[i]; - */ - - /* remove the data from queue */ - if(i > 0) - if(recv(sock, buf, i, MSG_NOSIGNAL) != i) { - set_error(IL_SYS, errno, "read_event: error reading data"); - free(buffer); - return(-1); - } - if(i < len) - /* the event is complete */ - break; - } -#endif - /* terminate buffer */ *p = 0; @@ -243,14 +211,19 @@ read_event(int sock, long *offset, il_octet_string_t *msg) */ #ifdef PERF_EVENTS_INLINE int -input_queue_get(il_octet_string *buffer, long *offset, int timeout) +input_queue_get(il_octet_string **buffer, long *offset, int timeout) { static long o = 0; int len; char *jobid; + static il_octet_string_t my_buffer; - len = glite_wll_perftest_produceEventString(&buffer->data, &jobid); - buffer->len = len; + assert(buffer != NULL); + + *buffer = &my_buffer; + + len = glite_wll_perftest_produceEventString(&my_buffer.data, &jobid); + my_buffer.len = len; if(len) { o += len; *offset = o; @@ -261,14 +234,17 @@ input_queue_get(il_octet_string *buffer, long *offset, int timeout) } #else int -input_queue_get(il_octet_string_t *buffer, long *offset, int timeout) +input_queue_get(il_octet_string_t **buffer, long *offset, int timeout) { fd_set fds; struct timeval tv; int msg_len; + static il_octet_string_t my_buffer; assert(buffer != NULL); + *buffer = &my_buffer; + FD_ZERO(&fds); FD_SET(sock, &fds); @@ -284,7 +260,8 @@ input_queue_get(il_octet_string_t *buffer, long *offset, int timeout) case -1: /* error */ switch(errno) { case EINTR: - il_log(LOG_DEBUG, " interrupted while waiting for event!\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, + " interrupted while waiting for event!"); return(0); default: @@ -300,16 +277,16 @@ input_queue_get(il_octet_string_t *buffer, long *offset, int timeout) return(-1); } - read_event(accepted, offset, buffer); + read_event(accepted, offset, &my_buffer); close(accepted); - if(buffer->data == NULL) { + if(my_buffer.data == NULL) { if(error_get_maj() != IL_OK) return(-1); else return(0); } - return(buffer->len); + return(my_buffer.len); } #endif diff --git a/org.glite.lb.logger/src/input_queue_socket_http.c b/org.glite.lb.logger/src/input_queue_socket_http.c new file mode 100644 index 0000000..fd0e303 --- /dev/null +++ b/org.glite.lb.logger/src/input_queue_socket_http.c @@ -0,0 +1,184 @@ +#ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "interlogd.h" + +static const int SOCK_QUEUE_MAX = 50; +extern char *socket_path; +extern char *file_prefix; + +static int sock; +static int accepted; + +static +int plain_reader(void *user_data, char *buffer, const int len) +{ + return (recv(*(int*)user_data, buffer, len, MSG_NOSIGNAL)); +} + + +int +input_queue_attach() +{ + struct sockaddr_un saddr; + + if((sock=socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + set_error(IL_SYS, errno, "input_queue_attach: error creating socket"); + return(-1); + } + + memset(&saddr, 0, sizeof(saddr)); + saddr.sun_family = AF_UNIX; + strcpy(saddr.sun_path, socket_path); + + /* test for the presence of the socket and another instance + of interlogger listening */ + if(connect(sock, (struct sockaddr *)&saddr, sizeof(saddr.sun_path)) < 0) { + if(errno == ECONNREFUSED) { + /* socket present, but no one at the other end; remove it */ + il_log(LOG_WARNING, " removing stale input socket %s\n", socket_path); + unlink(socket_path); + } + /* ignore other errors for now */ + } else { + /* connection was successful, so bail out - there is + another interlogger running */ + set_error(IL_SYS, EADDRINUSE, "input_queue_attach: another instance of interlogger is running"); + return(-1); + } + + if(bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { + set_error(IL_SYS, errno, "input_queue_attach: error binding socket"); + return(-1); + } + + if (listen(sock, SOCK_QUEUE_MAX)) { + set_error(IL_SYS, errno, "input_queue_attach: error listening on socket"); + return -1; + } + + return(0); +} + + +void input_queue_detach() +{ + if (sock >= 0) + close(sock); + unlink(socket_path); +} + + + +/* + * Returns: -1 on error, 0 if no message available, message length otherwise + * + */ +#ifdef PERF_EVENTS_INLINE +int +input_queue_get(il_octet_string_t **buffer, long *offset, int timeout) +{ + static long o = 0; + int len; + char *jobid; + static il_octet_string_t my_buffer; + + assert(buffer != NULL); + + *buffer = &my_buffer; + + len = glite_wll_perftest_produceEventString(&my_buffer.data, &jobid); + my_buffer.len = len; + if(len) { + o += len; + *offset = o; + } else if (len == 0) { + sleep(timeout); + } + return(len); +} +#else +int +input_queue_get(il_octet_string_t **buffer, long *offset, int timeout) +{ + fd_set fds; + struct timeval tv; + int msg_len; + static il_http_message_t msg; + + assert(buffer != NULL); + + *buffer = (il_octet_string_t *)&msg; + + FD_ZERO(&fds); + FD_SET(sock, &fds); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + msg_len = select(sock + 1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); + switch(msg_len) { + + case 0: /* timeout */ + return(0); + + case -1: /* error */ + switch(errno) { + case EINTR: + il_log(LOG_DEBUG, " interrupted while waiting for event!\n"); + return(0); + + default: + set_error(IL_SYS, errno, "input_queue_get: error waiting for event"); + return(-1); + } + default: + break; + } + + if((accepted=accept(sock, NULL, NULL)) < 0) { + set_error(IL_SYS, errno, "input_queue_get: error accepting connection"); + return(-1); + } + + msg_len = receive_http(&accepted, plain_reader, &msg); + + if(msg_len < 0) { + close(accepted); + if(error_get_maj() != IL_OK) + return -1; + else + return 0; + } + + close(accepted); + *offset = -1; + return(msg.len); +} +#endif + diff --git a/org.glite.lb.logger/src/interlogd.c b/org.glite.lb.logger/src/interlogd.c index a66d7f4..f8002ec 100644 --- a/org.glite.lb.logger/src/interlogd.c +++ b/org.glite.lb.logger/src/interlogd.c @@ -1,18 +1,38 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + /* interlogger - collect events from local-logger and send them to logging and bookkeeping servers */ +#include #include #include #include #include - -#include +#include +#include +#include +#include +#include #include "interlogd.h" -#include "glite/lb/consumer.h" #include "glite/lb/log_proto.h" #include "glite/security/glite_gss.h" #ifdef LB_PERF @@ -23,23 +43,28 @@ #if defined(IL_NOTIFICATIONS) #define DEFAULT_PREFIX "/tmp/notif_events" #define DEFAULT_SOCKET "/tmp/notif_interlogger.sock" +#define DEFAULT_PIDFILE "/var/glite/glite-lb-notif-interlogd.pid" #else #define DEFAULT_PREFIX EDG_WLL_LOG_PREFIX_DEFAULT #define DEFAULT_SOCKET "/tmp/interlogger.sock" +#define DEFAULT_PIDFILE "/var/glite/glite-lb-interlogd.pid" #endif + /* The name the program was run with, stripped of any leading path. */ char *program_name; int killflg = 0; int TIMEOUT = DEFAULT_TIMEOUT; -gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL; +cred_handle_t *cred_handle = NULL; pthread_mutex_t cred_handle_lock = PTHREAD_MUTEX_INITIALIZER; time_t key_mtime = 0, cert_mtime = 0; +static char *pidfile = DEFAULT_PIDFILE; + static void usage (int status) { printf("%s - \n" @@ -55,9 +80,14 @@ static void usage (int status) " -k, --key location of server private key\n" " -C, --CAdir directory containing CA certificates\n" " -b, --book send events to bookkeeping server only\n" + " -i, --pidfile pid file\n" " -l, --log-server specify address of log server\n" " -s, --socket non-default path of local socket\n" " -L, --lazy [] be lazy when closing connections to servers (default, timeout==0 means turn lazy off)\n" + " -p, --parallel [] use parallel streams to the same server\n" + " -q, --queue-low queue length that enables another insertions\n" + " -Q, --queue-high max queue length\n" + " -F, --conf load configuration from config file\n" #ifdef LB_PERF " -n, --nosend PERFTEST: consume events instead of sending\n" " -S, --nosync PERFTEST: do not check logd files for lost events\n" @@ -80,6 +110,10 @@ char *file_prefix = DEFAULT_PREFIX; int bs_only = 0; int lazy_close = 1; int default_close_timeout; +size_t max_store_size; +size_t queue_size_low = 0; +size_t queue_size_high = 0; +int parallel = 0; #ifdef LB_PERF int nosend = 0, norecover=0, nosync=0, noparse=0; char *event_source = NULL; @@ -91,6 +125,8 @@ char *key_file = NULL; char *CAcert_dir = NULL; char *log_server = NULL; char *socket_path = DEFAULT_SOCKET; +static char *conf_file = NULL; +static char *config = NULL; static struct option const long_options[] = { @@ -103,9 +139,15 @@ static struct option const long_options[] = {"key", required_argument, 0, 'k'}, {"book", no_argument, 0, 'b'}, {"CAdir", required_argument, 0, 'C'}, + {"pidfile", required_argument, 0, 'i'}, {"log-server", required_argument, 0, 'l'}, {"socket", required_argument, 0, 's'}, {"lazy", optional_argument, 0, 'L'}, + {"max-store", required_argument, 0, 'M'}, + {"parallel", optional_argument, 0, 'p'}, + {"queue_size_low", required_argument, 0, 'q'}, + {"queue_size_high", required_argument, 0, 'Q'}, + {"conf", required_argument, 0, 'F'}, #ifdef LB_PERF {"nosend", no_argument, 0, 'n'}, {"nosync", no_argument, 0, 'S'}, @@ -139,8 +181,13 @@ decode_switches (int argc, char **argv) "k:" /* key */ "C:" /* CA dir */ "b" /* only bookeeping */ - "l:" /* log server */ + "i:" /* pidfile*/ + "l:" /* log server */ "d" /* debug */ + "p" /* parallel */ + "q:" + "Q:" + "F:" /* conf file */ #ifdef LB_PERF "n" /* nosend */ "S" /* nosync */ @@ -150,9 +197,10 @@ decode_switches (int argc, char **argv) "e:" /* event file */ "j:" /* num jobs */ #endif -#endif +#endif "L::" /* lazy */ - "s:", /* socket */ + "s:" /* socket */ + "M:" /* max-store */, long_options, (int *) 0)) != EOF) { switch (c) @@ -192,6 +240,10 @@ decode_switches (int argc, char **argv) log_server = strdup(optarg); break; + case 'i': + pidfile = strdup(optarg); + break; + case 'C': CAcert_dir = strdup(optarg); break; @@ -202,7 +254,7 @@ decode_switches (int argc, char **argv) case 'L': lazy_close = 1; - if(optarg) + if(optarg) default_close_timeout = atoi(optarg); if(default_close_timeout == 0) { default_close_timeout = TIMEOUT; @@ -212,6 +264,29 @@ decode_switches (int argc, char **argv) default_close_timeout = TIMEOUT; break; + case 'M': + max_store_size = atoi(optarg); + break; + + case 'p': + if(optarg) + parallel = atoi(optarg); + else + parallel = 4; + break; + + case 'q': + queue_size_low = atoi(optarg); + break; + + case 'Q': + queue_size_high = atoi(optarg); + break; + + case 'F': + conf_file = strdup(optarg); + break; + #ifdef LB_PERF case 'n': nosend = 1; @@ -249,11 +324,96 @@ decode_switches (int argc, char **argv) } -void handle_signal(int num) { - il_log(LOG_DEBUG, "Received signal %d\n", num); - killflg++; +char *load_conf_file(char *filename) +{ + struct stat fs; + FILE *cf; + char *s; + + if(stat(filename, &fs) < 0) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_ERROR, + "Could not stat config file %s: %s\n", filename, strerror(errno)); + exit(EXIT_FAILURE); + } + s = malloc(fs.st_size + 1); + if(s == NULL) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_ERROR, "Not enough memory for config file"); + exit(EXIT_FAILURE); + } + cf = fopen(filename, "r"); + if(cf == NULL) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_ERROR, + "Error opening config file %s: %s\n", filename, strerror(errno)); + exit(EXIT_FAILURE); + } + if(fread(s, fs.st_size, 1, cf) != 1) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_ERROR, + "Error reading config file %s: %s\n", filename, strerror(errno)); + exit(EXIT_FAILURE); + } + fclose(cf); + s[fs.st_size] = 0; + return s; +} + +static int received_signal = 0; + +static void handle_signal(int num) +{ + received_signal = num; } + +void do_handle_signal() { + + if (received_signal == 0) return; + + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, "Received signal %d\n", received_signal); + + switch(received_signal) { + case SIGHUP: + /* TODO: reload all external configurations, see + https://rt3.cesnet.cz/rt/Ticket/Display.html?id=24879 */ + glite_common_log_reread(); + break; + + case SIGUSR1: + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, + "Logging priority is now %s for %s, %s for %s and %s for %s\n", + glite_common_log_priority_to_string(glite_common_log_get_priority(LOG_CATEGORY_SECURITY)), + LOG_CATEGORY_SECURITY, + glite_common_log_priority_to_string(glite_common_log_get_priority(LOG_CATEGORY_ACCESS)), + LOG_CATEGORY_ACCESS, + glite_common_log_priority_to_string(glite_common_log_get_priority(LOG_CATEGORY_CONTROL)), + LOG_CATEGORY_CONTROL); + break; + + case SIGUSR2: + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, + "Logging priority is now %s for %s and %s for %s\n", + glite_common_log_priority_to_string(glite_common_log_get_priority(LOG_CATEGORY_LB)), + LOG_CATEGORY_LB, + glite_common_log_priority_to_string(glite_common_log_get_priority(LOG_CATEGORY_LB_IL)), + IL_LOG_CATEGORY); + break; + + case SIGPIPE: + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, "Broken pipe, lost communication channel.\n"); + break; + + case SIGINT: + case SIGTERM: + case SIGQUIT: + killflg++; + break; + + } + + received_signal = 0; +} + + + int main (int argc, char **argv) { @@ -261,6 +421,7 @@ main (int argc, char **argv) char *p; edg_wll_GssStatus gss_stat; int ret; + FILE *pidf; program_name = argv[0]; @@ -271,31 +432,62 @@ main (int argc, char **argv) i = decode_switches (argc, argv); + if(glite_common_log_init()) { + fprintf(stderr, "glite_common_log_init() failed, exiting.\n"); + exit(EXIT_FAILURE); + } + + /* parse config file, if any */ + if(conf_file != NULL) { + config = load_conf_file(conf_file); + } + + /* check for reasonable queue lengths */ + if((queue_size_low == 0 && queue_size_high > 0) || + (queue_size_low > queue_size_high)) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "max queue length -Q must be greater than low queue length -q, both or none must be specified!"); + exit(EXIT_FAILURE); + } + /* force -b if we do not have log server */ if(log_server == NULL) { log_server = strdup(DEFAULT_LOG_SERVER); bs_only = 1; } - if(init_errors(verbose ? LOG_DEBUG : LOG_WARNING)) { - fprintf(stderr, "Failed to initialize error message subsys. Exiting.\n"); - exit(EXIT_FAILURE); + /* initialize error reporting */ + if(init_errors()) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "Failed to initialize error message subsystem. Exiting."); + exit(EXIT_FAILURE); } if (signal(SIGPIPE, SIG_IGN) == SIG_ERR || signal(SIGABRT, handle_signal) == SIG_ERR || signal(SIGTERM, handle_signal) == SIG_ERR || signal(SIGINT, handle_signal) == SIG_ERR) { - perror("signal"); - exit(EXIT_FAILURE); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "Failed to setup signal handlers: %s, exiting.", + strerror(errno)); + exit(EXIT_FAILURE); + } + +/* just try it before deamonizing to be able to complain aloud */ + if (!(pidf = fopen(pidfile,"w"))) { + perror(pidfile); + exit(EXIT_FAILURE); } + fclose(pidf); if(!debug && (daemon(0,0) < 0)) { - perror("daemon"); - exit(EXIT_FAILURE); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "Failed to daemonize itself: %s, exiting.", + strerror(errno)); + exit(EXIT_FAILURE); } + pidf = fopen(pidfile,"w"); assert(pidf); /* XXX */ + fprintf(pidf,"%d\n",getpid()); + fclose(pidf); + #ifdef LB_PERF /* this must be called after installing signal handlers */ glite_wll_perftest_init(NULL, /* host */ @@ -305,45 +497,78 @@ main (int argc, char **argv) njobs); #endif - il_log(LOG_INFO, "Initializing input queue...\n"); if(input_queue_attach() < 0) { - il_log(LOG_CRIT, "Failed to initialize input queue: %s\n", error_get_msg()); - exit(EXIT_FAILURE); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "Failed to initialize input queue: %s", + error_get_msg()); + exit(EXIT_FAILURE); } + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, "Initialized input queue."); /* initialize output queues */ - il_log(LOG_INFO, "Initializing event queues...\n"); if(queue_list_init(log_server) < 0) { - il_log(LOG_CRIT, "Failed to initialize output event queues: %s\n", error_get_msg()); - exit(EXIT_FAILURE); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "Failed to initialize output event queues: %s", + error_get_msg()); + exit(EXIT_FAILURE); } + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, "Initialized event queues."); if(lazy_close) - il_log(LOG_DEBUG, " using lazy mode when closing connections, timeout %d\n", - default_close_timeout); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, " using lazy mode when closing connections, timeout %d", + default_close_timeout); + /* get credentials */ if (CAcert_dir) setenv("X509_CERT_DIR", CAcert_dir, 1); - edg_wll_gss_watch_creds(cert_file,&cert_mtime); - ret = edg_wll_gss_acquire_cred_gsi(cert_file, key_file, &cred_handle, NULL, &gss_stat); + cred_handle = malloc(sizeof(*cred_handle)); + if(cred_handle == NULL) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "Failed to allocate structure for credentials."); + exit(EXIT_FAILURE); + } + cred_handle->creds = NULL; + cred_handle->counter = 0; + ret = edg_wll_gss_acquire_cred_gsi(cert_file, key_file, &cred_handle->creds, &gss_stat); if (ret) { char *gss_err = NULL; - char *str; if (ret == EDG_WLL_GSS_ERROR_GSS) edg_wll_gss_get_error(&gss_stat, "edg_wll_gss_acquire_cred_gsi()", &gss_err); - asprintf(&str, "Failed to load GSI credential: %s\n", - (gss_err) ? gss_err : "edg_wll_gss_acquire_cred_gsi() failed"); - il_log(LOG_CRIT, str); - free(str); + glite_common_log(LOG_CATEGORY_SECURITY, LOG_PRIORITY_FATAL, "Failed to load GSI credential: %s, exiting.", + (gss_err) ? gss_err : "edg_wll_gss_acquire_cred_gsi() failed"); if (gss_err) free(gss_err); exit(EXIT_FAILURE); } - - if (globus_module_activate(GLOBUS_COMMON_MODULE) != GLOBUS_SUCCESS) { - il_log(LOG_CRIT, "Failed to initialize Globus common module\n"); - exit(EXIT_FAILURE); + glite_common_log(LOG_CATEGORY_SECURITY, LOG_PRIORITY_INFO, "Using certificate %s", cred_handle->creds->name); + + /* parse config, initialize plugins */ + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, "Initializing plugins:\n"); + if(config) { + char *s = strstr(config, "[interlogd]"); + char *p; + char name[MAXPATHLEN+1]; + + /* next line */ + s = strchr(s, '\n'); + if(s) s++; + while(s) { + if(*s == 0 || *s == '[') + break; + /* parse line */ + p = strchr(s, '\n'); + if(p) { + *p = 0; + } + /* XXX possible overflow by long line in config file */ + ret = sscanf(s, " plugin =%s", name); + if(p) *p = '\n'; + if(ret > 0) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, " loading plugin %s\n", name); + if(plugin_mgr_init(name, config) < 0) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_ERROR, "Failed to load plugin %s: %s\n", name, error_get_msg()); + } + } + s = p + 1; + } } #ifndef PERF_EMPTY @@ -351,35 +576,38 @@ main (int argc, char **argv) #ifdef LB_PERF if(norecover) { if(event_store_init(file_prefix) < 0) { - il_log(LOG_CRIT, "Failed to init event stores: %s\n", error_get_msg()); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "Failed to initialize event stores: %s", + error_get_msg()); exit(EXIT_FAILURE); } } else #endif - { + { pthread_t rid; - il_log(LOG_INFO, "Starting recovery thread...\n"); if(pthread_create(&rid, NULL, recover_thread, NULL) < 0) { - il_log(LOG_CRIT, "Failed to start recovery thread: %s\n", strerror(errno)); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "Failed to start recovery thread: %s", strerror(errno)); exit(EXIT_FAILURE); } pthread_detach(rid); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, "Started recovery thread."); } #endif - il_log(LOG_INFO, "Entering main loop...\n"); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, "Entering main loop."); /* do the work */ if(loop() < 0) { - il_log(LOG_CRIT, "Fatal error: %s\n", error_get_msg()); - if (killflg) { - input_queue_detach(); - exit(EXIT_FAILURE); - } + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "Fatal error: %s", error_get_msg()); + if (killflg) { + input_queue_detach(); + unlink(pidfile); + exit(EXIT_FAILURE); + } } - il_log(LOG_INFO, "Done!\n"); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, "Done!"); input_queue_detach(); + unlink(pidfile); exit (0); } diff --git a/org.glite.lb.logger/src/logd.c b/org.glite.lb.logger/src/logd.c index 36489db..d2aaf76 100644 --- a/org.glite.lb.logger/src/logd.c +++ b/org.glite.lb.logger/src/logd.c @@ -1,32 +1,61 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include #include #include #include #include #include #include +#include #include #include #include #include #include +#include +#include +#include -#include +#if defined(FREEBSD) || defined(__FreeBSD__) +#define TCP_CORK TCP_NOPUSH +#endif +#include "glite/lbu/log.h" #include "glite/lb/context-int.h" +#include "glite/lb/timeouts.h" #include "logd_proto.h" -#include "glite/lb/consumer.h" #include "glite/security/glite_gss.h" #ifdef LB_PERF #include "glite/lb/lb_perftest.h" #endif +#define DEFAULT_PIDFILE "/var/glite/glite-lb-logd.pid" + +typedef void (*logd_handler_t)(int); + static const char rcsid[] = "@(#)$Id$"; -static int verbose = 0; static int debug = 0; static int port = EDG_WLL_LOG_PORT_DEFAULT; static char *prefix = EDG_WLL_LOG_PREFIX_DEFAULT; +static char *pidfile = DEFAULT_PIDFILE; static char *cert_file = NULL; static char *key_file = NULL; static char *CAcert_dir = NULL; @@ -43,13 +72,13 @@ extern char confirm_sock_name[256]; static struct option const long_options[] = { { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, - { "verbose", no_argument, 0, 'v' }, { "debug", no_argument, 0, 'd' }, { "port", required_argument, 0, 'p' }, { "file-prefix", required_argument, 0, 'f' }, { "cert", required_argument, 0, 'c' }, { "key", required_argument, 0, 'k' }, { "CAdir", required_argument, 0, 'C' }, + { "pidfile",required_argument, 0, 'i' }, { "socket",required_argument, 0, 's' }, { "noAuth", no_argument, 0, 'x' }, { "noIPC", no_argument, 0, 'y' }, @@ -75,26 +104,25 @@ usage(char *program_name) { "-h, --help display this help and exit\n" "-V, --version output version information and exit\n" "-d, --debug do not run as daemon\n" - "-v, --verbose print extensive debug output\n" "-p, --port port to listen\n" "-f, --file-prefix path and prefix for event files\n" "-c, --cert location of server certificate\n" "-k, --key location of server private key\n" "-C, --CAdir directory containing CA certificates\n" "-s, --socket interlogger's socket to send messages to\n" + "-i, --pidfile pid file\n" "--noAuth do not check caller's identity\n" "--noIPC do not send messages to inter-logger\n" "--noParse do not parse messages for correctness\n", program_name,program_name); } -static sighandler_t mysignal(int num,sighandler_t handler) +static logd_handler_t mysignal(int num,logd_handler_t handler) { struct sigaction sa,osa; memset(&sa,0,sizeof(sa)); sa.sa_handler = handler; - sa.sa_flags = SA_RESTART; return sigaction(num,&sa,&osa) ? SIG_ERR : osa.sa_handler; } @@ -102,40 +130,70 @@ static sighandler_t mysignal(int num,sighandler_t handler) *---------------------------------------------------------------------- * * handle_signal - - * USR1 - increase the verbosity of the program - * USR2 - decrease the verbosity of the program + * HUP - reread log4crc + * USR1 - print priorities of all standard categories + * USR2 - print priorities of all LB categories * *---------------------------------------------------------------------- */ -void handle_signal(int num) { - if (num != SIGCHLD) edg_wll_ll_log(LOG_NOTICE,"Received signal %d\n", num); - switch (num) { - case SIGUSR1: - if (edg_wll_ll_log_level < LOG_DEBUG) edg_wll_ll_log_level++; - edg_wll_ll_log(LOG_NOTICE,"Logging level is now %d\n", edg_wll_ll_log_level); - break; - case SIGUSR2: - if (edg_wll_ll_log_level > LOG_EMERG) edg_wll_ll_log_level--; - edg_wll_ll_log(LOG_NOTICE,"Logging level is now %d\n", edg_wll_ll_log_level); - break; - case SIGPIPE: - edg_wll_ll_log(LOG_NOTICE,"Broken pipe, lost communication channel.\n"); - break; - case SIGCHLD: - while (wait3(NULL,WNOHANG,NULL) > 0); - break; - case SIGINT: - case SIGTERM: - case SIGQUIT: - if (confirm_sock) { - edg_wll_ll_log(LOG_NOTICE,"Closing confirmation socket.\n"); - close(confirm_sock); - unlink(confirm_sock_name); - } - exit(1); - break; - default: break; + +static int received_signal = 0; + +static void handle_signal(int num) +{ + received_signal = num; +} + +void do_handle_signal() { + + if (received_signal == 0) return; + + if (received_signal != SIGCHLD) glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Received signal %d\n", received_signal); + switch (received_signal) { + case SIGHUP: + /* TODO: reload all external configurations, see + https://rt3.cesnet.cz/rt/Ticket/Display.html?id=24879 */ + glite_common_log_reread(); + break; + case SIGUSR1: + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO, + "Logging priority is now %s for %s, %s for %s and %s for %s\n", + glite_common_log_priority_to_string(glite_common_log_get_priority(LOG_CATEGORY_SECURITY)), + LOG_CATEGORY_SECURITY, + glite_common_log_priority_to_string(glite_common_log_get_priority(LOG_CATEGORY_ACCESS)), + LOG_CATEGORY_ACCESS, + glite_common_log_priority_to_string(glite_common_log_get_priority(LOG_CATEGORY_CONTROL)), + LOG_CATEGORY_CONTROL); + break; + case SIGUSR2: + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO, + "Logging priority is now %s for %s and %s for %s\n", + glite_common_log_priority_to_string(glite_common_log_get_priority(LOG_CATEGORY_LB)), + LOG_CATEGORY_LB, + glite_common_log_priority_to_string(glite_common_log_get_priority(LOG_CATEGORY_LB_LOGD)), + LOG_CATEGORY_LB_LOGD); + break; + case SIGPIPE: + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Broken pipe, lost communication channel.\n"); + break; + case SIGCHLD: + while (wait3(NULL,WNOHANG,NULL) > 0); + break; + case SIGINT: + case SIGTERM: + case SIGQUIT: + if (confirm_sock) { + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Closing confirmation socket.\n"); + close(confirm_sock); + unlink(confirm_sock_name); + } + unlink(pidfile); + exit(1); + break; + default: break; } + + received_signal = 0; } /* @@ -146,20 +204,18 @@ void handle_signal(int num) { *---------------------------------------------------------------------- */ static int -doit(int socket, gss_cred_id_t cred_handle, char *file_name_prefix, int noipc, int noparse) +doit(int socket, edg_wll_GssCred cred_handle, char *file_name_prefix, int noipc, int noparse) { char *subject; int ret,fd,count; struct timeval timeout; edg_wll_GssConnection con; edg_wll_GssStatus gss_stat; - gss_buffer_desc gss_token = GSS_C_EMPTY_BUFFER; - gss_name_t client_name = GSS_C_NO_NAME; - OM_uint32 min_stat; - gss_OID name_type = GSS_C_NO_OID; + edg_wll_GssPrincipal client = NULL; fd_set fdset; - struct sockaddr_in peer; + struct sockaddr_storage peer; socklen_t alen = sizeof peer; + char peerhost[64], peerserv[16]; ret = count = 0; FD_ZERO(&fdset); @@ -168,45 +224,61 @@ doit(int socket, gss_cred_id_t cred_handle, char *file_name_prefix, int noipc, i timeout.tv_sec = ACCEPT_TIMEOUT; timeout.tv_usec = 0; getpeername(socket,(struct sockaddr *) &peer,&alen); - edg_wll_ll_log(LOG_DEBUG,"Accepting connection (remaining timeout %d.%06d sec)\n", + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Accepting connection (remaining timeout %d.%06d sec)\n", (int)timeout.tv_sec, (int) timeout.tv_usec); + + ret = getnameinfo ((struct sockaddr *) &peer, alen, + peerhost, sizeof(peerhost), peerserv, sizeof(peerserv), NI_NUMERICHOST | NI_NUMERICSERV); + if (ret) { + glite_common_log(LOG_CATEGORY_ACCESS, LOG_PRIORITY_WARN, "getnameinfo: %s", gai_strerror (ret)); + strcpy(peerhost, "unknown"); strcpy(peerserv, "unknown"); + } + +/* XXX: ugly workaround, we may detect false expired certificated + * probably due to bug in Globus GSS/SSL. */ +#define _EXPIRED_CERTIFICATE_MESSAGE "certificate has expired" + if ((ret = edg_wll_gss_accept(cred_handle,socket,&timeout,&con, &gss_stat)) < 0) { - edg_wll_ll_log(LOG_DEBUG,"timeout after gss_accept is %d.%06d sec\n", + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_DEBUG,"timeout after gss_accept is %d.%06d sec\n", (int)timeout.tv_sec, (int) timeout.tv_usec); - edg_wll_ll_log(LOG_ERR,"%s: edg_wll_gss_accept() failed\n",inet_ntoa(peer.sin_addr)); - return edg_wll_log_proto_server_failure(ret,&gss_stat,"edg_wll_gss_accept() failed\n"); + if ( ret == EDG_WLL_GSS_ERROR_TIMEOUT ) { + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN,"%s: Client authentication failed - timeout reached, closing.\n",peerhost); + } else if (ret == EDG_WLL_GSS_ERROR_GSS) { + char *gss_err; + + edg_wll_gss_get_error(&gss_stat, "Client authentication failed", &gss_err); + if (strstr(gss_err,_EXPIRED_CERTIFICATE_MESSAGE)) { + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN,"%s: false expired certificate: %s\n",peerhost,gss_err); + free(gss_err); + return -1; + } + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN,"%s: GSS error: %s, closing.\n",peerhost,gss_err); + free(gss_err); + } else { + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN,"%s: Client authentication failed, closing.\n",peerhost); + } + return 1; } /* authenticate */ - edg_wll_ll_log(LOG_INFO,"Processing authentication:\n"); - gss_stat.major_status = gss_inquire_context(&gss_stat.minor_status, con.context, - &client_name, NULL, NULL, NULL, NULL, - NULL, NULL); - if (GSS_ERROR(gss_stat.major_status)) { - char *gss_err; - edg_wll_gss_get_error(&gss_stat, "Cannot read client identification", &gss_err); - edg_wll_ll_log(LOG_WARNING, "%s: %s\n", inet_ntoa(peer.sin_addr),gss_err); - free(gss_err); - } else { - gss_stat.major_status = gss_display_name(&gss_stat.minor_status, client_name, - &gss_token, &name_type); - if (GSS_ERROR(gss_stat.major_status)) { - char *gss_err; - edg_wll_gss_get_error(&gss_stat, "Cannot process client identification", &gss_err); - edg_wll_ll_log(LOG_WARNING, "%s: %s\n",inet_ntoa(peer.sin_addr),gss_err); - free(gss_err); - } + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_DEBUG,"Processing authentication:\n"); + ret = edg_wll_gss_get_client_conn(&con, &client, &gss_stat); + if (ret) { + char *gss_err; + edg_wll_gss_get_error(&gss_stat, "Cannot read client identification", &gss_err); + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN, "%s: %s\n", peerhost,gss_err); + free(gss_err); } - if (GSS_ERROR(gss_stat.major_status) || edg_wll_gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)) { - edg_wll_ll_log(LOG_INFO," User not authenticated, setting as \"%s\". \n",EDG_WLL_LOG_USER_DEFAULT); + if (ret || client->flags & EDG_WLL_GSS_FLAG_ANON) { + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN," User not authenticated, setting as \"%s\". \n",EDG_WLL_LOG_USER_DEFAULT); subject=strdup(EDG_WLL_LOG_USER_DEFAULT); } else { - edg_wll_ll_log(LOG_INFO," User successfully authenticated as:\n"); - edg_wll_ll_log(LOG_INFO, " %s\n", (char *)gss_token.value); - subject=gss_token.value; - memset(&gss_token.value, 0, sizeof(gss_token.value)); + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_INFO," User successfully authenticated as: %s\n",client->name); + subject=strdup(client->name); } + if (client) + edg_wll_gss_free_princ(client); /* get and process the data */ timeout.tv_sec = CONNECTION_TIMEOUT; @@ -214,41 +286,42 @@ doit(int socket, gss_cred_id_t cred_handle, char *file_name_prefix, int noipc, i while (timeout.tv_sec > 0) { count++; - edg_wll_ll_log(LOG_DEBUG,"Waiting for data delivery no. %d (remaining timeout %d.%06d sec)\n", + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Waiting for data delivery no. %d (remaining timeout %d.%06d sec)\n", count, (int)timeout.tv_sec, (int) timeout.tv_usec); FD_SET(con.sock,&fdset); fd = select(con.sock+1,&fdset,NULL,NULL,&timeout); switch (fd) { case 0: /* timeout */ - edg_wll_ll_log(LOG_DEBUG,"Connection timeout expired\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Connection timeout expired\n"); timeout.tv_sec = 0; break; case -1: /* error */ switch(errno) { case EINTR: - edg_wll_ll_log(LOG_DEBUG,"XXX: Waking up (remaining timeout %d.%06d sec)\n", + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"XXX: Waking up (remaining timeout %d.%06d sec)\n", (int)timeout.tv_sec, (int) timeout.tv_usec); continue; default: - SYSTEM_ERROR("select"); + glite_common_log_SYS_ERROR("select"); timeout.tv_sec = 0; break; } break; default: - edg_wll_ll_log(LOG_DEBUG,"Waking up (remaining timeout %d.%06d sec)\n", + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Waking up (remaining timeout %d.%06d sec)\n", (int)timeout.tv_sec, (int) timeout.tv_usec); break; } if (FD_ISSET(con.sock,&fdset)) { ret = edg_wll_log_proto_server(&con,&timeout,subject,file_name_prefix,noipc,noparse); + // TODO: put into edg_wll_log_proto_server? if (ret != 0) { - edg_wll_ll_log(LOG_DEBUG,"timeout after edg_wll_log_proto_server is %d.%06d sec\n", + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"timeout after edg_wll_log_proto_server is %d.%06d sec\n", (int)timeout.tv_sec, (int) timeout.tv_usec); if (ret != EDG_WLL_GSS_ERROR_EOF) - edg_wll_ll_log(LOG_ERR,"edg_wll_log_proto_server(): Error\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wll_log_proto_server(): Error\n"); else if (count == 1) - edg_wll_ll_log(LOG_ERR,"edg_wll_log_proto_server(): Error. EOF occured.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wll_log_proto_server(): Error. EOF occured.\n"); timeout.tv_sec = 0; timeout.tv_usec = 0; break; @@ -260,16 +333,9 @@ doit(int socket, gss_cred_id_t cred_handle, char *file_name_prefix, int noipc, i } -doit_end: - edg_wll_ll_log(LOG_DEBUG, "Closing descriptor '%d'...",con.sock); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG, "Closing descriptor %d.",con.sock); edg_wll_gss_close(&con, NULL); - if (con.sock == -1) - edg_wll_ll_log(LOG_DEBUG, "o.k.\n"); if (subject) free(subject); - if (gss_token.length) - gss_release_buffer(&min_stat, &gss_token); - if (client_name != GSS_C_NO_NAME) - gss_release_name(&min_stat, &client_name); return ret; } @@ -285,18 +351,16 @@ int main(int argc, char *argv[]) int ret; int childpid; int opt; + FILE *pidf; int listener_fd; int client_fd; - struct sockaddr_in client_addr; - int client_addr_len; + struct sockaddr_storage client_addr; + socklen_t client_addr_len; - char *my_subject_name = NULL; - - time_t cert_mtime = 0, key_mtime = 0; - OM_uint32 min_stat; + time_t cert_mtime = 0; edg_wll_GssStatus gss_stat; - gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; + edg_wll_GssCred cred = NULL; setlinebuf(stdout); @@ -310,7 +374,6 @@ This is LocalLogger, part of Workload Management System in EU DataGrid & EGEE.\n while ((opt = getopt_long(argc,argv, "h" /* help */ "V" /* version */ - "v" /* verbose */ "d" /* debug */ "p:" /* port */ "f:" /* file prefix */ @@ -318,6 +381,7 @@ This is LocalLogger, part of Workload Management System in EU DataGrid & EGEE.\n "k:" /* key */ "C:" /* CA dir */ "s:" /* socket */ + "i:" /* pidfile */ "x" /* noAuth */ "y" /* noIPC */ "z", /* noParse */ @@ -325,7 +389,6 @@ This is LocalLogger, part of Workload Management System in EU DataGrid & EGEE.\n switch (opt) { case 'V': fprintf(stdout,"%s:\t%s\n",argv[0],rcsid); exit(0); - case 'v': verbose = 1; break; case 'd': debug = 1; break; case 'p': port = atoi(optarg); break; case 'f': prefix = optarg; break; @@ -333,6 +396,7 @@ This is LocalLogger, part of Workload Management System in EU DataGrid & EGEE.\n case 'k': key_file = optarg; break; case 'C': CAcert_dir = optarg; break; case 's': socket_path = optarg; break; + case 'i': pidfile = optarg; break; case 'x': noAuth = 1; break; case 'y': noIPC = 1; break; case 'z': noParse = 1; break; @@ -341,55 +405,42 @@ This is LocalLogger, part of Workload Management System in EU DataGrid & EGEE.\n usage(argv[0]); exit(0); } } -#ifdef LB_PERF - edg_wll_ll_log_init(verbose ? LOG_INFO : LOG_ERR); -#else - edg_wll_ll_log_init(verbose ? LOG_DEBUG : LOG_INFO); -#endif - edg_wll_ll_log(LOG_INFO,"Initializing...\n"); + if (glite_common_log_init()) { + fprintf(stderr,"glite_common_log_init() failed, exiting."); + exit(1); + } + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Initializing...\n"); /* check noParse */ if (noParse) { - edg_wll_ll_log(LOG_INFO,"Parse messages for correctness... [no]\n"); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Parse messages for correctness... [no]\n"); } else { - edg_wll_ll_log(LOG_INFO,"Parse messages for correctness... [yes]\n"); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Parse messages for correctness... [yes]\n"); } /* check noIPC */ if (noIPC) { - edg_wll_ll_log(LOG_INFO,"Send messages also to inter-logger... [no]\n"); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Send messages also to inter-logger... [no]\n"); } else { - edg_wll_ll_log(LOG_INFO,"Send messages also to inter-logger... [yes]\n"); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Send messages also to inter-logger... [yes]\n"); } /* check prefix correctness */ if (strlen(prefix) > FILENAME_MAX - 34) { - edg_wll_ll_log(LOG_CRIT,"Too long prefix (%s) for file names, would not be able to write to log files. Exiting.\n",prefix); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_FATAL,"Too long prefix (%s) for file names, would not be able to write to log files. Exiting.\n",prefix); exit(1); } /* TODO: check for write permisions */ - edg_wll_ll_log(LOG_INFO,"Messages will be stored with the filename prefix \"%s\".\n",prefix); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Messages will be stored with the filename prefix \"%s\".\n",prefix); if (CAcert_dir) setenv("X509_CERT_DIR", CAcert_dir, 1); - /* initialize Globus common module */ -/* XXX: obsolete? - edg_wll_ll_log(LOG_INFO,"Initializing Globus common module..."); - if (globus_module_activate(GLOBUS_COMMON_MODULE) != GLOBUS_SUCCESS) { - edg_wll_ll_log(LOG_NOTICE,"no.\n"); - edg_wll_ll_log(LOG_CRIT, "Failed to initialize Globus common module. Exiting.\n"); - exit(1); - } else { - edg_wll_ll_log(LOG_INFO,"yes.\n"); - } -*/ - /* initialize signal handling */ if (mysignal(SIGUSR1, handle_signal) == SIG_ERR) { perror("signal"); exit(1); } if (mysignal(SIGUSR2, handle_signal) == SIG_ERR) { perror("signal"); exit(1); } if (mysignal(SIGPIPE, handle_signal) == SIG_ERR) { perror("signal"); exit(1); } - if (mysignal(SIGHUP, SIG_DFL) == SIG_ERR) { perror("signal"); exit(1); } + if (mysignal(SIGHUP, handle_signal) == SIG_ERR) { perror("signal"); exit(1); } if (mysignal(SIGINT, handle_signal) == SIG_ERR) { perror("signal"); exit(1); } if (mysignal(SIGQUIT, handle_signal) == SIG_ERR) { perror("signal"); exit(1); } if (mysignal(SIGTERM, handle_signal) == SIG_ERR) { perror("signal"); exit(1); } @@ -401,103 +452,121 @@ This is LocalLogger, part of Workload Management System in EU DataGrid & EGEE.\n edg_wll_gss_watch_creds(cert_file,&cert_mtime); /* XXX DK: support noAuth */ - ret = edg_wll_gss_acquire_cred_gsi(cert_file, key_file, &cred, &my_subject_name, - &gss_stat); + ret = edg_wll_gss_acquire_cred_gsi(cert_file, key_file, &cred, &gss_stat); if (ret) { /* XXX DK: call edg_wll_gss_get_error() */ - edg_wll_ll_log(LOG_CRIT,"Failed to get GSI credentials. Exiting.\n"); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_FATAL,"Failed to get GSI credentials. Exiting.\n"); exit(1); } - if (my_subject_name!=NULL) { - edg_wll_ll_log(LOG_INFO,"Server running with certificate: %s\n",my_subject_name); - free(my_subject_name); + if (cred->name!=NULL) { + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Server running with certificate: %s\n",cred->name); } else if (noAuth) { - edg_wll_ll_log(LOG_INFO,"Server running without certificate\n"); -#if 0 - /* XXX DK: */ - } else { - edg_wll_ll_log(LOG_CRIT,"No server credential found. Exiting.\n"); - exit(1); -#endif + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Server running without certificate\n"); } /* do listen */ - edg_wll_ll_log(LOG_INFO,"Listening on port %d\n",port); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Listening on port %d\n",port); listener_fd = do_listen(port); if (listener_fd == -1) { - edg_wll_ll_log(LOG_CRIT,"Failed to listen on port %d\n",port); - gss_release_cred(&min_stat, &cred); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_FATAL,"Failed to listen on port %d\n",port); + edg_wll_gss_release_cred(&cred, NULL); exit(-1); } else { - edg_wll_ll_log(LOG_DEBUG,"Listener's socket descriptor is '%d'\n",listener_fd); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_DEBUG,"Listener's socket descriptor is '%d'\n",listener_fd); } client_addr_len = sizeof(client_addr); bzero((char *) &client_addr, client_addr_len); +/* just try it before deamonizing to be able to complain aloud */ + if (!(pidf = fopen(pidfile,"w"))) { + perror(pidfile); + exit(-1); + } + fclose(pidf); + + /* daemonize */ if (debug) { - edg_wll_ll_log(LOG_INFO,"Running as daemon... [no]\n"); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Running as daemon... [no]\n"); } else { - edg_wll_ll_log(LOG_INFO,"Running as daemon... [yes]\n"); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_INFO,"Running as daemon... [yes]\n"); if (daemon(0,0) < 0) { - edg_wll_ll_log(LOG_CRIT,"Failed to run as daemon. Exiting.\n"); - SYSTEM_ERROR("daemon"); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_FATAL,"Failed to run as daemon. Exiting.\n"); + glite_common_log_SYS_ERROR("daemon"); exit(1); } } + pidf = fopen(pidfile,"w"); assert(pidf); /* XXX */ + fprintf(pidf,"%d\n",getpid()); + fclose(pidf); + /* * Main loop */ while (1) { - edg_wll_ll_log(LOG_INFO,"Accepting incomming connections...\n"); + int opt,my_errno; + + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_INFO,"Accepting incomming connections...\n"); client_fd = accept(listener_fd, (struct sockaddr *) &client_addr, &client_addr_len); + my_errno = errno; + do_handle_signal(); if (client_fd < 0) { + if (my_errno == EINTR) continue; close(listener_fd); - edg_wll_ll_log(LOG_CRIT,"Failed to accept incomming connections\n"); - SYSTEM_ERROR("accept"); - gss_release_cred(&min_stat, &cred); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_FATAL,"Failed to accept incomming connections\n"); + glite_common_log_SYS_ERROR("accept"); + edg_wll_gss_release_cred(&cred, NULL); exit(-1); } else { - edg_wll_ll_log(LOG_DEBUG,"Incomming connection on socket '%d'\n",client_fd); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Incomming connection on socket '%d'\n",client_fd); + } + + opt = 0; + if (setsockopt(client_fd,IPPROTO_TCP,TCP_CORK,(const void *) &opt,sizeof opt)) { + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"Can't reset TCP_CORK\n"); + } + opt = 1; + if (setsockopt(client_fd,IPPROTO_TCP,TCP_NODELAY,(const void *) &opt,sizeof opt)) { + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"Can't set TCP_NODELAY\n"); } switch (edg_wll_gss_watch_creds(cert_file,&cert_mtime)) { - gss_cred_id_t newcred; + edg_wll_GssCred newcred; case 0: break; case 1: - ret = edg_wll_gss_acquire_cred_gsi(cert_file,key_file,&newcred,NULL,&gss_stat); + ret = edg_wll_gss_acquire_cred_gsi(cert_file,key_file,&newcred,&gss_stat); if (ret) { - edg_wll_ll_log(LOG_WARNING,"Reloading credentials failed, continue with older\n"); + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN,"Reloading credentials failed, continue with older\n"); } else { - edg_wll_ll_log(LOG_DEBUG,"Reloading credentials succeeded\n"); - gss_release_cred(&min_stat, &cred); + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_DEBUG,"Reloading credentials succeeded\n"); + edg_wll_gss_release_cred(&cred, NULL); cred = newcred; } break; case -1: - edg_wll_ll_log(LOG_WARNING,"edg_wll_gss_watch_creds failed\n"); + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN,"edg_wll_gss_watch_creds failed\n"); break; } /* FORK - change next line if fork() is not needed (for debugging for example) */ #if 1 if ((childpid = fork()) < 0) { - SYSTEM_ERROR("fork"); + glite_common_log_SYS_ERROR("fork"); if (client_fd) close(client_fd); } if (childpid == 0) { ret = doit(client_fd,cred,prefix,noIPC,noParse); if (client_fd) close(client_fd); - edg_wll_ll_log(LOG_DEBUG,"Exiting.\n", + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_DEBUG,"Exiting.\n", CONNECTION_TIMEOUT); exit(0); } if (childpid > 0) { - edg_wll_ll_log(LOG_DEBUG,"Forked a new child with PID %d\n",childpid); + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_DEBUG,"Forked a new child with PID %d\n",childpid); if (client_fd) close(client_fd); } #else @@ -507,8 +576,7 @@ This is LocalLogger, part of Workload Management System in EU DataGrid & EGEE.\n #endif } /* while */ -end: if (listener_fd) close(listener_fd); - gss_release_cred(&min_stat, &cred); + edg_wll_gss_release_cred(&cred, NULL); exit(ret); } diff --git a/org.glite.lb.logger/src/logd_proto.c b/org.glite.lb.logger/src/logd_proto.c index 4e1a1e3..3e766d6 100644 --- a/org.glite.lb.logger/src/logd_proto.c +++ b/org.glite.lb.logger/src/logd_proto.c @@ -1,5 +1,23 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#include #include #include #include @@ -9,9 +27,13 @@ #include #include #include +#include +#include +#include +#include "glite/lbu/escape.h" +#include "glite/lbu/log.h" #include "glite/lb/context-int.h" -#include "glite/lb/escape.h" #include "glite/lb/events_parse.h" #include "logd_proto.h" @@ -20,7 +42,9 @@ static const int one = 1; extern char* socket_path; -int edg_wll_ll_log_level; +int glite_common_log_priority_security; +int glite_common_log_priority_access; +int glite_common_log_priority_control; #define tv_sub(a,b) {\ (a).tv_usec -= (b).tv_usec;\ @@ -34,6 +58,54 @@ int edg_wll_ll_log_level; /* *---------------------------------------------------------------------- * + * handle_gss_failures - handle GSS failures on the server side + * + * Returns: errno + * + *---------------------------------------------------------------------- + */ +static int handle_gss_failures(int code, edg_wll_GssStatus *gss_code, const char *text) +{ + const char *func = "edg_wll_log_proto_server()"; + int ret = 0; + + if(code>0) { + return(0); + } + switch(code) { + case EDG_WLL_GSS_ERROR_EOF: + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN,"%s: %s, EOF occured\n", func, text); + ret = EAGAIN; + break; + case EDG_WLL_GSS_ERROR_TIMEOUT: + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN,"%s: %s, timeout expired\n", func, text); + ret = EAGAIN; + break; + case EDG_WLL_GSS_ERROR_ERRNO: + glite_common_log_SYS_ERROR(func); + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN,"%s: %s, system error occured\n", func, text); + ret = EAGAIN; + break; + case EDG_WLL_GSS_ERROR_GSS: + { + char *gss_err; + + edg_wll_gss_get_error(gss_code, "GSS error occured", &gss_err); + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_WARN,"%s: %s, %s\n", func, text, gss_err); + free(gss_err); + ret = EAGAIN; + break; + } + default: + glite_common_log(LOG_CATEGORY_SECURITY,LOG_PRIORITY_ERROR,"%s: %s, unknown error occured\n"); + break; + } + return ret; +} + +/* + *---------------------------------------------------------------------- + * * send_answer_back - * *---------------------------------------------------------------------- @@ -45,16 +117,15 @@ static int send_answer_back(edg_wll_GssConnection *con, int answer, struct timev u_int8_t ans_end[4]; edg_wll_GssStatus gss_stat; - edg_wll_ll_log(LOG_INFO,"Sending answer \"%d\" back to client...",answer); ans_end[0] = ans & 0xff; ans >>= 8; ans_end[1] = ans & 0xff; ans >>= 8; ans_end[2] = ans & 0xff; ans >>= 8; ans_end[3] = ans; if ((err = edg_wll_gss_write_full(con,ans_end,4,timeout,&count, &gss_stat)) < 0 ) { - edg_wll_ll_log(LOG_INFO,"error.\n"); - return edg_wll_log_proto_server_failure(err,&gss_stat,"Error sending answer"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_INFO,"Error sending answer \"%d\" back to client.\n",answer); + return handle_gss_failures(err,&gss_stat,"Error sending answer"); } else { - edg_wll_ll_log(LOG_INFO,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Answer \"%d\" succesfully sent back to client.\n",answer); return 0; } } @@ -82,8 +153,8 @@ int init_confirmation() /* create socket */ if((confirm_sock=socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - SYSTEM_ERROR("socket"); - edg_wll_ll_log(LOG_ERR,"init_confirmation(): error creating socket\n"); + glite_common_log_SYS_ERROR("socket"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"init_confirmation(): error creating socket\n"); return(-1); } @@ -94,8 +165,8 @@ int init_confirmation() /* bind the socket */ if(bind(confirm_sock, (struct sockaddr *)&saddr, sizeof(saddr.sun_path)) < 0) { - SYSTEM_ERROR("bind"); - edg_wll_ll_log(LOG_ERR,"init_confirmation(): error binding socket\n"); + glite_common_log_SYS_ERROR("bind"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"init_confirmation(): error binding socket\n"); close(confirm_sock); unlink(confirm_sock_name); return(-1); @@ -103,8 +174,8 @@ int init_confirmation() /* and listen */ if(listen(confirm_sock, 5) < 0) { - SYSTEM_ERROR("listen"); - edg_wll_ll_log(LOG_ERR,"init_confirmation(): error listening on socket\n"); + glite_common_log_SYS_ERROR("listen"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"init_confirmation(): error listening on socket\n"); close(confirm_sock); unlink(confirm_sock_name); return(-1); @@ -133,8 +204,8 @@ int wait_for_confirmation(struct timeval *timeout, int *code) /* wait for confirmation at most timeout seconds */ if ((tmp=select(confirm_sock+1, &fds, NULL, NULL, timeout?&to:NULL)) < 0) { - SYSTEM_ERROR("select"); - edg_wll_ll_log(LOG_ERR,"wait_for_confirmation(): error selecting socket\n"); + glite_common_log_SYS_ERROR("select"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"wait_for_confirmation(): error selecting socket\n"); ret = -1; } else { if (tmp == 0) @@ -143,13 +214,13 @@ int wait_for_confirmation(struct timeval *timeout, int *code) int nsd = accept(confirm_sock, NULL, NULL); ret = 1; if(nsd < 0) { - SYSTEM_ERROR("accept"); - edg_wll_ll_log(LOG_ERR,"wait_for_confirmation(): error accepting a connection on a socket\n"); + glite_common_log_SYS_ERROR("accept"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"wait_for_confirmation(): error accepting a connection on a socket\n"); ret = -1; } else { if(recv(nsd, code, sizeof(*code), MSG_NOSIGNAL) < 0) { - SYSTEM_ERROR("recv"); - edg_wll_ll_log(LOG_ERR,"wait_for_confirmation(): error receiving a message from a socket\n"); + glite_common_log_SYS_ERROR("recv"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"wait_for_confirmation(): error receiving a message from a socket\n"); ret = -1; } close(nsd); @@ -187,32 +258,52 @@ int do_listen(int port) { int ret; int sock; - struct sockaddr_in my_addr; + struct addrinfo *ai; + struct addrinfo hints; + char *portstr = NULL; + + asprintf(&portstr, "%d", port); + if (portstr == NULL) { + glite_common_log(LOG_CATEGORY_CONTROL,LOG_PRIORITY_FATAL,"do_listen(): ENOMEM converting port number\n"); + return -1; + } + + memset (&hints, '\0', sizeof (hints)); + hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_socktype = SOCK_STREAM; - memset(&my_addr, 0, sizeof(my_addr)); - my_addr.sin_family = AF_INET; - my_addr.sin_addr.s_addr = INADDR_ANY; - my_addr.sin_port = htons(port); + ret = getaddrinfo (NULL, portstr, &hints, &ai); + if (ret != 0) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "getaddrinfo: %s", gai_strerror (ret)); + return -1; + } + if (ai == NULL) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, "getaddrinfo: no return"); + return -1; + } - sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock == -1) { - SYSTEM_ERROR("socket"); - edg_wll_ll_log(LOG_ERR,"do_listen(): error creating socket\n"); + glite_common_log_SYS_ERROR("socket"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"do_listen(): error creating socket\n"); + freeaddrinfo(ai); return -1; } setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); - ret = bind(sock, (struct sockaddr *)&my_addr, sizeof(my_addr)); + ret = bind(sock, ai->ai_addr, ai->ai_addrlen); if (ret == -1) { - SYSTEM_ERROR("bind"); - edg_wll_ll_log(LOG_ERR,"do_listen(): error binding socket\n"); + glite_common_log_SYS_ERROR("bind"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"do_listen(): error binding socket\n"); + freeaddrinfo(ai); return -1; } + freeaddrinfo(ai); ret = listen(sock, 5); if (ret == -1) { - SYSTEM_ERROR("listen"); - edg_wll_ll_log(LOG_ERR,"do_listen(): error listening on socket\n"); + glite_common_log_SYS_ERROR("listen"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"do_listen(): error listening on socket\n"); close(sock); return -1; } @@ -245,10 +336,8 @@ int edg_wll_log_proto_server(edg_wll_GssConnection *con, struct timeval *timeout int i,answer,answer_sent; int msg_sock; char *msg,*msg_begin; - FILE *outfile; - int filedesc,filelock_status,flags; + int filedesc,filelock_status; long filepos; - struct flock filelock; int priority; long lllid; int unique; @@ -264,12 +353,12 @@ int edg_wll_log_proto_server(edg_wll_GssConnection *con, struct timeval *timeout /* init */ if (edg_wll_InitContext(&context) != 0) { - edg_wll_ll_log(LOG_ERR,"edg_wll_InitContex(): error.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"edg_wll_InitContex(): error.\n"); answer = ENOMEM; goto edg_wll_log_proto_server_end; } if (edg_wll_ResetError(context) != 0) { - edg_wll_ll_log(LOG_ERR,"edg_wll_ResetError(): error.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"edg_wll_ResetError(): error.\n"); answer = ENOMEM; goto edg_wll_log_proto_server_end; } @@ -281,9 +370,9 @@ int edg_wll_log_proto_server(edg_wll_GssConnection *con, struct timeval *timeout snprintf(confirm_sock_name, sizeof(confirm_sock_name), "/tmp/dglogd_sock_%ld", lllid); if ((filedesc = open(confirm_sock_name,O_CREAT)) == -1) { if (errno == EEXIST) { - edg_wll_ll_log(LOG_WARNING,"Warning: LLLID %ld already in use.\n",lllid); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"Warning: LLLID %ld already in use.\n",lllid); } else { - SYSTEM_ERROR("open"); + glite_common_log_SYS_ERROR("open"); } } else { unique = 1; @@ -292,94 +381,88 @@ int edg_wll_log_proto_server(edg_wll_GssConnection *con, struct timeval *timeout } } if (!unique) { - edg_wll_ll_log(LOG_ERR,"Cannot determine the unique long local-logger id (LLLID)!\n",lllid); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_ERROR,"Cannot determine the unique long local-logger id (LLLID)!\n",lllid); return EAGAIN; } - edg_wll_ll_log(LOG_INFO,"Long local-logger id (LLLID): %ld\n",lllid); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_INFO,"Long local-logger id (LLLID): %ld ... [ok]\n",lllid); /* receive socket header */ - edg_wll_ll_log(LOG_INFO,"Reading socket header..."); memset(header, 0, EDG_WLL_LOG_SOCKET_HEADER_LENGTH+1); if ((err = edg_wll_gss_read_full(con, header, EDG_WLL_LOG_SOCKET_HEADER_LENGTH, timeout, &count, &gss_stat)) < 0) { if (err == EDG_WLL_GSS_ERROR_EOF) { - edg_wll_ll_log(LOG_INFO,"no data available.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"Reading socket header - no data available.\n"); answer = err; answer_sent = 1; /* i.e. do not try to send answer back */ } else { - edg_wll_ll_log(LOG_INFO,"error.\n"); - answer = edg_wll_log_proto_server_failure(err,&gss_stat,"Error receiving header"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"Error reading socket header.\n"); + answer = handle_gss_failures(err,&gss_stat,"Error reading socket header"); } goto edg_wll_log_proto_server_end; } else { - edg_wll_ll_log(LOG_INFO,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Reading socket header... [ok]\n"); } - edg_wll_ll_log(LOG_DEBUG,"Checking socket header..."); + /* Check socket header */ header[EDG_WLL_LOG_SOCKET_HEADER_LENGTH] = '\0'; if (strncmp(header,EDG_WLL_LOG_SOCKET_HEADER,EDG_WLL_LOG_SOCKET_HEADER_LENGTH)) { /* not the proper socket header text */ - edg_wll_ll_log(LOG_DEBUG,"error.\n"); - edg_wll_ll_log(LOG_ERR,"edg_wll_log_proto_server(): invalid socket header\n"); - edg_wll_ll_log(LOG_DEBUG,"edg_wll_log_proto_server(): read header '%s' instead of '%s'\n", + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wll_log_proto_server(): invalid socket header\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"edg_wll_log_proto_server(): read header '%s' instead of '%s'\n", header,EDG_WLL_LOG_SOCKET_HEADER); answer = EINVAL; goto edg_wll_log_proto_server_end; } else { - edg_wll_ll_log(LOG_DEBUG,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Read socket header: \"%s\" [ok]\n",header); } /* XXX: obsolete - edg_wll_ll_log(LOG_DEBUG,"Reading message priority..."); count = 0; if ((err = edg_wll_gss_read_full(con, &priority, sizeof(priority), timeout, &count, &gss_stat)) < 0) { - edg_wll_ll_log(LOG_DEBUG,"error.\n"); - answer = edg_wll_log_proto_server_failure(err,&gss_stat,"Error receiving message priority"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"Error reading message priority.\n"); + answer = handle_gss_failures(err,&gss_stat,"Error receiving message priority"); goto edg_wll_log_proto_server_end; } else { - edg_wll_ll_log(LOG_DEBUG,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Read message priority: %d [ok]\n",priority); } */ - edg_wll_ll_log(LOG_DEBUG,"Reading message size..."); + /* read message size */ count = 0; if ((err = edg_wll_gss_read_full(con, size_end, 4, timeout, &count,&gss_stat)) < 0) { - edg_wll_ll_log(LOG_DEBUG,"error.\n"); - answer = edg_wll_log_proto_server_failure(err,&gss_stat,"Error receiving message size"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Error reading message size.\n"); + answer = handle_gss_failures(err,&gss_stat,"Error reading message size"); goto edg_wll_log_proto_server_end; } else { - edg_wll_ll_log(LOG_DEBUG,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Reading message size... [ok]\n"); } size = size_end[3]; size <<=8; size |= size_end[2]; size <<=8; size |= size_end[1]; size <<=8; size |= size_end[0]; - edg_wll_ll_log(LOG_DEBUG,"Checking message size..."); if (size <= 0) { - edg_wll_ll_log(LOG_DEBUG,"error.\n"); /* probably wrong size in the header or nothing to read */ - edg_wll_ll_log(LOG_ERR,"edg_wll_log_proto_server(): invalid size read from socket header\n"); - edg_wll_ll_log(LOG_DEBUG,"Read size '%d'.\n",size); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wll_log_proto_server(): invalid size read from socket header\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Read message size '%d' [error].\n",size); answer = EINVAL; goto edg_wll_log_proto_server_end; } else { - edg_wll_ll_log(LOG_DEBUG,"o.k.\n"); - edg_wll_ll_log(LOG_DEBUG,"- Size read from header: %d bytes.\n",size); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Read message size: %d bytes [ok].\n",size); } /* format the DG.LLLID string */ if (asprintf(&dglllid,"DG.LLLID=%ld ",lllid) == -1) { - SYSTEM_ERROR("asprintf"); - edg_wll_ll_log(LOG_ERR,"edg_wll_log_proto_server(): nomem for DG.LLLID\n"); + glite_common_log_SYS_ERROR("asprintf"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wll_log_proto_server(): nomem for DG.LLLID\n"); answer = ENOMEM; goto edg_wll_log_proto_server_end; } dglllid_size = strlen(dglllid); /* format the DG.USER string */ - name_esc = edg_wll_LogEscape(name); + name_esc = glite_lbu_EscapeULM(name); if (asprintf(&dguser,"DG.USER=\"%s\" ",name_esc) == -1) { - SYSTEM_ERROR("asprintf"); - edg_wll_ll_log(LOG_ERR,"edg_wll_log_proto_server(): nomem for DG.USER\n"); + glite_common_log_SYS_ERROR("asprintf"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wll_log_proto_server(): nomem for DG.USER\n"); answer = ENOMEM; goto edg_wll_log_proto_server_end; } @@ -388,8 +471,8 @@ int edg_wll_log_proto_server(edg_wll_GssConnection *con, struct timeval *timeout /* allocate enough memory for all data */ msg_size = dglllid_size + dguser_size + size + 1; if ((msg = malloc(msg_size)) == NULL) { - SYSTEM_ERROR("malloc"); - edg_wll_ll_log(LOG_ERR,"edg_wll_log_proto_server(): out of memory for allocating message\n"); + glite_common_log_SYS_ERROR("malloc"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wll_log_proto_server(): out of memory for allocating message\n"); answer = ENOMEM; goto edg_wll_log_proto_server_end; } @@ -398,52 +481,48 @@ int edg_wll_log_proto_server(edg_wll_GssConnection *con, struct timeval *timeout strncpy(msg_begin,dguser,dguser_size); /* receive message */ - edg_wll_ll_log(LOG_INFO,"Reading message from socket..."); buf = msg_begin + dguser_size; count = 0; if ((err = edg_wll_gss_read_full(con, buf, size, timeout, &count, &gss_stat)) < 0) { - edg_wll_ll_log(LOG_INFO,"error.\n"); - answer = edg_wll_log_proto_server_failure(err,&gss_stat,"Error receiving message"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"Error reading message from socket.\n"); + answer = handle_gss_failures(err,&gss_stat,"Error reading message from socket."); goto edg_wll_log_proto_server_end; } else { - edg_wll_ll_log(LOG_INFO,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Reading message... [ok]\n"); + // glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_TRACE,"Read message: \"%s\"\n",msg); } if (buf[count] != '\0') buf[count] = '\0'; /* parse message and get jobId and priority from it */ if (!noparse && strstr(msg, "DG.TYPE=\"command\"") == NULL) { - edg_wll_ll_log(LOG_INFO,"Parsing message for correctness..."); if (edg_wll_ParseEvent(context,msg_begin,&event) != 0) { - edg_wll_ll_log(LOG_INFO,"error.\n"); - edg_wll_ll_log(LOG_ERR,"edg_wll_log_proto_server(): edg_wll_ParseEvent error\n"); - edg_wll_ll_log(LOG_ERR,"edg_wll_ParseEvent(): %s\n",context->errDesc); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wll_log_proto_server(): edg_wll_ParseEvent error\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wll_ParseEvent(): %s\n",context->errDesc); answer = edg_wll_Error(context,NULL,NULL); goto edg_wll_log_proto_server_end; } else { - edg_wll_ll_log(LOG_INFO,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Parsing message for correctness...[ok]\n"); } - edg_wll_ll_log(LOG_DEBUG,"Getting jobId from message..."); jobId = edg_wlc_JobIdGetUnique(event->any.jobId); priority = event->any.priority; edg_wll_FreeEvent(event); event->any.priority = priority; - edg_wll_ll_log(LOG_DEBUG,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Getting jobId from message...[ok]\n"); } else { if ((event = edg_wll_InitEvent(EDG_WLL_EVENT_UNDEF)) == NULL) { - edg_wll_ll_log(LOG_ERR, "edg_wll_InitEvent(): out of memory\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN, "edg_wll_InitEvent(): out of memory\n"); answer = ENOMEM; goto edg_wll_log_proto_server_end; } - edg_wll_ll_log(LOG_DEBUG,"Getting jobId from message..."); jobId = edg_wll_GetJobId(msg); if (!jobId || edg_wlc_JobIdParse(jobId,&j)) { - edg_wll_ll_log(LOG_DEBUG,"error.\n"); - edg_wll_ll_log(LOG_ERR,"ParseJobId(%s)\n",jobId?jobId:"NULL"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"Error getting jobId from message.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wlc_JobIdParse(%s)\n",jobId?jobId:"NULL"); answer = EINVAL; goto edg_wll_log_proto_server_end; } else { - edg_wll_ll_log(LOG_DEBUG,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Getting jobId from message...[ok]\n"); } free(jobId); jobId = edg_wlc_JobIdGetUnique(j); @@ -455,45 +534,43 @@ int edg_wll_log_proto_server(edg_wll_GssConnection *con, struct timeval *timeout else event->any.priority = 0; } - /* if not command, save message to file */ if(strstr(msg, "DG.TYPE=\"command\"") == NULL) { /* compose the name of the log file */ -// edg_wll_ll_log(LOG_DEBUG,"Composing filename from prefix \"%s\" and unique jobId \"%s\"...",prefix,jobId); count = strlen(prefix); strncpy(outfilename,prefix,count); count_total=count; strncpy(outfilename+count_total,".",1); count_total+=1; count=strlen(jobId); strncpy(outfilename+count_total,jobId,count); count_total+=count; outfilename[count_total]='\0'; -// edg_wll_ll_log(LOG_DEBUG,"o.k.\n"); +// glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Composing filename from prefix \"%s\" and unique jobId \"%s\"...[ok]",prefix,jobId); /* fopen and properly handle the filelock */ #ifdef LOGD_NOFILE - edg_wll_ll_log(LOG_NOTICE,"NOT writing message to \"%s\".\n",outfilename); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_INFO,"NOT writing message to \"%s\".\n",outfilename); filepos = 0; #else - edg_wll_ll_log(LOG_INFO,"Writing message to \"%s\"...",outfilename); if ( edg_wll_log_event_write(context, outfilename, msg, FCNTL_ATTEMPTS, FCNTL_TIMEOUT, &filepos) ) { char *errd; - SYSTEM_ERROR("edg_wll_log_event_write"); + // FIXME: there is probably not a correct errno + glite_common_log_SYS_ERROR("edg_wll_log_event_write"); answer = edg_wll_Error(context, NULL, &errd); - edg_wll_ll_log(LOG_ERR,"edg_wll_log_event_write error: %s\n",errd); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wll_log_event_write error: %s\n",errd); free(errd); goto edg_wll_log_proto_server_end; - } else edg_wll_ll_log(LOG_INFO,"o.k.\n"); + } else glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_INFO,"Writing message to \"%s\"... [ok]",outfilename); #endif } else { filepos = 0; } #ifdef LB_PERF - edg_wll_ll_log(LOG_INFO,"Calling perftest\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_INFO,"Calling perftest\n"); glite_wll_perftest_consumeEventString(msg); - edg_wll_ll_log(LOG_INFO,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_INFO,"Calling perftest... [done]\n"); #endif /* if not priority send now the answer back to client */ - if (!event->any.priority) { + if (!(event->any.priority & (EDG_WLL_LOGFLAG_SYNC|EDG_WLL_LOGFLAG_SYNC_COMPAT))) { if (!send_answer_back(con,answer,timeout)) { answer_sent = 1; } @@ -501,48 +578,45 @@ int edg_wll_log_proto_server(edg_wll_GssConnection *con, struct timeval *timeout /* send message via IPC (UNIX socket) */ if (!noipc) { - if (event->any.priority) { - edg_wll_ll_log(LOG_DEBUG,"Initializing 2nd UNIX socket (%s) for priority messages confirmation...",confirm_sock_name); + if (event->any.priority & (EDG_WLL_LOGFLAG_SYNC|EDG_WLL_LOGFLAG_SYNC_COMPAT)) { if(init_confirmation() < 0) { - edg_wll_ll_log(LOG_DEBUG,"error.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"Error initializing 2nd UNIX socket (%s) for priority messages confirmation.\n",confirm_sock_name); answer = errno; goto edg_wll_log_proto_server_end; } else { - edg_wll_ll_log(LOG_DEBUG,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Initializing 2nd UNIX socket (%s) for priority messages confirmation...[ok]\n",confirm_sock_name); } } - edg_wll_ll_log(LOG_DEBUG, - "Sending via IPC (UNIX socket \"%s\")\n\t" - "the message position %ld (%d bytes)", - socket_path, filepos, sizeof(filepos)); if ( edg_wll_log_event_send(context, socket_path, filepos, msg, msg_size, CONNECT_ATTEMPTS, timeout) ) { char *errd; - SYSTEM_ERROR("edg_wll_log_event_send"); + // XXX: probably not a SYSTEM ERROR + // glite_common_log_SYS_ERROR("edg_wll_log_event_send"); answer = edg_wll_Error(context, NULL, &errd); - edg_wll_ll_log(LOG_ERR,"edg_wll_log_event_send error: %s\n",errd); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"edg_wll_log_event_send error: %s\n",errd); free(errd); goto edg_wll_log_proto_server_end_1; - } else edg_wll_ll_log(LOG_DEBUG,"o.k.\n"); + } else glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG, + "Sending via IPC (UNIX socket \"%s\")\n\t" + "the message position %ld (%d bytes)... [ok]", + socket_path, filepos, sizeof(filepos)); - if (event->any.priority) { - edg_wll_ll_log(LOG_INFO,"Waiting for confirmation..."); + if (event->any.priority & (EDG_WLL_LOGFLAG_SYNC|EDG_WLL_LOGFLAG_SYNC_COMPAT)) { if ((count = wait_for_confirmation(timeout, &answer)) < 0) { - edg_wll_ll_log(LOG_INFO,"error.\n"); - edg_wll_ll_log(LOG_ERR,"wait_for_confirmation(): error.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_WARN,"Error waiting for confirmation.\n"); answer = errno; } else { - edg_wll_ll_log(LOG_INFO,"o.k.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Waiting for confirmation... [ok].\n"); if (count == 0) { - edg_wll_ll_log(LOG_DEBUG,"Waking up, timeout expired.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Waking up, timeout expired.\n"); answer = EAGAIN; } else { - edg_wll_ll_log(LOG_DEBUG,"Confirmation received, waking up.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"Confirmation received, waking up.\n"); } } } } else { - edg_wll_ll_log(LOG_DEBUG,"NOT sending via IPC.\n"); + glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_DEBUG,"NOT sending via IPC.\n"); } edg_wll_log_proto_server_end: @@ -559,7 +633,7 @@ edg_wll_log_proto_server_end: if (msg) free(msg); if (event) free(event); -// edg_wll_ll_log(LOG_INFO,"Done.\n"); +// glite_common_log(LOG_CATEGORY_ACCESS,LOG_PRIORITY_INFO,"Done.\n"); return answer; @@ -571,88 +645,3 @@ edg_wll_log_proto_server_end_1: goto edg_wll_log_proto_server_end; } -/* - *---------------------------------------------------------------------- - * - * edg_wll_log_proto_server_failure - handle protocol failures on the server side - * - * Returns: errno - * - *---------------------------------------------------------------------- - */ -int edg_wll_log_proto_server_failure(int code, edg_wll_GssStatus *gss_code, const char *text) -{ - const char *func = "edg_wll_log_proto_server()"; - int ret = 0; - - if(code>0) { - return(0); - } - switch(code) { - case EDG_WLL_GSS_ERROR_EOF: - edg_wll_ll_log(LOG_ERR,"%s: %s, EOF occured\n", func, text); - ret = EAGAIN; - break; - case EDG_WLL_GSS_ERROR_TIMEOUT: - edg_wll_ll_log(LOG_ERR,"%s: %s, timeout expired\n", func, text); - ret = EAGAIN; - break; - case EDG_WLL_GSS_ERROR_ERRNO: - SYSTEM_ERROR(func); - edg_wll_ll_log(LOG_ERR,"%s: %s, system error occured\n", func, text); - ret = EAGAIN; - break; - case EDG_WLL_GSS_ERROR_GSS: - { - char *gss_err; - - edg_wll_gss_get_error(gss_code, "GSS error occured", &gss_err); - edg_wll_ll_log(LOG_ERR,"%s: %s, %s\n", func, text, gss_err); - free(gss_err); - ret = EAGAIN; - break; - } - default: - edg_wll_ll_log(LOG_ERR,"%s: %s, unknown error occured\n"); - break; - } - return ret; -} - -/* - *---------------------------------------------------------------------- - * - * edg_wll_ll_log_init - initialize the logging level - * - *---------------------------------------------------------------------- - */ -void edg_wll_ll_log_init(int level) { - edg_wll_ll_log_level = level; -} - -/* - *---------------------------------------------------------------------- - * - * edg_wll_ll_log - print to stderr according to logging level - * serious messages are also written to syslog - * - *---------------------------------------------------------------------- - */ -void edg_wll_ll_log(int level, const char *fmt, ...) { - char *err_text; - va_list fmt_args; - - va_start(fmt_args, fmt); - vasprintf(&err_text, fmt, fmt_args); - va_end(fmt_args); - - if(level <= edg_wll_ll_log_level) - fprintf(stderr, "[%d] %s", (int) getpid(), err_text); - if(level <= LOG_ERR) { - openlog(NULL, LOG_PID | LOG_CONS, LOG_DAEMON); - syslog(level, "%s", err_text); - closelog(); - } - - if (err_text) free(err_text); -} diff --git a/org.glite.lb.logger/src/logd_proto.h b/org.glite.lb.logger/src/logd_proto.h index 2754e4a..993eec3 100644 --- a/org.glite.lb.logger/src/logd_proto.h +++ b/org.glite.lb.logger/src/logd_proto.h @@ -2,6 +2,23 @@ #define __EDG_WORKLOAD_LOGGING_LOCALLOGGER_LOGD_PROTO_H__ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + /** * \file edg/workload/logging/locallogger/logd_proto.h @@ -13,26 +30,12 @@ extern "C" { #endif - #include #include "glite/lb/log_proto.h" #include "glite/security/glite_gss.h" int edg_wll_log_proto_server(edg_wll_GssConnection *con, struct timeval *timeout, char *name, char *prefix, int noipc, int noparse); -int edg_wll_log_proto_server_failure(int code, edg_wll_GssStatus *gss_code, const char *text); - -#define SYSTEM_ERROR(my_err) { \ - if (errno !=0 ) \ - edg_wll_ll_log(LOG_ERR,"%s: %s\n",my_err,strerror(errno)); \ - else \ - edg_wll_ll_log(LOG_ERR,"%s\n",my_err); } - -/* locallogger daemon error handling */ -extern int edg_wll_ll_log_level; -void edg_wll_ll_log_init(int level); -void edg_wll_ll_log(int level, const char *fmt, ...); - /* fcntl defaults */ #define FCNTL_ATTEMPTS 5 diff --git a/org.glite.lb.logger/src/perftest_il.sh b/org.glite.lb.logger/src/perftest_il.sh index 6121555..45d16df 100644 --- a/org.glite.lb.logger/src/perftest_il.sh +++ b/org.glite.lb.logger/src/perftest_il.sh @@ -1,4 +1,20 @@ #!/bin/bash +# +# Copyright (c) Members of the EGEE Collaboration. 2004-2010. +# See http://www.eu-egee.org/partners for details on the copyright holders. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# numjobs=10 @@ -11,11 +27,14 @@ fi . $STAGEDIR/sbin/perftest_common.sh +DBNAME=${DBNAME:-lbserver20} +export LBDB=lbserver/@localhost:$DBNAME + DEBUG=${DEBUG:-0} # CONSUMER_ARGS= # PERFTEST_COMPONENT= # COMPONENT_ARGS= -#LOGJOBS_ARGS="" +LOGJOBS_ARGS="-s /tmp/interlogger.perftest" check_test_files || exit 1 @@ -59,7 +78,7 @@ echo "" fi PERFTEST_CONSUMER=$STAGEDIR/bin/glite-lb-interlogd-perf-empty -CONSUMER_ARGS="-d $COMM_ARGS" +CONSUMER_ARGS="-i /tmp/perftest_il.pid -d $COMM_ARGS" } group_a_test_a () @@ -75,7 +94,7 @@ group_a_test_b () { echo -n "b)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm -f \{\} \; } @@ -141,38 +160,38 @@ LOGJOBS_ARGS=" $COMM_ARGS" group_b_test_a () { - CONSUMER_ARGS="-d --nosend --noparse $COMM_ARGS" + CONSUMER_ARGS="-i /tmp/perftest_il.pid -d --nosend --noparse $COMM_ARGS" echo -n "a)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm \{\} \; } group_b_test_b () { - CONSUMER_ARGS="-d --nosend --nosync $COMM_ARGS" + CONSUMER_ARGS="-i /tmp/perftest_il.pid -d --nosend --nosync $COMM_ARGS" echo -n "b)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm \{\} \; } group_b_test_c () { - CONSUMER_ARGS="-d --nosend --norecover $COMM_ARGS" + CONSUMER_ARGS="-i /tmp/perftest_il.pid -d --nosend --norecover $COMM_ARGS" echo -n "c)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm \{\} \; } group_b_test_x () { - CONSUMER_ARGS="-d --nosend --nosync --norecover $COMM_ARGS" + CONSUMER_ARGS="-i /tmp/perftest_il.pid -d --nosend --nosync --norecover $COMM_ARGS" echo -n "x)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm \{\} \; } group_b_test_d () @@ -182,11 +201,11 @@ group_b_test_d () group_b_test_e () { - CONSUMER_ARGS="-d --nosend $COMM_ARGS" + CONSUMER_ARGS="-i /tmp/perftest_il.pid -d --nosend $COMM_ARGS" echo -n "e)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm \{\} \; } # echo "-------------------------------" @@ -254,63 +273,63 @@ echo "" fi PERFTEST_CONSUMER=$STAGEDIR/bin/glite-lb-bkserverd -CONSUMER_ARGS="-d --perf-sink=1" +CONSUMER_ARGS="--silent -S /tmp -D /tmp -t 1 -d --perf-sink=1 -p 10500 -w 10503" PERFTEST_COMPONENT=$STAGEDIR/bin/glite-lb-interlogd-perf -LOGJOBS_ARGS=" $COMM_ARGS" +LOGJOBS_ARGS=" -m localhost:10500 $COMM_ARGS" } group_c_test_a () { - COMPONENT_ARGS="-d --noparse $COMM_ARGS" + COMPONENT_ARGS="-i /tmp/perftest_il.pid -d --noparse $COMM_ARGS" echo -n "a)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm \{\} \; } group_c_test_b () { - COMPONENT_ARGS="-d --nosync $COMM_ARGS" + COMPONENT_ARGS="-i /tmp/perftest_il.pid -d --nosync $COMM_ARGS" echo -n "b)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm \{\} \; } group_c_test_c () { - COMPONENT_ARGS="-d --norecover $COMM_ARGS" + COMPONENT_ARGS="-i /tmp/perftest_il.pid -d --norecover $COMM_ARGS" echo -n "c)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm \{\} \; } group_c_test_x () { - COMPONENT_ARGS="-d --nosync --norecover $COMM_ARGS" + COMPONENT_ARGS="-i /tmp/perftest_il.pid -d --nosync --norecover $COMM_ARGS" echo -n "x)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm \{\} \; } group_c_test_d () { - COMPONENT_ARGS="-d --lazy=10 --nosync --norecover $COMM_ARGS" + COMPONENT_ARGS="-i /tmp/perftest_il.pid -d --lazy=10 --nosync --norecover $COMM_ARGS" echo -n "d)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm \{\} \; } group_c_test_e () { - COMPONENT_ARGS="-d $COMM_ARGS" + COMPONENT_ARGS="-i /tmp/perftest_il.pid -d $COMM_ARGS" echo -n "e)" run_test il $numjobs print_result - rm -f /tmp/perftest.log.* + find /tmp -maxdepth 1 -name perftest.log.\* -exec rm \{\} \; } @@ -344,7 +363,7 @@ do echo -n "Your choice: " read -e TEST_VARIANT done - echo -e "\tavg_job \t big_job \t avg_dag \t big_dag" + print_result_header fi if [[ "x$TEST_VARIANT" = "x*" ]] @@ -357,6 +376,7 @@ do for variant in $TEST_VARIANT do + export PERFTEST_NAME="il_${group}${variant}" group_${group}_test_${variant} done done diff --git a/org.glite.lb.logger/src/perftest_ll.sh b/org.glite.lb.logger/src/perftest_ll.sh index d6fc67d..d8eec47 100644 --- a/org.glite.lb.logger/src/perftest_ll.sh +++ b/org.glite.lb.logger/src/perftest_ll.sh @@ -1,4 +1,20 @@ #!/bin/bash +# +# Copyright (c) Members of the EGEE Collaboration. 2004-2010. +# See http://www.eu-egee.org/partners for details on the copyright holders. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# numjobs=1 @@ -114,7 +130,7 @@ then echo -n "Your choice: " read -e TEST_VARIANT done - echo -e "\tavg_job \t big_job \t avg_dag \t big_dag" + print_result_header fi if [[ "x$TEST_VARIANT" = "x*" ]] diff --git a/org.glite.lb.logger/src/plugin_mgr.c b/org.glite.lb.logger/src/plugin_mgr.c new file mode 100644 index 0000000..0611ba8 --- /dev/null +++ b/org.glite.lb.logger/src/plugin_mgr.c @@ -0,0 +1,88 @@ +#ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#include "interlogd.h" + +#include +#include +#include +#include + +struct plugin_list { + struct il_output_plugin plugin_def; + struct plugin_list *next; +}; + +static struct plugin_list *plugins = NULL; + +#define DL_RESOLVESYM(var, handle, name, type) \ + dlerror(); \ + var = (type) dlsym(handle, name); \ + if(var == NULL) { \ + snprintf(err, sizeof(err), "plugin_init: error resolving %s: %s", name, dlerror()); \ + set_error(IL_DL, ENOENT, err); \ + return -1; \ + } + +int plugin_mgr_init(const char *plugin_name, char *cfg) +{ + char err[256]; + void *dl_handle; + struct plugin_list *plugin; + + dlerror(); + dl_handle = dlopen(plugin_name, RTLD_LAZY); + if(dl_handle == NULL) { + snprintf(err, sizeof(err), "plugin_init: error opening dynamic library: %s", dlerror()); + set_error(IL_SYS, ENOENT, err); + return -1; + } + dlerror(); + + plugin = malloc(sizeof(*plugin)); + if(plugin == NULL) { + set_error(IL_NOMEM, ENOMEM, "plugin_init: error allocating plugin description"); + return -1; + } + + plugin->next = plugins; + plugins = plugin; + DL_RESOLVESYM(plugin->plugin_def.plugin_init, dl_handle, "plugin_init", int(*)(char *)); + DL_RESOLVESYM(plugin->plugin_def.plugin_supports_scheme, dl_handle, "plugin_supports_scheme", int(*)(const char *)); + DL_RESOLVESYM(plugin->plugin_def.event_queue_connect, dl_handle, "event_queue_connect", int (*)(struct event_queue*)); + DL_RESOLVESYM(plugin->plugin_def.event_queue_send, dl_handle, "event_queue_send", int (*)(struct event_queue *)); + DL_RESOLVESYM(plugin->plugin_def.event_queue_close, dl_handle, "event_queue_close", int (*)(struct event_queue *)); + + return (*plugin->plugin_def.plugin_init)(cfg); +} + + +struct il_output_plugin * +plugin_get(const char *scheme) +{ + struct plugin_list *outp; + + for(outp = plugins; outp != NULL; outp = outp->next) { + if((outp->plugin_def.plugin_supports_scheme)(scheme)) { + return &outp->plugin_def; + } + } + + return NULL; +} diff --git a/org.glite.lb.logger/src/queue_mgr.c b/org.glite.lb.logger/src/queue_mgr.c index b76c397..ac05324 100644 --- a/org.glite.lb.logger/src/queue_mgr.c +++ b/org.glite.lb.logger/src/queue_mgr.c @@ -1,10 +1,29 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include #include +#include -#include "glite/lb/consumer.h" +#include "glite/jobid/cjobid.h" +#include "glite/lb/context.h" #include "interlogd.h" @@ -17,7 +36,9 @@ struct queue_list { #endif }; +#if !defined(IL_NOTIFICATIONS) static struct event_queue *log_queue; +#endif static struct queue_list *queues; @@ -88,7 +109,7 @@ queue_list_add(struct queue_list **ql, const char *dest, struct event_queue *eq) return(-1); } el->queue = eq; - el->next = queues; + el->next = *ql; *ql = el; return 0; } @@ -122,6 +143,8 @@ queue_list_get(char *job_id_s) char *dest; struct queue_list *q; struct event_queue *eq; + struct il_output_plugin *outp; + #if !defined(IL_NOTIFICATIONS) IL_EVENT_ID_T job_id; @@ -135,8 +158,10 @@ queue_list_get(char *job_id_s) dest = jobid2dest(job_id); edg_wlc_JobIdFree(job_id); + outp = NULL; #else dest = job_id_s; + outp = plugin_get(dest); #endif if(dest == NULL) @@ -148,7 +173,7 @@ queue_list_get(char *job_id_s) #endif return(q->queue); } else { - eq = event_queue_create(dest); + eq = event_queue_create(dest, outp); if(eq) queue_list_add(&queues, dest, eq); #if !defined(IL_NOTIFICATIONS) @@ -171,7 +196,7 @@ queue_list_init(char *ls) { #if !defined(IL_NOTIFICATIONS) /* create queue for log server */ - log_queue = event_queue_create(ls); + log_queue = event_queue_create(ls, NULL); if(log_queue == NULL) return(-1); #endif diff --git a/org.glite.lb.logger/src/queue_mgr_http.c b/org.glite.lb.logger/src/queue_mgr_http.c new file mode 100644 index 0000000..f5e767f --- /dev/null +++ b/org.glite.lb.logger/src/queue_mgr_http.c @@ -0,0 +1,181 @@ +#ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#include +#include +#include + +#include "glite/jobid/cjobid.h" +#include "glite/lb/context.h" + +#include "interlogd.h" + +struct queue_list { + struct event_queue *queue; + char *dest; + struct queue_list *next; + time_t expires; +}; + +static struct event_queue *log_queue; +static struct queue_list *queues; + + +static +int +queue_list_create() +{ + queues = NULL; + + return(0); +} + + +static +int +queue_list_find(struct queue_list *ql, const char *dest, struct queue_list **el, struct queue_list **prev) +{ + struct queue_list *q, *p; + + assert(el != NULL); + + *el = NULL; + if(prev) + *prev = NULL; + + if(ql == NULL) + return(0); + + q = NULL; + p = ql; + + while(p) { + if(strcmp(p->dest, dest) == 0) { + *el = p; + if(prev) + *prev = q; + return(1); + } + + q = p; + p = p->next; + }; + + return(0); +} + + +static +int +queue_list_add(struct queue_list **ql, const char *dest, struct event_queue *eq) +{ + struct queue_list *el; + + assert(dest != NULL); + assert(eq != NULL); + assert(ql != NULL); + + el = malloc(sizeof(*el)); + if(el == NULL) { + set_error(IL_NOMEM, ENOMEM, "queue_list_add: not enough room for new queue"); + return(-1); + } + + el->dest = strdup(dest); + if(el->dest == NULL) { + free(el); + set_error(IL_NOMEM, ENOMEM, "queue_list_add: not enough memory for new queue"); + return(-1); + } + el->queue = eq; + el->next = *ql; + *ql = el; + return 0; +} + + +struct event_queue * +queue_list_get(char *job_id_s) +{ + char *dest; + struct queue_list *q; + struct event_queue *eq; + dest = job_id_s; + + if(dest == NULL) + return(NULL); + + if(queue_list_find(queues, dest, &q, NULL)) { + return(q->queue); + } else { + eq = event_queue_create(dest); + if(eq) + queue_list_add(&queues, dest, eq); + return(eq); + } +} + + +int +queue_list_is_log(struct event_queue *eq) +{ + return(eq == queue_list_get(NULL)); +} + + +int +queue_list_init(char *ls) +{ + return(queue_list_create()); +} + + +static struct queue_list *current; + + +struct event_queue * +queue_list_first() +{ + current = queues; + return(current ? current->queue : NULL); +} + + +struct event_queue * +queue_list_next() +{ + current = current ? current->next : NULL; + return(current ? current->queue : NULL); +} + + +int +queue_list_remove_queue(struct event_queue *eq) +{ + assert(eq != NULL); + + free(eq); + return(1); +} + + + +/* Local Variables: */ +/* c-indentation-style: gnu */ +/* End: */ diff --git a/org.glite.lb.logger/src/queue_thread.c b/org.glite.lb.logger/src/queue_thread.c index 20c25e7..7817d75 100644 --- a/org.glite.lb.logger/src/queue_thread.c +++ b/org.glite.lb.logger/src/queue_thread.c @@ -1,9 +1,27 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include #include #include +#include #include "interlogd.h" @@ -13,7 +31,7 @@ queue_thread_cleanup(void *q) { struct event_queue *eq = (struct event_queue *)q; - il_log(LOG_WARNING, "thread %d exits\n", eq->thread_id); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_WARN, "thread %d exits", eq->thread_id); /* unlock all held locks */ /* FIXME: check that the thread always exits when holding these locks; @@ -48,11 +66,14 @@ queue_thread(void *q) int exit_timeout = EXIT_TIMEOUT; if(init_errors(0) < 0) { - il_log(LOG_ERR, "Error initializing thread specific data, exiting!"); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_ERROR, + "Error initializing thread specific data, exiting!"); pthread_exit(NULL); } - il_log(LOG_DEBUG, " started new thread for delivery to %s:%d\n", eq->dest_name, eq->dest_port); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, + " started new thread for delivery to %s", + eq->dest); pthread_cleanup_push(queue_thread_cleanup, q); @@ -74,23 +95,28 @@ queue_thread(void *q) if(lazy_close && close_timeout) { ret = event_queue_wait(eq, close_timeout); if(ret == 1) {/* timeout? */ - event_queue_close(eq); - il_log(LOG_DEBUG, " connection to %s:%d closed\n", - eq->dest_name, eq->dest_port); + (*eq->event_queue_close)(eq); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " connection to %s closed", + eq->dest); } close_timeout = 0; } else { ret = event_queue_wait(eq, exit_timeout); if(ret == 1) { - il_log(LOG_INFO, " thread idle for more than %d seconds, exiting\n", exit_timeout); - event_queue_close(eq); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_INFO, + " thread idle for more than %d seconds, exiting", + exit_timeout); + (*eq->event_queue_close)(eq); event_queue_cond_unlock(eq); pthread_exit((void*)0); } } if(ret < 0) { /* error waiting */ - il_log(LOG_ERR, "queue_thread: %s\n", error_get_msg()); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_WARN, + "queue_thread: %s", + error_get_msg()); event_queue_cond_unlock(eq); pthread_exit((void*)-1); } @@ -103,44 +129,58 @@ queue_thread(void *q) event_queue_cond_unlock(eq); /* discard expired events */ - il_log(LOG_DEBUG, " discarding expired events\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, " discarding expired events"); now = time(NULL); event_queue_move_events(eq, NULL, cmp_expires, &now); if(!event_queue_empty(eq)) { /* deliver pending events */ - il_log(LOG_DEBUG, " attempting delivery to %s:%d\n", eq->dest_name, eq->dest_port); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " attempting delivery to %s", + eq->dest); /* connect to server */ - if((ret=event_queue_connect(eq)) == 0) { + if((ret=(*eq->event_queue_connect)(eq)) == 0) { /* not connected */ if(error_get_maj() != IL_OK) - il_log(LOG_ERR, "queue_thread: %s\n", error_get_msg()); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, + "queue_thread: %s", error_get_msg()); #if defined(IL_NOTIFICATIONS) - il_log(LOG_INFO, " could not connect to client %s, waiting for retry\n", eq->dest_name); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_INFO, + " could not connect to client %s, waiting for retry", + eq->dest); #else - il_log(LOG_INFO, " could not connect to bookkeeping server %s, waiting for retry\n", eq->dest_name); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_INFO, + " could not connect to bookkeeping server %s, waiting for retry", + eq->dest); #endif retrycnt++; } else { retrycnt = 0; /* connected, send events */ - switch(ret=event_queue_send(eq)) { + switch(ret=(*eq->event_queue_send)(eq)) { case 0: /* there was an error and we still have events to send */ if(error_get_maj() != IL_OK) - il_log(LOG_ERR, "queue_thread: %s\n", error_get_msg()); - il_log(LOG_DEBUG, " events still waiting\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, + "queue_thread: %s", + error_get_msg()); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " events still waiting"); break; case 1: /* hey, we are done for now */ - il_log(LOG_DEBUG, " all events for %s sent\n", eq->dest_name); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " all events for %s sent", + eq->dest); break; default: /* internal error */ - il_log(LOG_ERR, "queue_thread: %s\n", error_get_msg()); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + "queue_thread: %s", + error_get_msg()); exit = 1; break; @@ -150,9 +190,10 @@ queue_thread(void *q) if((ret == 1) && lazy_close) close_timeout = default_close_timeout; else { - event_queue_close(eq); - il_log(LOG_DEBUG, " connection to %s:%d closed\n", - eq->dest_name, eq->dest_port); + (*eq->event_queue_close)(eq); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " connection to %sclosed", + eq->dest); } } } @@ -164,7 +205,8 @@ queue_thread(void *q) /* Check if we are flushing and if we are, report status to master */ if(eq->flushing == 1) { - il_log(LOG_DEBUG, " flushing mode detected, reporting status\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " flushing mode detected, reporting status"); /* 0 - events waiting, 1 - events sent, < 0 - some error */ eq->flush_result = ret; eq->flushing = 2; @@ -182,7 +224,8 @@ queue_thread(void *q) which may cure server kicking us out after given number of connections */ #ifndef LB_PERF if((ret == 0) && (retrycnt > 0)) { - il_log(LOG_WARNING, " sleeping\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " sleeping"); event_queue_sleep(eq); } #endif @@ -208,18 +251,22 @@ queue_thread(void *q) int event_queue_create_thread(struct event_queue *eq) { + pthread_attr_t attr; + assert(eq != NULL); event_queue_lock(eq); /* if there is a thread already, just return */ - if(eq->thread_id > 0) { + if(eq->thread_id != 0) { event_queue_unlock(eq); return(0); } /* create the thread itself */ - if(pthread_create(&eq->thread_id, NULL, queue_thread, eq) < 0) { + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 16384); + if(pthread_create(&eq->thread_id, &attr, queue_thread, eq) < 0) { eq->thread_id = 0; set_error(IL_SYS, errno, "event_queue_create_thread: error creating new thread"); event_queue_unlock(eq); diff --git a/org.glite.lb.logger/src/recover.c b/org.glite.lb.logger/src/recover.c index 981b2b6..250a40a 100644 --- a/org.glite.lb.logger/src/recover.c +++ b/org.glite.lb.logger/src/recover.c @@ -1,6 +1,24 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include +#include #include #include @@ -14,42 +32,61 @@ void * recover_thread(void *q) { if(init_errors(0) < 0) { - il_log(LOG_ERR, "Error initializing thread specific data, exiting!"); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_ERROR, + "Error initializing thread specific data, exiting!"); pthread_exit(NULL); } while(1) { - il_log(LOG_INFO, "Looking up event files...\n"); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + "Looking up event files."); if(event_store_init(file_prefix) < 0) { - il_log(LOG_ERR, "recover_thread: %s\n", error_get_msg()); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, + "recover_thread: %s", error_get_msg()); exit(1); } if(event_store_recover_all() < 0) { - il_log(LOG_ERR, "recover_thread: %s\n", error_get_msg()); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, + "recover_thread: %s", error_get_msg()); exit(1); } if(event_store_cleanup() < 0) { - il_log(LOG_ERR, "recover_thread: %s\n", error_get_msg()); + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, + "recover_thread: %s", error_get_msg()); exit(1); } - il_log(LOG_INFO, "Reloading certificate...\n"); - if(pthread_mutex_lock(&cred_handle_lock) < 0) - abort(); - { - gss_cred_id_t new_cred_handle = GSS_C_NO_CREDENTIAL; - OM_uint32 min_stat; + glite_common_log(LOG_CATEGORY_SECURITY, LOG_PRIORITY_DEBUG, "Checking for new certificate."); + if (edg_wll_gss_watch_creds(cert_file, &cert_mtime) > 0) { + edg_wll_GssCred new_creds = NULL; int ret; ret = edg_wll_gss_acquire_cred_gsi(cert_file,key_file, - &new_cred_handle, NULL, NULL); - if (new_cred_handle != GSS_C_NO_CREDENTIAL) { - gss_release_cred(&min_stat, &cred_handle); - cred_handle = new_cred_handle; - il_log(LOG_INFO, "New certificate found and deployed.\n"); + &new_creds, NULL); + if (new_creds != NULL) { + if(pthread_mutex_lock(&cred_handle_lock) < 0) + abort(); + /* if no one is using the old credentials, release them */ + if(cred_handle && cred_handle->counter == 0) { + edg_wll_gss_release_cred(&cred_handle->creds, NULL); + free(cred_handle); + glite_common_log(LOG_CATEGORY_SECURITY, LOG_PRIORITY_DEBUG, + " freed old credentials"); + } + cred_handle = malloc(sizeof(*cred_handle)); + if(cred_handle == NULL) { + glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_FATAL, + "Failed to allocate structure for credentials."); + exit(EXIT_FAILURE); + } + cred_handle->creds = new_creds; + cred_handle->counter = 0; + if(pthread_mutex_unlock(&cred_handle_lock) < 0) + abort(); + glite_common_log(LOG_CATEGORY_SECURITY, LOG_PRIORITY_INFO, + "New certificate %s found and deployed.", + new_creds->name); } } - if(pthread_mutex_unlock(&cred_handle_lock) < 0) - abort(); - sleep(INPUT_TIMEOUT); + sleep(RECOVER_TIMEOUT); } } diff --git a/org.glite.lb.logger/src/send_event.c b/org.glite.lb.logger/src/send_event.c index 761b300..b48ab23 100644 --- a/org.glite.lb.logger/src/send_event.c +++ b/org.glite.lb.logger/src/send_event.c @@ -1,10 +1,26 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include -#ifdef HAVE_UNISTD_H +#include #include -#endif #include #include #include @@ -15,7 +31,7 @@ * - L/B server protocol handling routines */ -#include "glite/wmsutils/jobid/cjobid.h" +#include "glite/jobid/cjobid.h" #include "glite/lb/il_string.h" #include "glite/lb/context.h" @@ -59,7 +75,9 @@ send_confirmation(long lllid, int code) } ret = 1; - il_log(LOG_DEBUG, " sent code %d back to client\n", code); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " sent code %d back to client", + code); out: close(sock); @@ -102,7 +120,8 @@ static int gss_reader(void *user_data, char *buffer, int max_len) { - int ret, len; + int ret; + size_t len; struct reader_data *data = (struct reader_data *)user_data; edg_wll_GssStatus gss_stat; @@ -132,7 +151,7 @@ get_reply(struct event_queue *eq, char **buf, int *code_min) { char *msg=NULL; int ret, code; - int len, l; + int len; struct timeval tv; struct reader_data data; @@ -165,6 +184,7 @@ event_queue_connect(struct event_queue *eq) int ret; struct timeval tv; edg_wll_GssStatus gss_stat; + cred_handle_t *local_cred_handle; assert(eq != NULL); @@ -172,16 +192,35 @@ event_queue_connect(struct event_queue *eq) if(!nosend) { #endif - if(eq->gss.context == GSS_C_NO_CONTEXT) { + if(eq->gss.context == NULL) { tv.tv_sec = TIMEOUT; tv.tv_usec = 0; + + /* get pointer to the credentials */ if(pthread_mutex_lock(&cred_handle_lock) < 0) abort(); - il_log(LOG_DEBUG, " trying to connect to %s:%d\n", eq->dest_name, eq->dest_port); - ret = edg_wll_gss_connect(cred_handle, eq->dest_name, eq->dest_port, &tv, &eq->gss, &gss_stat); + local_cred_handle = cred_handle; + local_cred_handle->counter++; if(pthread_mutex_unlock(&cred_handle_lock) < 0) abort(); + + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " trying to connect to %s:%d", + eq->dest_name, eq->dest_port); + ret = edg_wll_gss_connect(local_cred_handle->creds, eq->dest_name, eq->dest_port, &tv, &eq->gss, &gss_stat); + if(pthread_mutex_lock(&cred_handle_lock) < 0) + abort(); + /* check if we need to release the credentials */ + --local_cred_handle->counter; + if(local_cred_handle != cred_handle && local_cred_handle->counter == 0) { + edg_wll_gss_release_cred(&local_cred_handle->creds, NULL); + free(local_cred_handle); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, " freed credentials, not used anymore"); + } + if(pthread_mutex_unlock(&cred_handle_lock) < 0) + abort(); + if(ret < 0) { char *gss_err = NULL; @@ -190,10 +229,11 @@ event_queue_connect(struct event_queue *eq) set_error(IL_DGGSS, ret, (ret == EDG_WLL_GSS_ERROR_GSS) ? gss_err : "event_queue_connect: edg_wll_gss_connect"); if (gss_err) free(gss_err); - eq->gss.context = GSS_C_NO_CONTEXT; + eq->gss.context = NULL; eq->timeout = TIMEOUT; return(0); } + eq->first_event_sent = 0; } #ifdef LB_PERF @@ -213,10 +253,11 @@ event_queue_close(struct event_queue *eq) if(!nosend) { #endif - if(eq->gss.context != GSS_C_NO_CONTEXT) { + if(eq->gss.context != NULL) { edg_wll_gss_close(&eq->gss, NULL); - eq->gss.context = GSS_C_NO_CONTEXT; + eq->gss.context = NULL; } + eq->first_event_sent = 0; #ifdef LB_PERF } #endif @@ -231,13 +272,12 @@ event_queue_close(struct event_queue *eq) int event_queue_send(struct event_queue *eq) { - int events_sent = 0; assert(eq != NULL); #ifdef LB_PERF if(!nosend) { #endif - if(eq->gss.context == GSS_C_NO_CONTEXT) + if(eq->gss.context == NULL) return(0); #ifdef LB_PERF } @@ -257,23 +297,19 @@ event_queue_send(struct event_queue *eq) if(event_queue_get(eq, &msg) < 0) return(-1); - il_log(LOG_DEBUG, " trying to deliver event at offset %d for job %s\n", msg->offset, msg->job_id_s); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " trying to deliver event at offset %d for job %s", + msg->offset, msg->job_id_s); #ifdef LB_PERF if(!nosend) { #endif - if(msg->len) { + if (msg->len) { tv.tv_sec = TIMEOUT; tv.tv_usec = 0; ret = edg_wll_gss_write_full(&eq->gss, msg->msg, msg->len, &tv, &bytes_sent, &gss_stat); - /* commented out due to the conflict with following ljocha's code if(ret < 0) { - eq->timeout = TIMEOUT; - return(0); - } - */ - if(ret < 0) { - if (ret == EDG_WLL_GSS_ERROR_ERRNO && errno == EPIPE && events_sent > 0) + if (ret == EDG_WLL_GSS_ERROR_ERRNO && errno == EPIPE && eq->first_event_sent ) eq->timeout = 0; else eq->timeout = TIMEOUT; @@ -282,18 +318,19 @@ event_queue_send(struct event_queue *eq) if((code = get_reply(eq, &rep, &code_min)) < 0) { /* could not get the reply properly, so try again later */ - if (events_sent>0) { + if (eq->first_event_sent) { /* could be expected server connection preemption */ clear_error(); eq->timeout = 1; } else { eq->timeout = TIMEOUT; - il_log(LOG_ERR, " error reading server %s reply:\n %s\n", eq->dest_name, error_get_msg()); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_WARN, " error reading server %s reply: %s", + eq->dest_name, error_get_msg()); } return(0); } - } - else { code = LB_OK; code_min = 0; rep = strdup("not sending empty message"); } + } + else { code = LB_OK; code_min = 0; rep = strdup("not sending empty message"); } #ifdef LB_PERF } else { glite_wll_perftest_consumeEventIlMsg(msg->msg+17); @@ -302,7 +339,9 @@ event_queue_send(struct event_queue *eq) } #endif - il_log(LOG_DEBUG, " event sent, server %s replied with %d, %s\n", eq->dest_name, code, rep); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_DEBUG, + " event sent, server %s replied with %d, %s", + eq->dest_name, code, rep); free(rep); /* the reply is back here */ @@ -312,6 +351,8 @@ event_queue_send(struct event_queue *eq) case LB_NOMEM: /* NOT USED: case LB_SYS: */ /* NOT USED: case LB_AUTH: */ + case LB_PERM: + case LB_DBERR: /* non fatal errors (for us) */ eq->timeout = TIMEOUT; return(0); @@ -319,10 +360,10 @@ event_queue_send(struct event_queue *eq) case LB_OK: /* event succesfully delivered */ - default: /* LB_DBERR, LB_PROTO */ + default: /* LB_PROTO */ /* the event was not accepted by the server */ /* update the event pointer */ - if(event_store_commit(msg->es, msg->ev_len, queue_list_is_log(eq)) < 0) + if(event_store_commit(msg->es, msg->ev_len, queue_list_is_log(eq), msg->generation) < 0) /* failure committing message, this is bad */ return(-1); /* if we have just delivered priority message from the queue, send confirmation */ @@ -335,10 +376,12 @@ event_queue_send(struct event_queue *eq) if((ret == 0) && (error_get_maj() != IL_OK)) - il_log(LOG_ERR, "send_event: %s\n", error_get_msg()); + glite_common_log(IL_LOG_CATEGORY, LOG_PRIORITY_ERROR, + "send_event: %s", + error_get_msg()); event_queue_remove(eq); - events_sent++; + eq->first_event_sent = 1; break; } /* switch */ diff --git a/org.glite.lb.logger/src/send_event_http.c b/org.glite.lb.logger/src/send_event_http.c new file mode 100644 index 0000000..ce79f73 --- /dev/null +++ b/org.glite.lb.logger/src/send_event_http.c @@ -0,0 +1,299 @@ +#ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include + + +/* + * - L/B server protocol handling routines + */ + +#include "glite/jobid/cjobid.h" +#include "glite/lb/il_string.h" +#include "glite/lb/context.h" + +#include "interlogd.h" + +struct reader_data { + edg_wll_GssConnection *gss; + struct timeval *timeout; +}; + + +static +int +gss_reader(void *user_data, char *buffer, int max_len) +{ + int ret; + struct reader_data *data = (struct reader_data *)user_data; + edg_wll_GssStatus gss_stat; + + ret = edg_wll_gss_read(data->gss, buffer, max_len, data->timeout, &gss_stat); + if(ret < 0) { + char *gss_err = NULL; + + if(ret == EDG_WLL_GSS_ERROR_GSS) { + edg_wll_gss_get_error(&gss_stat, "get_reply", &gss_err); + set_error(IL_DGGSS, ret, gss_err); + free(gss_err); + } else + set_error(IL_DGGSS, ret, "get_reply"); + } + return(ret); +} + + +/* + * Read reply from server. + * Returns: -1 - error reading message, + * code > 0 - http status code from server + */ +static +int +get_reply(struct event_queue *eq, char **buf, int *code_min) +{ + int ret, code; + int len; + struct timeval tv; + struct reader_data data; + il_http_message_t msg; + + tv.tv_sec = TIMEOUT; + tv.tv_usec = 0; + data.gss = &eq->gss; + data.timeout = &tv; + len = receive_http(&data, gss_reader, &msg); + if(len < 0) { + set_error(IL_PROTO, LB_PROTO, "get_reply: error reading server reply"); + return(-1); + } + if(msg.data) free(msg.data); + if(msg.reply_string) *buf = msg.reply_string; + *code_min = 0; /* XXX fill in flag for fault */ + return(msg.reply_code); +} + + + +/* + * Returns: 0 - not connected, timeout set, 1 - OK + */ +int +event_queue_connect(struct event_queue *eq) +{ + int ret; + struct timeval tv; + edg_wll_GssStatus gss_stat; + cred_handle_t *local_cred_handle; + + assert(eq != NULL); + +#ifdef LB_PERF + if(!nosend) { +#endif + + if(eq->gss.context == NULL) { + + tv.tv_sec = TIMEOUT; + tv.tv_usec = 0; + + /* get pointer to the credentials */ + if(pthread_mutex_lock(&cred_handle_lock) < 0) + abort(); + local_cred_handle = cred_handle; + local_cred_handle->counter++; + if(pthread_mutex_unlock(&cred_handle_lock) < 0) + abort(); + + il_log(LOG_DEBUG, " trying to connect to %s:%d\n", eq->dest_name, eq->dest_port); + ret = edg_wll_gss_connect(local_cred_handle->creds, eq->dest_name, eq->dest_port, &tv, &eq->gss, &gss_stat); + if(pthread_mutex_lock(&cred_handle_lock) < 0) + abort(); + /* check if we need to release the credentials */ + --local_cred_handle->counter; + if(local_cred_handle != cred_handle && local_cred_handle->counter == 0) { + edg_wll_gss_release_cred(&local_cred_handle->creds, NULL); + free(local_cred_handle); + il_log(LOG_DEBUG, " freed credentials, not used anymore\n"); + } + if(pthread_mutex_unlock(&cred_handle_lock) < 0) + abort(); + + if(ret < 0) { + char *gss_err = NULL; + + if (ret == EDG_WLL_GSS_ERROR_GSS) + edg_wll_gss_get_error(&gss_stat, "event_queue_connect: edg_wll_gss_connect", &gss_err); + set_error(IL_DGGSS, ret, + (ret == EDG_WLL_GSS_ERROR_GSS) ? gss_err : "event_queue_connect: edg_wll_gss_connect"); + if (gss_err) free(gss_err); + eq->gss.context = NULL; + eq->timeout = TIMEOUT; + return(0); + } + } + +#ifdef LB_PERF + } +#endif + + return(1); +} + + +int +event_queue_close(struct event_queue *eq) +{ + assert(eq != NULL); + +#ifdef LB_PERF + if(!nosend) { +#endif + + if(eq->gss.context != NULL) { + edg_wll_gss_close(&eq->gss, NULL); + eq->gss.context = NULL; + } +#ifdef LB_PERF + } +#endif + return(0); +} + + +/* + * Send all events from the queue. + * Returns: -1 - system error, 0 - not sent, 1 - queue empty + */ +int +event_queue_send(struct event_queue *eq) +{ + int events_sent = 0; + assert(eq != NULL); + +#ifdef LB_PERF + if(!nosend) { +#endif + if(eq->gss.context == NULL) + return(0); +#ifdef LB_PERF + } +#endif + + /* feed the server with events */ + while (!event_queue_empty(eq)) { + struct server_msg *msg; + char *rep; + int ret, code, code_min; + size_t bytes_sent; + struct timeval tv; + edg_wll_GssStatus gss_stat; + + clear_error(); + + if(event_queue_get(eq, &msg) < 0) + return(-1); + + il_log(LOG_DEBUG, " trying to deliver event at offset %d for job %s\n", msg->offset, msg->job_id_s); + +#ifdef LB_PERF + if(!nosend) { +#endif + /* XXX: ljocha -- does it make sense to send empty messages ? */ + if (msg->len) { + tv.tv_sec = TIMEOUT; + tv.tv_usec = 0; + ret = edg_wll_gss_write_full(&eq->gss, msg->msg, msg->len, &tv, &bytes_sent, &gss_stat); + if(ret < 0) { + if (ret == EDG_WLL_GSS_ERROR_ERRNO && errno == EPIPE && events_sent > 0) { + eq->timeout = 0; + } else { + il_log(LOG_ERR, "send_event: %s\n", error_get_msg()); + eq->timeout = TIMEOUT; + } + return(0); + } + if((code = get_reply(eq, &rep, &code_min)) < 0) { + /* could not get the reply properly, so try again later */ + if (events_sent>0) + eq->timeout = 1; + else { + eq->timeout = TIMEOUT; + il_log(LOG_ERR, " error reading server %s reply:\n %s\n", eq->dest_name, error_get_msg()); + } + return(0); + } + } + else { code = 200; code_min = 0; rep = strdup("not sending empty message"); } +#ifdef LB_PERF + } else { + glite_wll_perftest_consumeEventIlMsg(msg->msg+17); + code = 200; + rep = strdup("OK"); + } +#endif + + il_log(LOG_DEBUG, " event sent, server %s replied with %d, %s\n", eq->dest_name, code, rep); + free(rep); + + /* the reply is back here, decide what to do with message */ + /* HTTP error codes: + 1xx - informational (eg. 100 Continue) + 2xx - successful (eg. 200 OK) + 3xx - redirection (eg. 301 Moved Permanently) + 4xx - client error (eq. 400 Bad Request) + 5xx - server error (eq. 500 Internal Server Error) + */ + if(code >= 100 && code < 200) { + + /* non fatal errors (for us), try to deliver later */ + eq->timeout = TIMEOUT; + return(0); + } + + /* the message was consumed (successfully or not) */ + /* update the event pointer */ + if(event_store_commit(msg->es, msg->ev_len, queue_list_is_log(eq)) < 0) + /* failure committing message, this is bad */ + return(-1); + + event_queue_remove(eq); + events_sent++; + } /* while */ + + return(1); + +} /* send_events */ + + +/* this is just not used */ +int +send_confirmation(long lllid, int code) +{ + return 0; +} diff --git a/org.glite.lb.logger/src/server_msg.c b/org.glite.lb.logger/src/server_msg.c index e9578a1..aa57e1a 100644 --- a/org.glite.lb.logger/src/server_msg.c +++ b/org.glite.lb.logger/src/server_msg.c @@ -1,13 +1,30 @@ #ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include #include +#include #include "interlogd.h" #include "glite/lb/il_msg.h" #include "glite/lb/events_parse.h" -#include "glite/lb/consumer.h" #include "glite/lb/context.h" static @@ -17,7 +34,7 @@ create_msg(il_octet_string_t *ev, char **buffer, long *receipt, time_t *expires) char *p; int len; char *event = ev->data; - *receipt = 0; + *receipt = 0L; #if defined(INTERLOGD_EMS) /* find DG.LLLID */ @@ -42,24 +59,23 @@ create_msg(il_octet_string_t *ev, char **buffer, long *receipt, time_t *expires) int n; p += 12; /* skip the key and = */ - if((n = atoi(p)) == 0) { + n = atoi(p); + if((n & (EDG_WLL_LOGFLAG_SYNC|EDG_WLL_LOGFLAG_SYNC_COMPAT)) == 0) { /* normal asynchronous message */ - *receipt = 0; + *receipt = 0L; } } else { /* could not find priority key */ - *receipt = 0; + *receipt = 0L; } } else { /* could not find local logger PID, confirmation can not be sent */ - *receipt = 0; + *receipt = 0L; } #endif - if(p = strstr(event, "DG.EXPIRES")) { - int n; - + if((p = strstr(event, "DG.EXPIRES")) != NULL) { p += 11; *expires = atoi(p); } @@ -119,11 +135,12 @@ server_msg_copy(struct server_msg *src) msg->receipt_to = src->receipt_to; msg->offset = src->offset; #if defined(IL_NOTIFICATIONS) - msg->dest_name = strdup(src->dest_name); + msg->dest_name = src->dest_name ? strdup(src->dest_name) : NULL; msg->dest_port = src->dest_port; - msg->dest = strdup(src->dest); + msg->dest = src->dest ? strdup(src->dest) : NULL; #endif msg->expires = src->expires; + msg->generation = src->generation; return(msg); } @@ -144,16 +161,26 @@ server_msg_init(struct server_msg *msg, il_octet_string_t *event) #if defined(IL_NOTIFICATIONS) - edg_wll_InitContext(&context); /* parse the notification event */ - if((ret=edg_wll_ParseNotifEvent(context, event->data, ¬if_event))) { + edg_wll_InitContext(&context); + ret=edg_wll_ParseNotifEvent(context, event->data, ¬if_event); + edg_wll_FreeContext(context); + if(ret) { set_error(IL_LBAPI, ret, "server_msg_init: error parsing notification event"); return(-1); } + /* FIXME: check for allocation error */ - if(notif_event->notification.dest_host && + if(notif_event->notification.dest_url && + (strlen(notif_event->notification.dest_url) > 0)) { + /* destination URL */ + msg->dest = strdup(notif_event->notification.dest_url); + msg->dest_name = NULL; + msg->dest_port = 0; + } else if(notif_event->notification.dest_host && (strlen(notif_event->notification.dest_host) > 0)) { + /* destination host and port */ msg->dest_name = strdup(notif_event->notification.dest_host); msg->dest_port = notif_event->notification.dest_port; asprintf(&msg->dest, "%s:%d", msg->dest_name, msg->dest_port); diff --git a/org.glite.lb.logger/src/server_msg_http.c b/org.glite.lb.logger/src/server_msg_http.c new file mode 100644 index 0000000..3a0209a --- /dev/null +++ b/org.glite.lb.logger/src/server_msg_http.c @@ -0,0 +1,145 @@ +#ident "$Header$" +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#include +#include +#include + +#include "interlogd.h" +#include "glite/lb/il_msg.h" +#include "glite/lb/events_parse.h" +#include "glite/lb/context.h" + +static +int +create_msg(il_http_message_t *ev, char **buffer, long *receipt, time_t *expires) +{ + char *event = ev->data; + + *receipt = 0; + *expires = 0; + + *buffer = ev->data; + return ev->len;; +} + + +struct server_msg * +server_msg_create(il_octet_string_t *event, long offset) +{ + struct server_msg *msg; + + msg = malloc(sizeof(*msg)); + if(msg == NULL) { + set_error(IL_NOMEM, ENOMEM, "server_msg_create: out of memory allocating message"); + return(NULL); + } + + if(server_msg_init(msg, event) < 0) { + server_msg_free(msg); + return(NULL); + } + msg->offset = offset; + + return(msg); +} + + +struct server_msg * +server_msg_copy(struct server_msg *src) +{ + struct server_msg *msg; + + msg = malloc(sizeof(*msg)); + if(msg == NULL) { + set_error(IL_NOMEM, ENOMEM, "server_msg_copy: out of memory allocating message"); + return(NULL); + } + + msg->msg = malloc(src->len); + if(msg->msg == NULL) { + set_error(IL_NOMEM, ENOMEM, "server_msg_copy: out of memory allocating server message"); + server_msg_free(msg); + return(NULL); + } + msg->len = src->len; + memcpy(msg->msg, src->msg, src->len); + + msg->job_id_s = strdup(src->job_id_s); + msg->ev_len = src->ev_len; + msg->es = src->es; + msg->receipt_to = src->receipt_to; + msg->offset = src->offset; +#if defined(IL_NOTIFICATIONS) + msg->dest_name = strdup(src->dest_name); + msg->dest_port = src->dest_port; + msg->dest = strdup(src->dest); +#endif + msg->expires = src->expires; + return(msg); +} + + +int +server_msg_init(struct server_msg *msg, il_octet_string_t *event) +{ + il_http_message_t *hmsg = (il_http_message_t *)event; + + assert(msg != NULL); + assert(event != NULL); + + memset(msg, 0, sizeof(*msg)); + + + msg->job_id_s = hmsg->host; + if(msg->job_id_s == NULL) { + set_error(IL_LBAPI, EDG_WLL_ERROR_PARSE_BROKEN_ULM, "server_msg_init: error getting id"); + return -1; + } + msg->len = create_msg(hmsg, &msg->msg, &msg->receipt_to, &msg->expires); + if(msg->len < 0) + return -1; + /* set this to indicate new data owner */ + hmsg->data = NULL; + hmsg->host = NULL; + msg->ev_len = hmsg->len + 1; /* must add separator size too */ + return 0; + +} + + +int +server_msg_is_priority(struct server_msg *msg) +{ + assert(msg != NULL); + + return(msg->receipt_to != 0); +} + + +int +server_msg_free(struct server_msg *msg) +{ + assert(msg != NULL); + + if(msg->msg) free(msg->msg); + if(msg->job_id_s) free(msg->job_id_s); + free(msg); + return 0; +} diff --git a/org.glite.lb.logger/test/IlTestBase.cpp b/org.glite.lb.logger/test/IlTestBase.cpp index a6b4624..4ef7301 100644 --- a/org.glite.lb.logger/test/IlTestBase.cpp +++ b/org.glite.lb.logger/test/IlTestBase.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include "IlTestBase.h" #include diff --git a/org.glite.lb.logger/test/IlTestBase.h b/org.glite.lb.logger/test/IlTestBase.h index 69bf347..449dbee 100644 --- a/org.glite.lb.logger/test/IlTestBase.h +++ b/org.glite.lb.logger/test/IlTestBase.h @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + extern "C" { #include "interlogd.h" } diff --git a/org.glite.lb.logger/test/event_queueTest.cpp b/org.glite.lb.logger/test/event_queueTest.cpp index 86a6be1..e07c19f 100644 --- a/org.glite.lb.logger/test/event_queueTest.cpp +++ b/org.glite.lb.logger/test/event_queueTest.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include "IlTestBase.h" diff --git a/org.glite.lb.logger/test/event_storeTest.cpp b/org.glite.lb.logger/test/event_storeTest.cpp index 8364cf4..982c7ff 100644 --- a/org.glite.lb.logger/test/event_storeTest.cpp +++ b/org.glite.lb.logger/test/event_storeTest.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include "IlTestBase.h" diff --git a/org.glite.lb.logger/test/il_test.cpp b/org.glite.lb.logger/test/il_test.cpp index cd97a73..3d1d554 100644 --- a/org.glite.lb.logger/test/il_test.cpp +++ b/org.glite.lb.logger/test/il_test.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include diff --git a/org.glite.lb.logger/test/input_queue_socketTest.cpp b/org.glite.lb.logger/test/input_queue_socketTest.cpp index d29e2cc..dd53f52 100644 --- a/org.glite.lb.logger/test/input_queue_socketTest.cpp +++ b/org.glite.lb.logger/test/input_queue_socketTest.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include "IlTestBase.h" diff --git a/org.glite.lb.logger/test/ll_test.cpp b/org.glite.lb.logger/test/ll_test.cpp index 1e8dce6..1ac340a 100644 --- a/org.glite.lb.logger/test/ll_test.cpp +++ b/org.glite.lb.logger/test/ll_test.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include diff --git a/org.glite.lb.logger/test/logd_proto_test.c b/org.glite.lb.logger/test/logd_proto_test.c index 9ee0b44..fcd78cf 100644 --- a/org.glite.lb.logger/test/logd_proto_test.c +++ b/org.glite.lb.logger/test/logd_proto_test.c @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include #include diff --git a/org.glite.lb.logger/test/server_msgTest.cpp b/org.glite.lb.logger/test/server_msgTest.cpp index e669ea1..2bdc50d 100644 --- a/org.glite.lb.logger/test/server_msgTest.cpp +++ b/org.glite.lb.logger/test/server_msgTest.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) Members of the EGEE Collaboration. 2004-2010. +See http://www.eu-egee.org/partners for details on the copyright holders. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + #include #include "IlTestBase.h" -- 1.8.2.3