Sprout from branch_RC31_3 2010-08-19 14:30:10 UTC Zdeněk Šustr <sustr4@cesnet.cz> 'New age for the subsys'
Cherrypick from master 2010-06-25 09:08:51 UTC Michal Voců <michal@ruk.cuni.cz> '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 <sustr4@cesnet.cz> '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
--- /dev/null
+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
--- /dev/null
+#!/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 ($_ = <V>) {
+ 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 ("", <V>);
+ 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 ("", <V>);
+ 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 ($_ = <S>) {
+ 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= <INP>;
+ chomp($kname);
+ close INP;
+
+ if ( $kname == "Linux") {
+ $arch = ("x86_64\npowerpc\nppc64\n");
+
+ open INP, "uname -p | "; # Check processor type
+ $procname= <INP>;
+ chomp($procname);
+ close INP;
+
+ if ($arch =~/^$procname\n/) {
+ return ($lib64); }
+
+ open INP, "uname -m | "; # Check machine hardware
+ $machname= <INP>;
+ 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
+
+};
+
+}
--- /dev/null
+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'.
--- /dev/null
+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
--- /dev/null
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry id='glitelbharvester'>
+
+ <refmeta>
+ <refentrytitle>glite-lb-harvester</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo>EU EGEE Project</refmiscinfo>
+ </refmeta>
+
+ <refnamediv id='name'>
+ <refname>glite-lb-harvester</refname>
+ <refpurpose>daemon for processing L&B notifications</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv id='synopsis'>
+ <cmdsynopsis>
+ <command>glite-lb-harvester</command>
+
+ <arg><group choice='plain'>
+ <arg>-h</arg>
+ <arg>--help</arg>
+ </group></arg>
+
+ <arg><group choice='plain'>
+ <arg>-v</arg>
+ <arg>--version</arg>
+ </group></arg>
+
+ <arg><group choice='plain'>
+ <arg>-d</arg>
+ <arg>--debug</arg>
+ </group> <replaceable>LEVEL</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>-D</arg>
+ <arg>--daemon</arg>
+ </group></arg>
+
+ <arg><group choice='plain'>
+ <arg>-i</arg>
+ <arg>--pidfile</arg>
+ </group> <replaceable>PIDFILE</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>-s</arg>
+ <arg>--threads</arg>
+ </group> <replaceable>N</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>-t</arg>
+ <arg>--ttl</arg>
+ </group> <replaceable>TIME</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>-H</arg>
+ <arg>--history</arg>
+ </group> <replaceable>TIME</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>-c</arg>
+ <arg>--config</arg>
+ </group></arg>
+
+ <arg><group choice='plain'>
+ <arg>-m</arg>
+ <arg>--pg</arg>
+ </group> <replaceable>USER/PWD@SERVER:DBNAME</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>-n</arg>
+ <arg>--notifs</arg>
+ </group> <replaceable>FILE</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>-p</arg>
+ <arg>--port</arg>
+ </group> <replaceable>PORT</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>-C</arg>
+ <arg>--cert</arg>
+ </group> <replaceable>FILE</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>-K</arg>
+ <arg>--key</arg>
+ </group> <replaceable>FILE</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>-o</arg>
+ <arg>--old</arg>
+ </group></arg>
+
+ <arg><group choice='plain'>
+ <arg>-l</arg>
+ <arg>--cleanup</arg>
+ </group></arg>
+
+ <arg><group choice='plain'>
+ <arg>-u</arg>
+ <arg>--no-purge</arg>
+ </group></arg>
+
+ <arg><group choice='plain'>
+ <arg>-w</arg>
+ <arg>--wlcg</arg>
+ </group></arg>
+
+ <arg><group choice='plain'>
+ <arg>--wlcg-binary</arg>
+ </group> <replaceable>EXECUTABLE</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>--wlcg-topic</arg>
+ </group> <replaceable>TOPIC</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>--wlcg-config</arg>
+ </group> <replaceable>FILENAME</replaceable></arg>
+
+ <arg><group choice='plain'>
+ <arg>--wlcg-flush</arg>
+ </group></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+ <para>
+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.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Requirements</title>
+ <para>
+It is required on L&B servers side:
+ <itemizedlist>
+ <listitem><para>
+<filename>lastUpdateTime</filename> index, see "Changing Index Configuration" section in L&B Admin Guide
+ </para></listitem>
+ <listitem><para>
+L&B harvester identity (certification subject) in super users file
+ </para></listitem>
+ </itemizedlist>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><option>-h</option>|<option>--help</option></term>
+ <listitem><para>
+Print short usage.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <variablelist>
+ <varlistentry>
+ <term><option>-v</option>|<option>--version</option></term>
+ <listitem><para>
+Print harvester version identifier.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-d</option>|<option>--debug</option></term>
+ <listitem><para>
+ Verbosity level:
+ <variablelist>
+ <varlistentry><term>0</term><listitem><para>error only</para></listitem></varlistentry>
+ <varlistentry><term>1</term><listitem><para>warnings</para></listitem></varlistentry>
+ <varlistentry><term>2</term><listitem><para>info/progress</para></listitem></varlistentry>
+ <varlistentry><term>3</term><listitem><para>debug</para></listitem></varlistentry>
+ <varlistentry><term>4</term><listitem><para>insane</para></listitem></varlistentry>
+ <varlistentry><term>+8 (8,9,10,11,12)</term><listitem><para>don't fork and no preventive restarts</para></listitem></varlistentry>
+ </variablelist>
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-D</option>|<option>--daemonize</option></term>
+ <listitem><para>
+Daemonize and detach from console. Error messages are directed to syslog.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-i</option>|<option>--pidfile</option></term>
+ <listitem><para>
+The file with process ID. Automatically removed on shutdown.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-s</option>|<option>--threads</option></term>
+ <listitem><para>
+Number of threads (slaves). Configured L&B servers are equally distributed between threads.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-t</option>|<option>--ttl</option></term>
+ <listitem><para>
+Validity (time to live) of the notifications. Daemon regularly refreshes notification in advance as needed.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-H</option>|<option>--history</option></term>
+ <listitem><para>
+Historic dive limit in seconds. <= means unlimited.
+ </para><para>
+ 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.
+ </para><para>
+ 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.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-c</option>|<option>--config</option></term>
+ <listitem><para>
+ Config file name with list of L&B servers. When used together with database option <option>-m</option> (<option>--pg</option>), this parameter has precedence before <filename>lb20</filename> table.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-m</option>|<option>--pg</option></term>
+ <listitem><para>
+Database connection string in the <filename>USER/PWD@SERVER:DBNAME</filename> form. There are used following tables in database:
+ <itemizedlist>
+ <listitem><para>
+ <filename>lb20</filename> - the list of L&B servers is taken from this table. But when is specified option <option>-c</option> (<option>--config</option>) too, the file has precedence before this table.
+ </para><para>
+There is kept a column <filename>monitored</filename> 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 <filename>false</filename> value is set. After refreshing or creating the notification, the value is set back to <filename>true</filename>.
+ </para></listitem>
+ <listitem><para>
+ <filename>jobs</filename> - table for storing job states. Each record is updated for each incoming notification - when state of the job changes in L&B server.
+ </para></listitem>
+ </itemizedlist></para><para>
+Database schema can be found in source code of <filename>org.glite.lb.harvester</filename>: <filename>examples/test.sql</filename>
+ </para><para>
+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 <filename>examples</filename> source directory.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-n</option>|<option>--notifs</option></term>
+ <listitem><para>
+File for internal usage in L&B harvester. There is kept persistent information about active notifications or errors on L&B servers. Default is <filename>/var/tmp/notifs.txt</filename>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-p</option>|<option>--port</option></term>
+ <listitem><para>
+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.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-C</option>|<option>--cert</option></term>
+ <listitem><para>
+X509 certificate file.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-K</option>|<option>--key</option></term>
+ <listitem><para>
+X509 key file.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-o</option>|<option>--old</option></term>
+ <listitem><para>
+"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.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-l</option>|<option>--cleanup</option></term>
+ <listitem><para>
+Cleans up all active notifications and quits.
+ </para><para>
+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).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-u</option>|<option>--no-purge</option></term>
+ <listitem><para>
+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'.
+ </para><para>
+For using together with <option>-m</option> (<option>--pg</option>).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-w</option>|<option>--wlcg</option></term>
+ <listitem><para>
+Enables delivery to MSG publish. Messages are sent by executing a binary with proper parameters.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--wlcg-binary</option></term>
+ <listitem><para>
+Full path to msg-publish binary executable, which is called for sending messages. Default is <filename>/usr/bin/msg-publish</filename>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--wlcg-topic</option></term>
+ <listitem><para>
+Topic used in MSG publish messages. Default is <filename>org.wlcg.usage.jobStatus</filename>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--wlcg-config</option></term>
+ <listitem><para>
+Config file used in MSG publish. Default is <filename>/etc/msg-publish/msg-publish.conf</filename>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--wlcg-flush</option></term>
+ <listitem><para>
+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.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>GLITE_LB_HARVESTER_NO_REMOVE</term>
+ <listitem><para>
+<filename>0</filename> or <filename>false</filename> 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.
+ </para><para>
+Intended for debugging purposes.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>EXAMPLES</title>
+
+ <refsect2>
+ <title>MSG publish infrastructure</title>
+ <para>
+Harvester will send notifications using msg-publish infrastructure. List of the L&B servers to harvest is specified in config file specified by <option>-c</option> option:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><command>glite-lb-harvester -c servers.txt -C certfile -K keyfile --wlcg</command></term>
+ <listitem><para>
+With newer L&B servers >= 2.0.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><command>glite-lb-harvester -c servers.txt -C certfile -K keyfile --wlcg --old</command></term>
+ <listitem><para>
+With older L&B servers < 2.0 (backward compatible but greedy notifications).
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+Custom configuration examples for MSG publish:
+ <itemizedlist>
+ <listitem><para>
+<option>--wlcg-binary</option> <filename>$HOME/bin/msg-publish</filename>
+ </para></listitem><listitem><para>
+<option>--wlcg-topic</option> <filename>org.wlcg.usage.JobStatus2</filename>
+ </para></listitem><listitem><para>
+<option>--wlcg-config</option> <filename>$HOME/etc/msg-publish.conf.wlcg</filename>
+ </para></listitem>
+ </itemizedlist>
+ </para>
+ </refsect2>
+
+ <refsect2>
+ <title>Real Time Monitor</title>
+ <para>
+Harvester will use postgres database. Table <filename>lb20</filename> with L&B servers to harvest (read-only), table <filename>jobs</filename> for result job states (read/write):
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><command>glite-lb-harvester -C certfile -K keyfile --pg rtm/@:rtm -p 9004</command></term>
+ <listitem><para>
+In this case the L&B harvester will connect to database <filename>rtm</filename> on <filename>localhost</filename> as user <filename>rtm</filename>. For incoming notification it will request and listen only on port 9004.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>Other recommended options</title>
+ <para>
+Use <command>glite-lb-harvester --help</command> for the whole summary.
+ </para><para>
+For example:
+ <variablelist>
+ <varlistentry>
+ <term><option>--daemonize --pidfile /var/run/glite-lb-harvester.pid</option></term>
+ <listitem><para>
+Daemonizing and using syslog.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-d 2</option></term>
+ <listitem><para>
+Decreasing verbosity (2 for errors and warnings only).
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </refsect2>
+ </refsect1>
+
+ <refsect1>
+ <title>EXIT</title>
+ <para>
+In non-daemon mode CTRL-C can be used.
+ </para><para>
+Use the pidfile in daemon mode (pidfile will vanish after exit):
+ </para><para>
+<command>kill `cat /var/run/glite-lb-harvester.pid`</command>
+ </para><para>
+All notifications are preserved on LB servers, and will expire later. You can
+purge them at once, if they won't be needed:
+ </para><para>
+<command>glite-lb-harvester --cleanup</command>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>EXIT STATUS</title>
+ <variablelist>
+ <varlistentry>
+ <term>0</term>
+ <listitem><para>Success.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>1</term>
+ <listitem><para>Reloading, used only internally for preventive restarts.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>2</term>
+ <listitem><para>Error occurred. Messages go on console (foreground run) or into syslog (daemon run), depending on verbosity.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>AUTHOR</title>
+ <para>gLite L&B product team, CESNET.</para>
+ </refsect1>
+
+</refentry>
--- /dev/null
+#! /bin/sh
+
+
+usage() {
+cat <<EOF
+
+ ./test.sh
+
+ Testing of the L&B harvester using local daemons and databases.
+
+ Requirements:
+ - working L&B software (ideally with passed org.glite.testsuites.ctb/LB/test)
+ - mysql and postgresql databases, with sufficient access
+ pg_hba.conf content for example:
+ local all all trust all
+ - created user \$RTM_NAME (rtm by default) in postgres DB
+ - proxy certificate
+ - writable working directory with harvester built with -DRTM_SQL_STORAGE_ENABLED=1
+ (or via 'make test')
+
+ non-default configuration is possible via following env variables or
+ using ~/.glite.conf:
+ GLITE_LOCATION..................path to glite SW
+ GLOBUS_LOCATION.................path to globus SW
+ GLITE_HOST_CERT.................path to host certificate
+ GLITE_HOST_KEY..................path to host key
+ GLITE_LB_TEST_DB................L&B connection string
+ (default lbserver/@localhost:lbserver20test,
+ autocreating the database when empty)
+ GLITE_RTM_TEST_DB...............L&B connection string, existing user with
+ privileges required
+ (default rtm/@localhost:rtmtest,
+ autocreating the database when empty)
+ GLITE_MYSQL_ROOT_USER...........mysql root user (default: root)
+ GLITE_MYSQL_ROOT_PASSWORD.......mysql root password (default: none)
+ GLITE_PG_ROOT_USER..............postgres root user (default: postgres)
+ GLITE_LB_TEST_SERVER_PORT.......(default 10000)
+ GLITE_LB_TEST_PIDFILE...........(default /tmp/glite-lb-test.pid)
+ GLITE_RTM_TEST_PIDFILE..........(default /tmp/glite-rtm-test.pid)
+ GLITE_RTM_TEST_TTL..............notif validity (default 60 seconds)
+ GLITE_RTM_TEST_ADDITIONAL_ARGS..additional arguments for harvester
+
+EOF
+}
+
+
+init() {
+ # get the configuration
+ GLITE_LOCATION=${GLITE_LOCATION:-"/opt/glite"}
+ [ -f /etc/glite.conf ] && . /etc/glite.conf
+ [ -f $HOME/.glite.conf ] && . $HOME/.glite.conf
+
+ GLOBUS_LOCATION=${GLOBUS_LOCATION:-"/opt/globus"}
+
+ if [ -n "$GLITE_HOST_CERT" -a -n "$GLITE_HOST_KEY" ] ;then
+ X509_USER_CERT="$GLITE_HOST_CERT"
+ X509_USER_KEY="$GLITE_HOST_KEY"
+ fi
+
+# if [ -z "$X509_USER_CERT" -o -z "$X509_USER_KEY" ] ; then
+ if [ -e "$GLOBUS_LOCATION/bin/grid-proxy-info" ] ; then
+ timeleft=`$GLOBUS_LOCATION/bin/grid-proxy-info 2>&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
--- /dev/null
+--
+-- 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)
+);
--- /dev/null
+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
+
--- /dev/null
+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.
--- /dev/null
+Enhanced L&B notification client.
--- /dev/null
+module.version=1.0.4
+module.age=1
--- /dev/null
+#ident "$Header$"
+
+/*
+ * Real time monitor.
+ */
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <glite/security/glite_gss.h>
+#ifdef WITH_LBU_DB
+#include <glite/lbu/trio.h>
+#include <glite/lbu/db.h>
+#endif
+#include <glite/lb/context.h>
+#ifndef WITH_OLD_LB
+#include <glite/lb/connpool.h>
+#endif
+#include <glite/lb/notification.h>
+#include <glite/lb/consumer.h>
+
+
+// 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;
+}
# 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
SUFFIXES=.no
-GLOBUSINC=-I${globus_prefix}/include/${nothrflavour}
-
-GLOBUSTHRINC=-I${globus_prefix}/include/${thrflavour}
-
ifdef LB_STANDALONE
LB_STANDALONE_FLAGS:=-DLB_STANDALONE
endif
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
#
#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
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}
input_queue_socket.o \
input_queue_socketTest.o \
send_event.o \
+ plugin_mgr. o \
event_queue.o \
event_queueTest.o \
IlTestBase.o \
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:
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/
#!/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}
[ -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
[ -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()
--- /dev/null
+#!/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 ($_ = <V>) {
+ 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 ("", <V>);
+ 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 ("", <V>);
+ 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 ($_ = <S>) {
+ 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= <INP>;
+ chomp($kname);
+ close INP;
+
+ if ( $kname == "Linux") {
+ $arch = ("x86_64\npowerpc\nppc64\n");
+
+ open INP, "uname -p | "; # Check processor type
+ $procname= <INP>;
+ chomp($procname);
+ close INP;
+
+ if ($arch =~/^$procname\n/) {
+ return ($lib64); }
+
+ open INP, "uname -m | "; # Check machine hardware
+ $machname= <INP>;
+ 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
+
+};
+
+}
-.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
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.
.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
.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.
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.
-.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
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.
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.
.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.
--- /dev/null
+#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 <syslog.h>
+
+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
#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 <pthread.h>
#include <sys/time.h>
#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
#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
// #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;
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
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 */
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 */
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;
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 */
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);
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 *);
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 *);
/* 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 *);
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
- 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
--- /dev/null
+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.
--- /dev/null
+gLite Logging and Bookkeeping local-logger and inter-logger
# $Header$
-module.version=1.4.11
-module.age=4
+module.version=2.1.4
+module.age=1
+/*
+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
public:
virtual Connection *newConnection(int fd) const = 0;
virtual Connection *accept(int fd) const = 0;
+
+ virtual ~Factory() {}
};
class Endpoint {
--- /dev/null
+/*
+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() {
+}
-#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 T>
- class EventHandler {
- public:
+#include <list>
- virtual eventstatus_t handleEvent(T *&e);
- eventstatus_t dispatchEvent(Event *&e) {
- T *event = dynamic_cast<T*>(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<class T>
- bool registerHandler(EventHandler<T> *);
+/**
+ * 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<class T>
- bool registerHandlerFirst(EventHandler<T> *);
+/**
+ * Holds addres of event handler, ie. pointer to member function of T
+ * that takes E* & as an argument.
+ */
+template<class T, class E>
+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*>(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<class T, class E>
+ EventHandler& registerHandler(T *handler, int (T::*method)(E* &)) {
+ EventHandler *h = new TypedEventHandler<T,E>(handler, method);
+ addHandler(h);
+ return *h;
+ }
+
+ template<class T>
+ EventHandler& registerHandler(T *handler) {
+ return registerHandler(handler, &T::handleEvent);
+ }
+
+private:
+ std::list<EventHandler*> handlers;
+ void addHandler(EventHandler*);
+ void removeHandler(EventHandler *);
};
--- /dev/null
+/*
+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<EventHandler*>::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)
+{
+}
+/*
+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
+/*
+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 <string>
public Transport
{
public:
- class Factory: public Transport::Factory {
+
+ // factory class
+ class Factory: public Transport::Factory,
+ public Singleton<HTTPTransport::Factory> {
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)
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,
unsigned int content_length;
int parseHeader(const char *s, unsigned int len);
+ void serializeHeaders(Message *msg);
};
+/*
+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 <iostream>
#include <string.h>
-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;
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;
}
} else {
// report error
+ // XXX - this may happen, do not handle using exceptions
std::cout << "Wrong content length" << std::endl;
throw new Exception();
}
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;
}
}
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->
}
--- /dev/null
+/*
+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
--- /dev/null
+/*
+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()
+{
+}
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 \
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
--- /dev/null
+/*
+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 <string>
+
+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
--- /dev/null
+/*
+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 <pthread.h>
+
+/** 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
--- /dev/null
+/*
+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 <pthread.h>
+#include <sys/time.h>
+#include <sstream>
+
+#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();
+}
+
+/*
+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<PlainConnection::Factory> {
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)
{}
+/*
+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 <sys/types.h>
#include <sys/socket.h>
-PlainConnection::Factory PlainConnection::theFactory;
-
-
PlainConnection::~PlainConnection()
{
}
int
PlainConnection::write(char *buf, unsigned int len)
{
+ int ret;
+
+ ret = ::write(fd, buf, len);
+ return ret;
}
+/*
+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
virtual bool initialize() = 0;
virtual bool cleanup () = 0;
+
+ virtual ~Plugin();
};
// add plugin with given name to the list of registered plugins
+/*
+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() {
+}
+
--- /dev/null
+/*
+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 <map>
+#include <string>
+
+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<std::string,std::string>::iterator iterator;
+
+ iterator begin()
+ { return properties.begin(); }
+
+ iterator end()
+ { return properties.end(); }
+
+
+private:
+ std::map<std::string,std::string> properties;
+};
+
+#endif
+/*
+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
+/*
+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
+/*
+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 <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "ThreadPool.H"
#include "SocketInput.H"
-
+#include "InputChannel.H"
+#include "Exception.H"
// create unix domain socket for input
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);
// 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;
}
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();
}
+/*
+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
: fd(afd), event(NONE) {}
+ virtual ~WorkDescription();
+
protected:
enum Event { NONE, READY, TIMEOUT, ERROR } event;
void doWork();
+/*
+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 <time.h>
#include <pthread.h>
#include <poll.h>
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
+#include <errno.h>
#include <iostream>
}
+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);
pthread_cond_init(&wait_queue_cond_ready, NULL);
pipe(pd);
ufds = static_cast<struct pollfd *>(malloc(sizeof(struct pollfd)));
+ if(ufds == NULL) {
+ throw new Exception;
+ }
ufds->fd = pd[0];
ufds->events = POLLIN;
ufds_size = 1;
num_workers = n;
for(unsigned int i = 0; i < n; i++) {
+ // XXX check return
pthread_create(&workers[i], NULL, ThreadPool::threadMain, NULL);
}
}
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);
}
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;
+ }
}
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;
}
{
ThreadPool *pool = ThreadPool::instance();
- pthread_mutex_unlock(&(pool->work_queue_mutex));
+ E_ASSERT(pthread_mutex_unlock(&(pool->work_queue_mutex)) >= 0);
}
std::list<WaitDesc *>::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);
}
std::list<WaitDesc *>::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<struct pollfd *>(realloc(ufds, (1 + wait_count) * sizeof(struct pollfd)));
if(ufds == NULL) {
-// throw new Exception();
+ throw new Exception();
}
ufds_size = wait_count + 1;
}
min_timeout = w->timeout;
}
}
- pthread_mutex_unlock(&wait_queue_mutex);
+ E_ASSERT(pthread_mutex_unlock(&wait_queue_mutex) >= 0);
}
}
// 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
// check for consistency
if(p->fd != w->get_fd()) {
// mismatch, what shall we do?
- abort();
+ throw new Exception;
}
// subtract the time passed from timeout
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;
}
}
}
+/*
+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
--- /dev/null
+/*
+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()
+{
+}
+/*
+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;
// 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);
+/*
+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 <cppunit/extensions/HelperMacros.h>
#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 );
+/*
+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 <cppunit/extensions/HelperMacros.h>
#include "PluginManager.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
+
+ 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 <cppunit/extensions/HelperMacros.h>
#include "Singleton.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
+
+ 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 <cppunit/extensions/HelperMacros.h>
#include <unistd.h>
#include <sys/socket.h>
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();
+/*
+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 <assert.h>
#include <fstream>
--- /dev/null
+#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 <activemq/library/ActiveMQCPP.h>
+#include <cms/ConnectionFactory.h>
+#include <cms/Connection.h>
+#include <cms/Session.h>
+#include <cms/Topic.h>
+#include <cms/MessageProducer.h>
+#include <cms/ExceptionListener.h>
+#include <cms/TextMessage.h>
+#include <cms/Message.h>
+
+#include <string>
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/param.h>
+
+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:";
#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)
*/
#include <stdio.h>
#include <stdlib.h>
-#include "glite/wmsutils/jobid/cjobid.h"
+#include "glite/jobid/cjobid.h"
#include "interlogd.h"
};
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");
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");
#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);
#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);
eq->tail = el;
}
eq->tail_ems = el;
- } else
+ } else
#endif
- {
+ {
/* normal messages */
if(eq->tail)
eq->tail->prev = el;
#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
assert(eq != NULL);
assert(msg != NULL);
-
+
event_queue_lock(eq);
el = eq->head;
#if defined(INTERLOGD_EMS)
}
-int
+int
event_queue_remove(struct event_queue *eq)
{
struct event_queue_msg *el;
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);
}
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) {
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);
}
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);
#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 <assert.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
+#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
-#ifdef HAVE_UNISTD_H
#include <unistd.h>
-#endif
#include <fcntl.h>
+#include <sys/param.h>
-#include "glite/lb/consumer.h"
#include "glite/lb/events_parse.h"
#include "interlogd.h"
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 */
};
*/
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;
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);
}
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 *
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) {
*p++ = 0;
break;
} else
- *p++ = (char) c;
+ *p++ = (char) c;
}
if(c != EVENT_SEPARATOR) {
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);
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;
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");
}
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);
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);
{
assert(es != NULL);
- if(pthread_rwlock_unlock(&es->update_lock))
+ if(pthread_rwlock_unlock(&es->commit_lock))
abort();
return(0);
}
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");
/*
- * 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;
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 */
}
/* 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);
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
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);
}
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);
}
/* 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 */
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
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;
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
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;
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);
}
* 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
}
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)
* 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)
{
/* 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+");
/* 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");
}
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);
* --------------------------------
*/
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)) {
}
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);
}
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);
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);
}
#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);
}
}
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;
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;
(es->last_committed_bs == 0) &&
(es->offset == 0)) {
ret = event_store_read_ctl(es);
- } else
+ } else
ret = 0;
-
+
event_store_release(es);
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);
}
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 */
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 */
} 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);
struct event_store_list *sl;
- if(pthread_rwlock_rdlock(&store_list_lock))
+ if(pthread_rwlock_rdlock(&store_list_lock))
abort();
/* recover all event stores */
/* 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)
{
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");
/* try to remove event files */
- if(pthread_rwlock_wrlock(&store_list_lock))
+ if(pthread_rwlock_wrlock(&store_list_lock))
abort();
sl = store_list;
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;
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);
}
--- /dev/null
+#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 <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <sys/param.h>
+
+#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);
+}
+
--- /dev/null
+#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 <string.h>
+#include <errno.h>
+
+#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;
+}
#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 <errno.h>
#include <stdio.h>
extern void _start (void), etext (void);
#endif
-/* XXX DK: */
-#include <err.h> // 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;
void
error_key_delete(void *err)
{
+ if(((struct error_inf*)err)->msg)
+ free(((struct error_inf*)err)->msg);
free(err);
}
int
-init_errors(int level)
+init_errors()
{
static pthread_once_t error_once = PTHREAD_ONCE_INIT;
struct error_inf *err;
if(err->msg == NULL)
return(-1);
- if(level)
- log_level = level;
-
#ifdef LB_PROF
monstartup((u_long)&_start, (u_long)&etext);
#endif
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) {
+++ /dev/null
-#ifndef IL_ERROR_H
-#define IL_ERROR_H
-
-#ident "$Header$"
-
-#include <syslog.h>
-
-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
#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 <errno.h>
#include <string.h>
#include <unistd.h>
+#include <stdio.h>
-#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"
#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
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;
}
#endif /* INTERLOGD_FLUSH */
#ifdef INTERLOGD_HANDLE_CMD
-static
+static
int
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)
#endif
} else if(strncmp(token, "DG.JOBID", r - token) == 0) {
char *p;
-
+
r += 2; /* skip =" */
p = index(r, '"');
if(p == NULL) { ret = -1; continue; }
} else if(strncmp(token, "DG.LLLID", r - token) == 0) {
sscanf(++r, "%ld", receipt);
}
-
+
}
return(0);
}
* -1 - failure
*/
-static
-int
+static
+int
handle_cmd(il_octet_string_t *event, long offset)
{
char *job_id_s;
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;
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) {
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 */
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);
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);
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);
}
/* prevent deadlock in next flush */
- if(pthread_mutex_unlock(&flush_lock) < 0)
+ if(pthread_mutex_unlock(&flush_lock) < 0)
abort();
}
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);
#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;
/* 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
#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)
-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) {
}
#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 */
#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 <sys/socket.h>
#include <sys/un.h>
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 */
{
char *buffer, *p, *n;
int len, alen, i, chunk_size = DEFAULT_CHUNK_SIZE;
- static char buf[1024];
msg->data = NULL;
msg->len = 0;
(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.
}
} 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;
*/
#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;
}
#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);
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:
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
--- /dev/null
+#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 <sys/socket.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#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
+
#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 <stdio.h>
#include <getopt.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
-
-#include <globus_common.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/param.h>
#include "interlogd.h"
-#include "glite/lb/consumer.h"
#include "glite/lb/log_proto.h"
#include "glite/security/glite_gss.h"
#ifdef LB_PERF
#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"
" -k, --key <file> location of server private key\n"
" -C, --CAdir <dir> directory containing CA certificates\n"
" -b, --book send events to bookkeeping server only\n"
+ " -i, --pidfile pid file\n"
" -l, --log-server <host> specify address of log server\n"
" -s, --socket <path> non-default path of local socket\n"
" -L, --lazy [<timeout>] be lazy when closing connections to servers (default, timeout==0 means turn lazy off)\n"
+ " -p, --parallel [<num>] use <num> parallel streams to the same server\n"
+ " -q, --queue-low <num> queue length that enables another insertions\n"
+ " -Q, --queue-high <num> max queue length\n"
+ " -F, --conf <file> 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"
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;
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[] =
{
{"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'},
"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 */
"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)
log_server = strdup(optarg);
break;
+ case 'i':
+ pidfile = strdup(optarg);
+ break;
+
case 'C':
CAcert_dir = strdup(optarg);
break;
case 'L':
lazy_close = 1;
- if(optarg)
+ if(optarg)
default_close_timeout = atoi(optarg);
if(default_close_timeout == 0) {
default_close_timeout = TIMEOUT;
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;
}
-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)
{
char *p;
edg_wll_GssStatus gss_stat;
int ret;
+ FILE *pidf;
program_name = argv[0];
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 */
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
#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);
}
#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 <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
-#include <globus_common.h>
+#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;
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' },
"-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 <num> port to listen\n"
"-f, --file-prefix <prefix> path and prefix for event files\n"
"-c, --cert <file> location of server certificate\n"
"-k, --key <file> location of server private key\n"
"-C, --CAdir <dir> directory containing CA certificates\n"
"-s, --socket <dir> interlogger's socket to send messages to\n"
+ "-i, --pidfile <file> 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;
}
*----------------------------------------------------------------------
*
* 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;
}
/*
*----------------------------------------------------------------------
*/
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);
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;
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;
}
-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;
}
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);
while ((opt = getopt_long(argc,argv,
"h" /* help */
"V" /* version */
- "v" /* verbose */
"d" /* debug */
"p:" /* port */
"f:" /* file prefix */
"k:" /* key */
"C:" /* CA dir */
"s:" /* socket */
+ "i:" /* pidfile */
"x" /* noAuth */
"y" /* noIPC */
"z", /* noParse */
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;
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;
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); }
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
#endif
} /* while */
-end:
if (listener_fd) close(listener_fd);
- gss_release_cred(&min_stat, &cred);
+ edg_wll_gss_release_cred(&cred, NULL);
exit(ret);
}
#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 <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <syslog.h>
#include <fcntl.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <netdb.h>
+#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"
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;\
/*
*----------------------------------------------------------------------
*
+ * 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 -
*
*----------------------------------------------------------------------
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;
}
}
/* 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);
}
/* 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);
/* 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);
/* 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)
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);
{
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;
}
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;
/* 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;
}
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;
}
}
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;
}
/* 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;
}
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);
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;
}
/* 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:
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;
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);
-}
#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
extern "C" {
#endif
-
#include <syslog.h>
#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
#!/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
. $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
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 ()
echo -n "b)"
run_test il $numjobs
print_result
- rm -f /tmp/perftest.log.*
+ find /tmp -maxdepth 1 -name perftest.log.\* -exec rm -f \{\} \;
}
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 ()
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 "-------------------------------"
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 \{\} \;
}
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*" ]]
for variant in $TEST_VARIANT
do
+ export PERFTEST_NAME="il_${group}${variant}"
group_${group}_test_${variant}
done
done
#!/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
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*" ]]
--- /dev/null
+#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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+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;
+}
#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 <string.h>
#include <errno.h>
#include <assert.h>
+#include <stdio.h>
-#include "glite/lb/consumer.h"
+#include "glite/jobid/cjobid.h"
+#include "glite/lb/context.h"
#include "interlogd.h"
#endif
};
+#if !defined(IL_NOTIFICATIONS)
static struct event_queue *log_queue;
+#endif
static struct queue_list *queues;
return(-1);
}
el->queue = eq;
- el->next = queues;
+ el->next = *ql;
*ql = el;
return 0;
}
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;
dest = jobid2dest(job_id);
edg_wlc_JobIdFree(job_id);
+ outp = NULL;
#else
dest = job_id_s;
+ outp = plugin_get(dest);
#endif
if(dest == NULL)
#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)
{
#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
--- /dev/null
+#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 <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#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: */
#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 <stdio.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
+#include <unistd.h>
#include "interlogd.h"
{
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;
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);
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);
}
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;
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);
}
}
}
/* 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;
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
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);
#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 <stdio.h>
+#include <unistd.h>
#include <assert.h>
#include <errno.h>
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);
}
}
#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 <assert.h>
#include <errno.h>
-#ifdef HAVE_UNISTD_H
+#include <stdio.h>
#include <unistd.h>
-#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
* - 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"
}
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);
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;
{
char *msg=NULL;
int ret, code;
- int len, l;
+ int len;
struct timeval tv;
struct reader_data data;
int ret;
struct timeval tv;
edg_wll_GssStatus gss_stat;
+ cred_handle_t *local_cred_handle;
assert(eq != NULL);
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;
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
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
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
}
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;
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);
}
#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 */
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);
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 */
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 */
--- /dev/null
+#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 <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+
+/*
+ * - 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;
+}
#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 <errno.h>
#include <assert.h>
#include <string.h>
+#include <stdio.h>
#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
char *p; int len;
char *event = ev->data;
- *receipt = 0;
+ *receipt = 0L;
#if defined(INTERLOGD_EMS)
/* find DG.LLLID */
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);
}
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);
}
#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);
--- /dev/null
+#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 <errno.h>
+#include <assert.h>
+#include <string.h>
+
+#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;
+}
+/*
+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 <string.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
+
+ 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"
}
+/*
+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 <cppunit/extensions/HelperMacros.h>
#include "IlTestBase.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
+
+ 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 <cppunit/extensions/HelperMacros.h>
#include "IlTestBase.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
+
+ 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 <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.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
+
+ 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 <cppunit/extensions/HelperMacros.h>
#include "IlTestBase.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
+
+ 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 <iostream>
#include <cppunit/extensions/HelperMacros.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
+
+ 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 <sys/types.h>
#include <sys/socket.h>
#include <sys/un.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
+
+ 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 <cppunit/extensions/HelperMacros.h>
#include "IlTestBase.h"