[Opensrf-commits] r1970 - in branches/rel_1_4: . bin examples/apache2 include/opensrf src/extras src/libopensrf src/python/osrf src/router (dbs)

svn at svn.open-ils.org svn at svn.open-ils.org
Wed Jun 30 22:05:10 EDT 2010


Author: dbs
Date: 2010-06-30 22:05:08 -0400 (Wed, 30 Jun 2010)
New Revision: 1970

Added:
   branches/rel_1_4/examples/apache2/opensrf.conf
Removed:
   branches/rel_1_4/examples/apache2/opensrf
Modified:
   branches/rel_1_4/README
   branches/rel_1_4/bin/osrf_ctl.sh.in
   branches/rel_1_4/configure.ac
   branches/rel_1_4/include/opensrf/osrf_app_session.h
   branches/rel_1_4/include/opensrf/osrf_system.h
   branches/rel_1_4/include/opensrf/utils.h
   branches/rel_1_4/src/extras/Makefile.install
   branches/rel_1_4/src/libopensrf/opensrf.c
   branches/rel_1_4/src/libopensrf/osrf_app_session.c
   branches/rel_1_4/src/libopensrf/osrf_application.c
   branches/rel_1_4/src/libopensrf/osrf_prefork.c
   branches/rel_1_4/src/libopensrf/osrf_system.c
   branches/rel_1_4/src/libopensrf/transport_session.c
   branches/rel_1_4/src/libopensrf/utils.c
   branches/rel_1_4/src/python/osrf/gateway.py
   branches/rel_1_4/src/router/osrf_router.c
Log:
Merge r1950 through r1969 from trunk; prep for 1.4.0 release

Modified: branches/rel_1_4/README
===================================================================
--- branches/rel_1_4/README	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/README	2010-07-01 02:05:08 UTC (rev 1970)
@@ -19,7 +19,6 @@
   * "debian-etch" for Debian 4.0
   * "debian-lenny" for Debian 5.0
   * "ubuntu-hardy" for Ubuntu 8.04
-  * "ubuntu-intrepid" for Ubuntu 8.10
   * "ubuntu-karmic" for Ubuntu 9.10
 
 Less-tested values for <osname> include:

Modified: branches/rel_1_4/bin/osrf_ctl.sh.in
===================================================================
--- branches/rel_1_4/bin/osrf_ctl.sh.in	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/bin/osrf_ctl.sh.in	2010-07-01 02:05:08 UTC (rev 1970)
@@ -174,10 +174,7 @@
 	fi;
 
 	do_action "start" $PID_OSRF_C "OpenSRF C (host=$host)";
-	opensrf-c $host $OPT_CONFIG opensrf;
-    sleep 1; # give the main C proc time to appear in ps
-	pid=$(ps ax | grep "OpenSRF System-C" | grep -v grep | awk '{print $1}')
-	echo $pid > "$PID_OSRF_C";
+	opensrf-c $host $OPT_CONFIG opensrf "$PID_OSRF_C";
 	return 0;
 }
 

Modified: branches/rel_1_4/configure.ac
===================================================================
--- branches/rel_1_4/configure.ac	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/configure.ac	2010-07-01 02:05:08 UTC (rev 1970)
@@ -1,6 +1,6 @@
 # Copyright (C) 2008 Equinox Software, Inc.
 # Kevin Beswick <kevinbeswick00 at gmail.com>
-# Copyright (C) 2009 Dan Scott <dscott at laurentian.ca>
+# Copyright (C) 2009-2010 Dan Scott <dscott at laurentian.ca>
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -59,8 +59,6 @@
         fi
 ])
 
-
-
 #-------------------------------
 # Installation options
 #-------------------------------
@@ -146,6 +144,7 @@
 # path to the directory containing the java dependency jar files (included if java installs)
 if test $OSRF_INSTALL_JAVA; then
 	AC_SUBST([OSRF_JAVA_DEPSDIR], [/opt/java])
+    AC_CONFIG_FILES([src/java/Makefile])
 fi
 
 #--------------------------------
@@ -171,18 +170,44 @@
 [  --with-apxs=path                 location of the apxs (Apache extension) tool (default is /usr/bin/apxs2)],
 [APXS2=${withval}],
 [APXS2=/usr/bin/apxs2])
+if ! test -x "$APXS2"; then
+	for i in /usr/bin /usr/sbin /usr/local/apache/bin /usr/local/apache2/bin ; do
+		for j in apxs apxs2 ; do
+			if test -x "$i/$j"; then
+				APXS2="$i/$j"
+				break
+			fi
+		done
+	done
+fi
 AC_SUBST([APXS2])
 
 AC_ARG_WITH([apache],
 [  --with-apache=path               location of the Apache headers (default is /usr/include/apache2)],
 [APACHE2_HEADERS=${withval}],
 [APACHE2_HEADERS=/usr/include/apache2])
+if ! test -d "$APACHE2_HEADERS"; then
+	for i in /usr/include/httpd ; do
+		if test -d "$i"; then
+			APACHE2_HEADERS="$i"
+			break
+		fi
+	done
+fi
 AC_SUBST([APACHE2_HEADERS])
 
 AC_ARG_WITH([apr],
 [  --with-apr=path                  location of the Apache Portable Runtime headers (default is /usr/include/apr-1.0/)],
 [APR_HEADERS=${withval}],
 [APR_HEADERS=/usr/include/apr-1.0])
+if ! test -d "$APR_HEADERS"; then
+	for i in /usr/include/apr-1 ; do
+		if test -d "$i"; then
+			APR_HEADERS="$i"
+			break
+		fi
+	done
+fi
 AC_SUBST([APR_HEADERS])
 
 AC_ARG_WITH([libxml],
@@ -227,6 +252,19 @@
 AC_CONFIG_FILES([Makefile
 	src/Makefile])
 
+#PYTHON TESTS
+if test x$OSRF_INSTALL_PYTHON = xtrue; then
+    AC_CHECK_PROG([HAVE_PYTHON],python,yes,no)
+    if test $HAVE_PYTHON = "no"; then
+        AC_MSG_ERROR([*** python not found, aborting])
+    fi
+    AC_PYTHON_MOD([setuptools])
+    AC_CONFIG_FILES([
+        examples/math_client.py
+        src/python/Makefile
+    ])
+fi
+
 if test "x$OSRF_INSTALL_CORE" = "xtrue"; then
 	#--------------------------------
 	# Check for dependencies.
@@ -240,16 +278,6 @@
 	AC_MSG_ERROR([*** apxs not found, aborting])
 	fi  
 
-	#PYTHON TESTS
-	if test x$OSRF_INSTALL_PYTHON = xtrue; then
-		AC_CHECK_PROG([HAVE_PYTHON],python,yes,no)
-		if test $HAVE_PYTHON = "no"; then
-			AC_MSG_ERROR([*** python not found, aborting])
-		fi
-		AC_PYTHON_MOD([setuptools])
-	fi
-
-
 	#-----------------------------
 	# Checks for libraries.
 	#-----------------------------
@@ -302,16 +330,13 @@
 	AC_CONFIG_FILES([doc/dokuwiki-doc-stubber.pl
 			 examples/math_xul_client/Makefile
 			 examples/math_bench.pl
-			 examples/math_client.py
 			 examples/multisession-test.pl
 			 src/c-apps/Makefile
 			 src/gateway/Makefile
-			 src/java/Makefile
 			 src/jserver/Makefile
 			 src/libopensrf/Makefile
 			 src/perl/Makefile
 			 src/ports/strn_compat/Makefile
-			 src/python/Makefile
 			 src/router/Makefile
 			 src/srfsh/Makefile
 			 bin/opensrf-perl.pl

Deleted: branches/rel_1_4/examples/apache2/opensrf
===================================================================
--- branches/rel_1_4/examples/apache2/opensrf	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/examples/apache2/opensrf	2010-07-01 02:05:08 UTC (rev 1970)
@@ -1,49 +0,0 @@
-# This is a barebones Apache virtual host configuration, suitable
-# for testing out the OpenSRF gateway and HTTP translator, and
-# that's about it.
-
-NameVirtualHost *:80
-<VirtualHost *:80>
-	ServerName localhost:80
-	ServerAlias 127.0.0.1:80
- 	#DocumentRoot /openils/var/web/
-	#DirectoryIndex index.xml index.html index.xhtml
-
-	# ----------------------------------------------------------------------------------
-	# Configure the gateway
-	# ----------------------------------------------------------------------------------
-	OSRFGatewayConfig /openils/conf/opensrf_core.xml
-	# Translator memcache server.  Default is localhost
-	# OSRFTranslatorCacheServer 127.0.0.1:11211
-
-	# ----------------------------------------------------------------------------------
-	# XXX Note, it's important to explicitly set the JSON encoding style 
-	# (OSRFGatewayLegacyJSON), since the default encoding style will likely change 
-	# with OpenSRF 1.0
-	# ----------------------------------------------------------------------------------
-	# OpenSRF JSON legacy gateway
-	# ----------------------------------------------------------------------------------
-	<Location /gateway>
-		SetHandler osrf_json_gateway_module
-		OSRFGatewayLegacyJSON "true"
-		allow from all
-	</Location>
-	# ----------------------------------------------------------------------------------
-	# New-style OpenSRF JSON gateway
-	# ----------------------------------------------------------------------------------
-	<Location /osrf-gateway-v1>
-		SetHandler osrf_json_gateway_module
-		OSRFGatewayLegacyJSON "false"
-		allow from all
-	</Location>
-
-	# ----------------------------------------------------------------------------------
-	# OpenSRF-over-HTTP translator
-	# (http://open-ils.org/dokuwiki/doku.php?id=opensrf_over_http)
-	# ----------------------------------------------------------------------------------
-	<Location /osrf-http-translator>
-		SetHandler osrf_http_translator_module
-		allow from all
-	</Location>
-
-</VirtualHost>

Copied: branches/rel_1_4/examples/apache2/opensrf.conf (from rev 1969, trunk/examples/apache2/opensrf.conf)
===================================================================
--- branches/rel_1_4/examples/apache2/opensrf.conf	                        (rev 0)
+++ branches/rel_1_4/examples/apache2/opensrf.conf	2010-07-01 02:05:08 UTC (rev 1970)
@@ -0,0 +1,49 @@
+# This is a barebones Apache virtual host configuration, suitable
+# for testing out the OpenSRF gateway and HTTP translator, and
+# that's about it.
+
+NameVirtualHost *:80
+<VirtualHost *:80>
+	ServerName localhost:80
+	ServerAlias 127.0.0.1:80
+ 	#DocumentRoot /openils/var/web/
+	#DirectoryIndex index.xml index.html index.xhtml
+
+	# ----------------------------------------------------------------------------------
+	# Configure the gateway
+	# ----------------------------------------------------------------------------------
+	OSRFGatewayConfig /openils/conf/opensrf_core.xml
+	# Translator memcache server.  Default is localhost
+	# OSRFTranslatorCacheServer 127.0.0.1:11211
+
+	# ----------------------------------------------------------------------------------
+	# XXX Note, it's important to explicitly set the JSON encoding style 
+	# (OSRFGatewayLegacyJSON), since the default encoding style will likely change 
+	# with OpenSRF 1.0
+	# ----------------------------------------------------------------------------------
+	# OpenSRF JSON legacy gateway
+	# ----------------------------------------------------------------------------------
+	<Location /gateway>
+		SetHandler osrf_json_gateway_module
+		OSRFGatewayLegacyJSON "true"
+		allow from all
+	</Location>
+	# ----------------------------------------------------------------------------------
+	# New-style OpenSRF JSON gateway
+	# ----------------------------------------------------------------------------------
+	<Location /osrf-gateway-v1>
+		SetHandler osrf_json_gateway_module
+		OSRFGatewayLegacyJSON "false"
+		allow from all
+	</Location>
+
+	# ----------------------------------------------------------------------------------
+	# OpenSRF-over-HTTP translator
+	# (http://open-ils.org/dokuwiki/doku.php?id=opensrf_over_http)
+	# ----------------------------------------------------------------------------------
+	<Location /osrf-http-translator>
+		SetHandler osrf_http_translator_module
+		allow from all
+	</Location>
+
+</VirtualHost>

Modified: branches/rel_1_4/include/opensrf/osrf_app_session.h
===================================================================
--- branches/rel_1_4/include/opensrf/osrf_app_session.h	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/include/opensrf/osrf_app_session.h	2010-07-01 02:05:08 UTC (rev 1970)
@@ -19,9 +19,6 @@
 extern "C" {
 #endif
 
-#define DEF_RECV_TIMEOUT 6 /* receive timeout */
-#define DEF_QUEUE_SIZE
-
 enum OSRF_SESSION_STATE { 
 	OSRF_SESSION_CONNECTING,
 	OSRF_SESSION_CONNECTED,
@@ -87,6 +84,10 @@
 
 	/** Hash table of pending requests. */
 	osrfAppRequest* request_hash[ OSRF_REQUEST_HASH_SIZE ];
+
+	/** Boolean: true if the app wants to terminate the process.  Typically this means that */
+	/** a drone has lost its database connection and can therefore no longer function.      */
+	int panic;
 };
 typedef struct osrf_app_session_struct osrfAppSession;
 
@@ -149,6 +150,8 @@
 
 void osrfAppSessionCleanup( void );
 
+void osrfAppSessionPanic( osrfAppSession* ses );
+
 #ifdef __cplusplus
 }
 #endif

Modified: branches/rel_1_4/include/opensrf/osrf_system.h
===================================================================
--- branches/rel_1_4/include/opensrf/osrf_system.h	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/include/opensrf/osrf_system.h	2010-07-01 02:05:08 UTC (rev 1970)
@@ -17,6 +17,8 @@
 extern "C" {
 #endif
 
+void osrfSystemSetPidFile( const char* name );
+
 int osrf_system_bootstrap_client( char* config_file, char* contextnode );
 
 int osrfSystemBootstrapClientResc( const char* config_file,

Modified: branches/rel_1_4/include/opensrf/utils.h
===================================================================
--- branches/rel_1_4/include/opensrf/utils.h	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/include/opensrf/utils.h	2010-07-01 02:05:08 UTC (rev 1970)
@@ -280,7 +280,6 @@
 int init_proc_title( int argc, char* argv[] );
 int set_proc_title( const char* format, ... );
 
-
 int daemonize( void );
 
 void* safe_malloc(int size);

Modified: branches/rel_1_4/src/extras/Makefile.install
===================================================================
--- branches/rel_1_4/src/extras/Makefile.install	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/src/extras/Makefile.install	2010-07-01 02:05:08 UTC (rev 1970)
@@ -3,8 +3,8 @@
 #
 # Makefile to install prerequisites for OpenSRF
 #
-# Currently supports Debian (etch/lenny), Ubuntu (hardy/intrepid/karmic), and Gentoo.
-# Working towards support of CentOS 5 / RHEL 5.
+# Currently supports Debian (etch/lenny), Ubuntu (hardy/karmic), and Gentoo.
+# Working towards support of CentOS 5 / RHEL 5 and Fedora.
 # Installs Perl prereqs, libjs with Perl wrapper
 #
 # usage:
@@ -14,8 +14,6 @@
 # 	- or -
 # 	make -f Makefile.install ubuntu-hardy
 # 	- or -
-# 	make -f Makefile.install ubuntu-intrepid
-# 	- or -
 # 	make -f Makefile.install ubuntu-karmic
 # 	- or -
 # 	make -f Makefile.install centos
@@ -23,6 +21,8 @@
 # 	make -f Makefile.install rhel
 # 	- or -
 # 	make -f Makefile.install gentoo
+# 	- or -
+# 	make -f Makefile.install fedora13
 #
 # Notes:
 #
@@ -42,15 +42,19 @@
 # Gentoo needs explicit versions on many of these packages
 # to simulate a "blessed" set of packages
 
+# 64 or 32 bit os?
+LBITS=$(shell getconf LONG_BIT)
+
 # ejabberd is not packaged on CentOS/RHEL, so we have to
 # download the installable package from the source
 EJABBERD_VER=2.1.2
-EJABBERD_PKG=ejabberd-2.1.2-linux-x86_64-installer.bin
+EJABBERD_PKG=ejabberd-2.1.2-linux-x86-installer.bin
 EJABBERD_PKG_x64=ejabberd-2.1.2-linux-x86_64-installer.bin
 EJABBERD_HOST=http://www.process-one.net/downloads/ejabberd
 
 # Centos and Redhat will require the rpmforge repository mostly for memcache and perl modules
-RPMFORGE_PKG=rpmforge-release-0.5.1-1.el5.rf.x86_64.rpm
+RPMFORGE_PKG_x64=rpmforge-release-0.5.1-1.el5.rf.x86_64.rpm
+RPMFORGE_PKG=rpmforge-release-0.5.1-1.el5.rf.i386.rpm
 RPMFORGE_HOST=http://packages.sw.be/rpmforge-release
 
 # need newer libtool, autoconf, and automake on centos
@@ -125,7 +129,7 @@
 	python-setuptools
 
 CENTOS = \
-	apr-util-devel.x86_64 \
+	apr-util-devel \
 	autoconf \
 	automake \
 	gcc \
@@ -162,19 +166,13 @@
 	perl-Log-Log4perl \
 	perl-Memcached-libmemcached \
 	perl-Module-Build \
-	perl-Net-Jabber \
 	perl-Net-Server \
-	perl-RPC-XML \
 	perl-Template-Toolkit \
 	perl-Test-Pod \
 	perl-Tie-IxHash \
 	perl-UNIVERSAL-require \
 	perl-Unix-Syslog \
-	perl-XML-LibXML \
-	perl-XML-LibXSLT \
 	perl-XML-Parser \
-	perl-XML-Simple \
-	perl-XML-RPC \
 	psmisc \
 	python-devel \
 	python-setuptools\
@@ -182,7 +180,72 @@
 	wget
 
 CENTOS_PERL = \
+	Net::Jabber \
+	Net::XMPP \
+	RPC::XML \
+	XML::LibXML \
+	XML::LibXSLT \
+	XML::Simple
 
+FEDORAS = \
+	autoconf \
+	automake \
+	ejabberd \
+	expat-devel \
+	gcc \
+	gdbm-devel \
+	httpd \
+	httpd-devel \
+	less \
+	libgcrypt-devel \
+	libmemcached \
+	libmemcached-devel \
+	libtool \
+	libxml2-devel \
+	libxml2-python \
+	libxslt-devel \
+	make \
+	memcached \
+	mod_perl \
+	ntpdate \
+	perl-Cache-Memcached \
+	perl-Class-DBI \
+	perl-Class-DBI-AbstractSearch \
+	perl-Class-DBI-SQLite \
+	perl-DateTime-Format-Builder \
+	perl-DateTime-Format-ISO8601 \
+	perl-DateTime-Format-Mail \
+	perl-DateTime-Set \
+	perl-devel \
+	perl-Error \
+	perl-File-Find-Rule \
+	perl-FreezeThaw \
+	perl-JSON-XS \
+	perl-libwww-perl \
+	perl-Log-Log4perl \
+	perl-Module-Build \
+	perl-Net-Jabber \
+	perl-Net-Server \
+	perl-RPC-XML \
+	perl-SQL-Abstract-Limit \
+	perl-Template-Toolkit \
+	perl-Test-Deep \
+	perl-Test-Exception \
+	perl-Test-Pod \
+	perl-Tie-IxHash \
+	perl-UNIVERSAL-require \
+	perl-Unix-Syslog \
+	perl-XML-LibXML \
+	perl-XML-LibXSLT \
+	perl-XML-Simple \
+	psmisc \
+	python-devel \
+	python-dns \
+	python-memcached \
+	python-setuptools \
+	python-simplejson \
+	readline-devel
+
 GENTOOS = \
 	vim\
 	ntp\
@@ -266,15 +329,15 @@
 lenny: install_extra_debs
 generic_debian: install_debs install_cpan_force install_cpan_xml debian_sys_config
 
+fedora13: install_fedora_rpms
+
 gentoo: install_gentoos install_gentoo_rc install_gentoo_perl install
 
 rhel: centos
 
 ubuntu-hardy: generic_ubuntu install_cpan_xml hardy
-ubuntu-intrepid: generic_ubuntu install_cpan_xml intrepid
 ubuntu-karmic: generic_ubuntu karmic
 hardy: install_cpan install_libmemcached 
-intrepid: install_extra_debs install_libmemcached 
 karmic: install_extra_debs install_extra_debs_karmic
 generic_ubuntu: install_debs install_cpan_force debian_sys_config
 
@@ -293,16 +356,39 @@
 	for m in $(CPAN_MODULES_XML); do perl -MCPAN -e "install \"$$m\";"; done
 
 # Install ejabberd from official project installer binary
-install_ejabberd:    
-	if [ ! -f $(EJABBERD_PKG).gz ]; then wget $(EJABBERD_HOST)/$(EJABBERD_VER)/$(EJABBERD_PKG).gz; fi;
-	gunzip $(EJABBERD_PKG).gz
-	chmod u+x $(EJABBERD_PKG)
-	./$(EJABBERD_PKG) --mode unattended --prefix /opt/ejabberd --adminpw opensrf
+install_ejabberd:
+	if [ $(LBITS) -eq 64 ]; then \
+		if [ ! -f $(EJABBERD_PKG_x64).gz ]; then \
+			wget $(EJABBERD_HOST)/$(EJABBERD_VER)/$(EJABBERD_PKG_x64).gz; \
+		fi; \
+		gunzip $(EJABBERD_PKG_x64).gz; \
+		chmod u+x $(EJABBERD_PKG_x64); \
+		./$(EJABBERD_PKG_x64) --mode unattended --prefix /opt/ejabberd --adminpw opensrf ; \
+	fi;
+	if [ $(LBITS) -eq 32 ]; then \
+		if [ ! -f $(EJABBERD_PKG).gz ]; then \
+			wget $(EJABBERD_HOST)/$(EJABBERD_VER)/$(EJABBERD_PKG).gz; \
+		fi; \
+		gunzip $(EJABBERD_PKG).gz; \
+		chmod u+x $(EJABBERD_PKG); \
+		./$(EJABBERD_PKG) --mode unattended --prefix /opt/ejabberd --adminpw opensrf ; \
+	fi;
 
 # Install rpmforge for redhat and centos
 install_rpmforge:
-	if [ ! -f $(RPMFORGE_PKG).gz ]; then wget $(RPMFORGE_HOST)/$(RPMFORGE_PKG); fi;
-	rpm -Uvh --force ./$(RPMFORGE_PKG)
+	if [ $(LBITS) -eq 64 ]; then \
+		if [ ! -f $(RPMFORGE_PKG_x64) ]; then \
+			wget $(RPMFORGE_HOST)/$(RPMFORGE_PKG_x64) ; \
+			yum -y remove subversion*i386 ; \
+		fi; \
+		rpm -Uvh --force ./$(RPMFORGE_PKG_x64) ; \
+	fi;
+	if [ $(LBITS) -eq 32 ]; then \
+		if [ ! -f $(RPMFORGE_PKG) ]; then \
+			wget $(RPMFORGE_HOST)/$(RPMFORGE_PKG) ; \
+		fi; \
+		rpm -Uvh --force ./$(RPMFORGE_PKG) ; \
+	fi;
 	yum update -y
 
 # Install automake, autoconf, and libtool
@@ -383,9 +469,14 @@
 
 # ------------------------------------------------------------------
 
+# Fedora
+install_fedora_rpms:
+	yum -y install $(FEDORAS)
+
 # CENTOS
 install_centos_rpms:
 	yum -y install $(CENTOS)
+	yum -y update
 
 install_centos_perl:
 	for m in $(CENTOS_PERL_FORCE); do perl -MCPAN -e "CPAN::Shell->force(qw#install $$m#);"; done

Modified: branches/rel_1_4/src/libopensrf/opensrf.c
===================================================================
--- branches/rel_1_4/src/libopensrf/opensrf.c	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/src/libopensrf/opensrf.c	2010-07-01 02:05:08 UTC (rev 1970)
@@ -1,5 +1,17 @@
-#include <opensrf/osrf_system.h>
+#include "opensrf/osrf_system.h"
 
+/**
+	@brief Run an OSRF server as defined by the command line and a config file.
+	@param argc Number of command line arguments, plus one.
+	@param argv Ragged array of command name plus command line arguments.
+	@return 0 if successful, or 1 if failure.
+
+	Command line parameters:
+	- Full network name of the host where the process is running; or 'localhost' will do.
+	- Name of the configuration file; normally '/openils/conf/opensrf_core.xml'.
+	- Name of an aggregate within the configuration file, containing the relevant subset
+	of configuration stuff.
+*/
 int main( int argc, char* argv[] ) {
 
 	if( argc < 4 ) {
@@ -7,12 +19,15 @@
 		return 1;
 	}
 
-	/* these must be strdup'ed because init_proc_title / set_proc_title 
+	/* these must be strdup'ed because init_proc_title / set_proc_title
 		are evil and overwrite the argv memory */
-	char* host		= strdup( argv[1] );
-	char* config	= strdup( argv[2] );
-	char* context	= strdup( argv[3] );
+	char* host      = strdup( argv[1] );
+	char* config    = strdup( argv[2] );
+	char* context   = strdup( argv[3] );
 
+	if( argv[4] )
+		osrfSystemSetPidFile( argv[4] );
+
 	init_proc_title( argc, argv );
 	set_proc_title( "OpenSRF System-C" );
 
@@ -26,7 +41,6 @@
 		);
 	}
 
-
 	free(host);
 	free(config);
 	free(context);

Modified: branches/rel_1_4/src/libopensrf/osrf_app_session.c
===================================================================
--- branches/rel_1_4/src/libopensrf/osrf_app_session.c	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/src/libopensrf/osrf_app_session.c	2010-07-01 02:05:08 UTC (rev 1970)
@@ -240,9 +240,13 @@
 	becomes available before the end of the timeout; otherwise NULL;
 
 	If there is already a message available in the input queue for this request, dequeue and
-	return it 	immediately.  Otherwise wait up to timeout seconds until you either get an
+	return it immediately.  Otherwise wait up to timeout seconds until you either get an
 	input message for the specified request, run out of time, or encounter an error.
 
+	If the only message we receive for this request is a STATUS message with a status code
+	OSRF_STATUS_COMPLETE, then return NULL.  That means that the server has nothing further
+	to send in response to this request.
+
 	You may also receive other messages for other requests, and other sessions.  These other
 	messages will be wholly or partially processed behind the scenes while you wait for the
 	one you want.
@@ -271,7 +275,7 @@
 		osrfLogDebug( OSRF_LOG_MARK,  "In app_request receive with remaining time [%d]",
 				(int) remaining );
 
-		
+
 		osrf_app_session_queue_wait( req->session, 0, NULL );
 		if(req->session->transport_error) {
 			osrfLogError(OSRF_LOG_MARK, "Transport error in recv()");
@@ -474,6 +478,7 @@
 	session->remote_service = strdup(remote_service);
 	session->session_locale = NULL;
 	session->transport_error = 0;
+	session->panic = 0;
 
 	#ifdef ASSUME_STATELESS
 	session->stateless = 1;
@@ -813,6 +818,8 @@
 
 	/* defaulting to protocol 1 for now */
 	osrfMessage* con_msg = osrf_message_init( CONNECT, session->thread_trace, 1 );
+
+	// Address this message to the router
 	osrf_app_session_reset_remote( session );
 	session->state = OSRF_SESSION_CONNECTING;
 	int ret = _osrf_app_session_send( session, con_msg );
@@ -999,12 +1006,12 @@
 	message; process subsequent messages if they are available, but don't wait for them.
 
 	The first parameter identifies an osrfApp session, but all we really use it for is to
-	get a pointer to the transport_session.  Typically, if not always, a given process
-	opens only a single transport_session (to talk to the Jabber server), and all app
-	sessions in that process use the same transport_session.
+	get a pointer to the transport_session.  Typically, a given process opens only a single
+	transport_session (to talk to the Jabber server), and all app sessions in that process
+	use the same transport_session.
 
-	Hence this function indiscriminately waits for input messages for all osrfAppSessions,
-	not just the one specified.
+	Hence this function indiscriminately waits for input messages for all osrfAppSessions
+	tied to the same Jabber session, not just the one specified.
 
 	Dispatch each message to the appropriate processing routine, depending on its type
 	and contents, and on whether we're acting as a client or as a server for that message.
@@ -1059,7 +1066,7 @@
 	free(session->orig_remote_id);
 	free(session->session_id);
 	free(session->remote_service);
-	
+
 	// Free the request hash
 	int i;
 	for( i = 0; i < OSRF_REQUEST_HASH_SIZE; ++i ) {
@@ -1192,7 +1199,7 @@
 
 /**
 	@brief Free the global session cache.
-	
+
 	Note that the osrfHash that implements the global session cache does @em not have a
 	callback function installed for freeing its cargo.  As a result, any remaining
 	osrfAppSessions are leaked, along with all the osrfAppRequests and osrfMessages they
@@ -1203,7 +1210,14 @@
 	osrfAppSessionCache = NULL;
 }
 
+/**
+	@brief Arrange for immediate termination of the process.
+	@param ses Pointer to the current osrfAppSession.
 
-
-
-
+	Typical use case: a server drone loses its database connection, thereby becoming useless.
+	It terminates so that it will not receive further requests, being unable to service them.
+*/
+void osrfAppSessionPanic( osrfAppSession* ses ) {
+	if( ses )
+		ses->panic = 1;
+}

Modified: branches/rel_1_4/src/libopensrf/osrf_application.c
===================================================================
--- branches/rel_1_4/src/libopensrf/osrf_application.c	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/src/libopensrf/osrf_application.c	2010-07-01 02:05:08 UTC (rev 1970)
@@ -90,10 +90,12 @@
 	appear in subsequent log messages.
 */
 int osrfAppRegisterApplication( const char* appName, const char* soFile ) {
-	if(!appName || ! soFile) return -1;
+	if( !appName || ! soFile ) return -1;
 	char* error;
 
-	if(!_osrfAppHash)
+	osrfLogSetAppname( appName );
+
+	if( !_osrfAppHash )
 		_osrfAppHash = osrfNewHash();
 
 	osrfLogInfo( OSRF_LOG_MARK, "Registering application %s with file %s", appName, soFile );
@@ -137,8 +139,6 @@
 
 	osrfLogInfo( OSRF_LOG_MARK, "Application %s registered successfully", appName );
 
-	osrfLogSetAppname(appName);
-
 	osrfAppSetOnExit(app, appName);
 
 	return 0;

Modified: branches/rel_1_4/src/libopensrf/osrf_prefork.c
===================================================================
--- branches/rel_1_4/src/libopensrf/osrf_prefork.c	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/src/libopensrf/osrf_prefork.c	2010-07-01 02:05:08 UTC (rev 1970)
@@ -1,6 +1,6 @@
 /**
 	@file osrf_prefork.c
-	@brief Implementation of 
+	@brief Spawn and manage a collection of child process to service requests.
 
 	Spawn a collection of child processes, replacing them as needed.  Forward requests to them
 	and let the children do the work.
@@ -9,19 +9,21 @@
 	child dies, either deliberately or otherwise, we can spawn another one to replace it,
 	keeping the number of children within a predefined range.
 
-	Use a doubly-linked circular list to keep track of the children, forwarding requests to them
-	in an approximately round-robin fashion.
+	Use a doubly-linked circular list to keep track of the children to whom we have forwarded
+	a request, and who are still working on them.  Use a separate linear linked list to keep
+	track of children that are currently idle.  Move them back and forth as needed.
 
 	For each child, set up two pipes:
 	- One for the parent to send requests to the child.
 	- One for the child to notify the parent that it is available for another request.
 
-	The message sent to the child is an XML stanza as received from Jabber.
+	The message sent to the child represents an XML stanza as received from Jabber.
 
 	When the child finishes processing the request, it writes the string "available" back
 	to the parent.  Then the parent knows that it can send that child another request.
 */
 
+#include <errno.h>
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/time.h>
@@ -52,31 +54,36 @@
 	int current_num_children;   /**< How many children are currently on the list. */
 	int keepalive;        /**< Keepalive time for stateful sessions. */
 	char* appname;        /**< Name of the application. */
-	/** Points to a circular linked list of children */
+	/** Points to a circular linked list of children. */
 	struct prefork_child_struct* first_child;
+	/** List of of child processes that aren't doing anything at the moment and are
+		therefore available to service a new request. */
+	struct prefork_child_struct* idle_list;
 	/** List of allocated but unused prefork_children, available for reuse.  Each one is just
 		raw memory, apart from the "next" pointer used to stitch them together.  In particular,
 		there is no child process for them, and the file descriptors are not open. */
 	struct prefork_child_struct* free_list;
-	transport_client* connection;  /**< Connection to Jabber */
+	transport_client* connection;  /**< Connection to Jabber. */
 } prefork_simple;
 
 struct prefork_child_struct {
-	pid_t pid;            /**< Process ID of the child */
-	int read_data_fd;     /**< Child uses to read request */
-	int write_data_fd;    /**< Parent uses to write request */
-	int read_status_fd;   /**< Parent reads to see if child is available */
-	int write_status_fd;  /**< Child uses to notify parent when it's available again */
-	int available;        /**< Boolean; true when the child is between requests */
-	int max_requests;     /**< How many requests a child can process before terminating */
-	const char* appname;  /**< Name of the application */
+	pid_t pid;            /**< Process ID of the child. */
+	int read_data_fd;     /**< Child uses to read request. */
+	int write_data_fd;    /**< Parent uses to write request. */
+	int read_status_fd;   /**< Parent reads to see if child is available. */
+	int write_status_fd;  /**< Child uses to notify parent when it's available again. */
+	int max_requests;     /**< How many requests a child can process before terminating. */
+	const char* appname;  /**< Name of the application. */
 	int keepalive;        /**< Keepalive time for stateful sessions. */
-	struct prefork_child_struct* next;  /**< Linkage pointer for linked list */
-	struct prefork_child_struct* prev;  /**< Linkage pointer for linked list */
+	struct prefork_child_struct* next;  /**< Linkage pointer for linked list. */
+	struct prefork_child_struct* prev;  /**< Linkage pointer for linked list. */
 };
 
 typedef struct prefork_child_struct prefork_child;
 
+/** Boolean.  Set to true by a signal handler when it traps SIGCHLD. */
+static volatile sig_atomic_t child_dead;
+
 static int prefork_simple_init( prefork_simple* prefork, transport_client* client,
 	int max_requests, int min_children, int max_children );
 static prefork_child* launch_child( prefork_simple* forker );
@@ -86,7 +93,7 @@
 
 static void del_prefork_child( prefork_simple* forker, pid_t pid );
 static void check_children( prefork_simple* forker, int forever );
-static void prefork_child_process_request(prefork_child*, char* data);
+static int  prefork_child_process_request(prefork_child*, char* data);
 static int prefork_child_init_hook(prefork_child*);
 static prefork_child* prefork_child_init( prefork_simple* forker,
 		int read_data_fd, int write_data_fd,
@@ -99,12 +106,14 @@
 static void osrf_prefork_register_routers( const char* appname );
 static void osrf_prefork_child_exit( prefork_child* );
 
-/** Boolean.  Set to true by a signal handler when it traps SIGCHLD. */
-static volatile sig_atomic_t child_dead;
-
 static void sigchld_handler( int sig );
 
-int osrf_prefork_run(const char* appname) {
+/**
+	@brief Spawn and manage a collection of drone processes for servicing requests.
+	@param appname Name of the application.
+	@return 0 if successful, or -1 if error.
+*/
+int osrf_prefork_run( const char* appname ) {
 
 	if(!appname) {
 		osrfLogError( OSRF_LOG_MARK, "osrf_prefork_run requires an appname to run!");
@@ -147,6 +156,7 @@
 
 	char* resc = va_list_to_string("%s_listener", appname);
 
+	// Make sure that we haven't already booted
 	if(!osrfSystemBootstrapClientResc( NULL, NULL, resc )) {
 		osrfLogError( OSRF_LOG_MARK, "Unable to bootstrap client for osrf_prefork_run()");
 		free(resc);
@@ -163,14 +173,14 @@
 		return -1;
 	}
 
-	// Finish initializing the prefork_simple
+	// Finish initializing the prefork_simple.
 	forker.appname   = strdup(appname);
 	forker.keepalive = kalive;
 
-	// Spawn the children
+	// Spawn the children; put them in the idle list.
 	prefork_launch_children( &forker );
 
-	// Tell the router that you're open for business
+	// Tell the router that you're open for business.
 	osrf_prefork_register_routers(appname);
 
 	// Sit back and let the requests roll in
@@ -189,6 +199,8 @@
 	@param routerDomain Domain of the router.
 
 	Tell the router that you're open for business so that it can route requests to you.
+
+	Called only by the parent process.
 */
 static void osrf_prefork_send_router_registration(
 		const char* appname, const char* routerName, const char* routerDomain ) {
@@ -209,8 +221,9 @@
 	free(jid);
 }
 
-/** parses a single "complex" router configuration chunk */
-static void osrf_prefork_parse_router_chunk(const char* appname, jsonObject* routerChunk) {
+/* parses a single "complex" router configuration chunk */
+// Called only by the parent process
+static void osrf_prefork_parse_router_chunk(const char* appname, const jsonObject* routerChunk) {
 
 	const char* routerName = jsonObjectGetString(jsonObjectGetKeyConst(routerChunk, "name"));
 	const char* domain = jsonObjectGetString(jsonObjectGetKeyConst(routerChunk, "domain"));
@@ -240,13 +253,19 @@
 	}
 }
 
+/**
+	@brief Register the application with one or more routers, according to the configuration.
+	@param appname Name of the application.
+
+	Called only by the parent process.
+*/
 static void osrf_prefork_register_routers( const char* appname ) {
 
 	jsonObject* routerInfo = osrfConfigGetValueObject(NULL, "/routers/router");
 
 	int i;
 	for(i = 0; i < routerInfo->size; i++) {
-		jsonObject* routerChunk = jsonObjectGetIndex(routerInfo, i);
+		const jsonObject* routerChunk = jsonObjectGetIndex(routerInfo, i);
 
 		if(routerChunk->type == JSON_STRING) {
 			/* this accomodates simple router configs */
@@ -256,31 +275,48 @@
 					routerName);
 			osrf_prefork_send_router_registration(appname, routerName, domain);
 
+			free( routerName );
+			free( domain );
 		} else {
 			osrf_prefork_parse_router_chunk(appname, routerChunk);
 		}
 	}
+
+	jsonObjectFree( routerInfo );
 }
 
+/**
+	@brief Initialize a child process.
+	@param child Pointer to the prefork_child representing the new child process.
+	@return Zero if successful, or -1 if not.
+
+	Called only by child processes.  Actions:
+	- Connect to one or more cache servers
+	- Reconfigure logger, if necessary
+	- Discard parent's Jabber connection and open a new one
+	- Dynamically call an application-specific initialization routine
+	- Change the command line as reported by ps
+*/
 static int prefork_child_init_hook(prefork_child* child) {
 
 	if(!child) return -1;
 	osrfLogDebug( OSRF_LOG_MARK, "Child init hook for child %d", child->pid);
 
+	// Connect to cache server(s).
 	osrfSystemInitCache();
 	char* resc = va_list_to_string("%s_drone", child->appname);
 
-	/* if we're a source-client, tell the logger now that we're a new process*/
+	// If we're a source-client, tell the logger now that we're a new process.
 	char* isclient = osrfConfigGetValue(NULL, "/client");
 	if( isclient && !strcasecmp(isclient,"true") )
 		osrfLogSetIsClient(1);
 	free(isclient);
 
-	/* we want to remove traces of our parents socket connection
-	* so we can have our own */
+	// Remove traces of our parent's socket connection so we can have our own.
 	osrfSystemIgnoreTransportClient();
 
-	if(!osrfSystemBootstrapClientResc( NULL, NULL, resc)) {
+	// Connect to Jabber
+	if(!osrfSystemBootstrapClientResc( NULL, NULL, resc )) {
 		osrfLogError( OSRF_LOG_MARK, "Unable to bootstrap client for osrf_prefork_run()");
 		free(resc);
 		return -1;
@@ -288,6 +324,8 @@
 
 	free(resc);
 
+	// Dynamically call the application-specific initialization function
+	// from a previously loaded shared library.
 	if( ! osrfAppRunChildInit(child->appname) ) {
 		osrfLogDebug(OSRF_LOG_MARK, "Prefork child_init succeeded\n");
 	} else {
@@ -295,12 +333,16 @@
 		return -1;
 	}
 
+	// Change the command line as reported by ps
 	set_proc_title( "OpenSRF Drone [%s]", child->appname );
 	return 0;
 }
 
-static void prefork_child_process_request(prefork_child* child, char* data) {
-	if( !child ) return;
+// Called only by a child process
+// Non-zero return code means that the child process has decided to terminate immediately,
+// without waiting for a DISCONNECT or max_requests.
+static int prefork_child_process_request(prefork_child* child, char* data) {
+	if( !child ) return 0;
 
 	transport_client* client = osrfSystemGetTransportClient();
 
@@ -319,11 +361,20 @@
 	transport_message* msg = new_message_from_xml( data );
 
 	osrfAppSession* session = osrf_stack_transport_handler(msg, child->appname);
-	if(!session) return;
+	if(!session) return 0;
 
+	int rc = session->panic;
+
+	if( rc ) {
+		osrfLogWarning( OSRF_LOG_MARK,
+			"Drone for session %s terminating immediately", session->session_id );
+		osrfAppSessionFree( session );
+		return rc;
+	}
+
 	if( session->stateless && session->state != OSRF_SESSION_CONNECTED ) {
 		osrfAppSessionFree( session );
-		return;
+		return rc;
 	}
 
 	osrfLogDebug( OSRF_LOG_MARK, "Entering keepalive loop for session %s", session->session_id );
@@ -343,6 +394,9 @@
 
 		osrfLogDebug(OSRF_LOG_MARK, "Data received == %d", recvd);
 
+		if( session->panic )
+			rc = 1;
+
 		if(retval) {
 			osrfLogError(OSRF_LOG_MARK, "queue-wait returned non-success %d", retval);
 			break;
@@ -364,25 +418,29 @@
 
 			break;
 		}
+
+		// If the child process has decided to terminate immediately
+		if( rc )
+			break;
 	}
 
 	osrfLogDebug( OSRF_LOG_MARK, "Exiting keepalive loop for session %s", session->session_id );
 	osrfAppSessionFree( session );
-	return;
+	return rc;
 }
 
-
 /**
 	@brief Partially initialize a prefork_simple provided by the caller.
 	@param prefork Pointer to a a raw prefork_simple to be initialized.
 	@param client Pointer to a transport_client (connection to Jabber).
-	@param max_requests
+	@param max_requests The maximum number of requests that a child process may service
+			before terminating.
 	@param min_children Minimum number of child processes to maintain.
 	@param max_children Maximum number of child processes to maintain.
 	@return 0 if successful, or 1 if not (due to invalid parameters).
 */
 static int prefork_simple_init( prefork_simple* prefork, transport_client* client,
-		 int max_requests, int min_children, int max_children ) {
+		int max_requests, int min_children, int max_children ) {
 
 	if( min_children > max_children ) {
 		osrfLogError( OSRF_LOG_MARK,  "min_children (%d) is greater "
@@ -400,7 +458,6 @@
 		"min_children=%d, max_children=%d", max_requests, min_children, max_children );
 
 	/* flesh out the struct */
-	//prefork_simple* prefork = safe_malloc(sizeof(prefork_simple));
 	prefork->max_requests = max_requests;
 	prefork->min_children = min_children;
 	prefork->max_children = max_children;
@@ -411,19 +468,30 @@
 	prefork->keepalive    = 0;
 	prefork->appname      = NULL;
 	prefork->first_child  = NULL;
+	prefork->idle_list    = NULL;
 	prefork->free_list    = NULL;
 	prefork->connection   = client;
 
 	return 0;
 }
 
+/**
+	@brief Spawn a new child process and put it in the idle list.
+	@param forker Pointer to the prefork_simple that will own the process.
+	@return Pointer to the new prefork_child, or not at all.
+
+	Spawn a new child process.  Create a prefork_child for it and put it in the idle list.
+
+	After forking, the parent returns a pointer to the new prefork_child.  The child
+	services its quota of requests and then terminates without returning.
+*/
 static prefork_child* launch_child( prefork_simple* forker ) {
 
 	pid_t pid;
 	int data_fd[2];
 	int status_fd[2];
 
-	/* Set up the data pipes and add the child struct to the parent */
+	// Set up the data and status pipes
 	if( pipe(data_fd) < 0 ) { /* build the data pipe*/
 		osrfLogError( OSRF_LOG_MARK,  "Pipe making error" );
 		return NULL;
@@ -431,28 +499,35 @@
 
 	if( pipe(status_fd) < 0 ) {/* build the status pipe */
 		osrfLogError( OSRF_LOG_MARK,  "Pipe making error" );
+		close( data_fd[1] );
+		close( data_fd[0] );
 		return NULL;
 	}
 
-	osrfLogInternal( OSRF_LOG_MARK,  "Pipes: %d %d %d %d",
+	osrfLogInternal( OSRF_LOG_MARK, "Pipes: %d %d %d %d",
 			data_fd[0], data_fd[1], status_fd[0], status_fd[1] );
+
+	// Create and initialize a prefork_child for the new process
 	prefork_child* child = prefork_child_init( forker, data_fd[0],
 			data_fd[1], status_fd[0], status_fd[1] );
 
-	add_prefork_child( forker, child );
-
 	if( (pid=fork()) < 0 ) {
-		osrfLogError( OSRF_LOG_MARK,  "Forking Error" );
+		osrfLogError( OSRF_LOG_MARK, "Forking Error" );
+		prefork_child_free( forker, child );
 		return NULL;
 	}
 
+	// Add the new child to the head of the idle list
+	child->next = forker->idle_list;
+	forker->idle_list = child;
+
 	if( pid > 0 ) {  /* parent */
 
 		signal(SIGCHLD, sigchld_handler);
 		(forker->current_num_children)++;
 		child->pid = pid;
 
-		osrfLogDebug( OSRF_LOG_MARK,  "Parent launched %d", pid );
+		osrfLogDebug( OSRF_LOG_MARK, "Parent launched %d", pid );
 		/* *no* child pipe FD's can be closed or the parent will re-use fd's that
 			the children are currently using */
 		return child;
@@ -461,7 +536,7 @@
 	else { /* child */
 
 		osrfLogInternal( OSRF_LOG_MARK,
-				"I am  new child with read_data_fd = %d and write_status_fd = %d",
+				"I am new child with read_data_fd = %d and write_status_fd = %d",
 				child->read_data_fd, child->write_status_fd );
 
 		child->pid = getpid();
@@ -475,17 +550,30 @@
 			osrf_prefork_child_exit(child);
 		}
 
-		prefork_child_wait( child );
-		osrf_prefork_child_exit(child); /* just to be sure */
+		prefork_child_wait( child );      // Should exit without returning
+		osrf_prefork_child_exit( child ); // Just to be sure
+		return NULL;  // Unreachable, but it keeps the compiler happy
 	}
-	return NULL;
 }
 
+/**
+	@brief Terminate a child process.
+	@param child Pointer to the prefork_child representing the child process.
+
+	Called only by child processes.  Dynamically call an application-specific shutdown
+	function from a previously loaded shared library; then exit.
+*/
 static void osrf_prefork_child_exit(prefork_child* child) {
 	osrfAppRunExitCode();
 	exit(0);
 }
 
+/**
+	@brief Launch all the child processes, putting them in the idle list.
+	@param forker Pointer to the prefork_simple that will own the children.
+
+	Called only by the parent process (in order to become a parent).
+*/
 static void prefork_launch_children( prefork_simple* forker ) {
 	if(!forker) return;
 	int c = 0;
@@ -493,7 +581,6 @@
 		launch_child( forker );
 }
 
-
 /**
 	@brief Signal handler for SIGCHLD: note that a child process has terminated.
 	@param sig The value of the trapped signal; always SIGCHLD.
@@ -505,15 +592,15 @@
 	child_dead = 1;
 }
 
-
 /**
 	@brief Replenish the collection of child processes, after one has terminated.
 	@param forker Pointer to the prefork_simple that manages the child processes.
 
-	This function is called when we notice (via a signal handler) that a child
-	process has died.
+	The parent calls this function when it notices (via a signal handler) that
+	a child process has died.
 
-	Spawn a new child process to replace each of the terminated ones.
+	Wait on the dead children so that they won't be zombies.  Spawn new ones as needed
+	to maintain at least a minimum number.
 */
 void reap_children( prefork_simple* forker ) {
 
@@ -525,25 +612,38 @@
 	// Bury the children so that they won't be zombies.  WNOHANG means that waitpid() returns
 	// immediately if there are no waitable children, instead of waiting for more to die.
 	// Ignore the return code of the child.  We don't do an autopsy.
-	while( (child_pid = waitpid(-1, NULL, WNOHANG)) > 0)
+	while( (child_pid = waitpid(-1, NULL, WNOHANG)) > 0) {
+		--forker->current_num_children;
 		del_prefork_child( forker, child_pid );
+	}
 
-	/* Spawn more children as needed to maintain a minimum brood. */
+	// Spawn more children as needed.
 	while( forker->current_num_children < forker->min_children )
 		launch_child( forker );
 }
 
-static void prefork_run(prefork_simple* forker) {
+/**
+	@brief Read transport_messages and dispatch them to child processes for servicing.
+	@param forker Pointer to the prefork_simple that manages the child processes.
 
-	if( forker->first_child == NULL )
-		return;
+	This is the main loop of the parent process, and once entered, does not exit.
 
+	For each usable transport_message received: look for an idle child to service it.  If
+	no idle children are available, either spawn a new one or, if we've already spawned the
+	maximum number of children, wait for one to become available.  Once a child is available
+	by whatever means, write an XML version of the input message, to a pipe designated for
+	use by that child.
+*/
+static void prefork_run( prefork_simple* forker ) {
+
+	if( NULL == forker->idle_list )
+		return;   // No available children, and we haven't even started yet
+
 	transport_message* cur_msg = NULL;
 
-
 	while(1) {
 
-		if( forker->first_child == NULL ) {/* no more children */
+		if( forker->first_child == NULL && forker->idle_list == NULL ) {/* no more children */
 			osrfLogWarning( OSRF_LOG_MARK, "No more children..." );
 			return;
 		}
@@ -553,8 +653,17 @@
 		cur_msg = client_recv( forker->connection, -1 );
 
 		if( cur_msg == NULL )
-			continue;           // Error?  Interrupted by a signal?
+			continue;           // Error?  Interrupted by a signal?  Try again...
 
+		message_prepare_xml( cur_msg );
+		const char* msg_data = cur_msg->msg_xml;
+		if( ! msg_data || ! *msg_data ) {
+			osrfLogWarning( OSRF_LOG_MARK, "Received % message from %s, thread %",
+					(msg_data ? "empty" : "NULL"), cur_msg->sender, cur_msg->thread );
+			message_free( cur_msg );
+			continue;       // Message not usable; go on to the next one.
+		}
+
 		int honored = 0;     /* will be set to true when we service the request */
 		int no_recheck = 0;
 
@@ -565,41 +674,43 @@
 			no_recheck = 0;
 
 			osrfLogDebug( OSRF_LOG_MARK, "Server received inbound data" );
-			int k;
-			prefork_child* cur_child = forker->first_child;
 
-			/* Look for an available child */
-			for( k = 0; k < forker->current_num_children; k++ ) {
+			prefork_child* cur_child = NULL;
 
+			// Look for an available child in the idle list.  Since the idle list operates
+			// as a stack, the child we get is the one that was most recently active, or
+			// most recently spawned.  That means it's the one most likely still to be in
+			// physical memory, and the one least likely to have to be swapped in.
+			while( forker->idle_list ) {
+
+				osrfLogInfo( OSRF_LOG_MARK, "Looking for idle child" );
+				// Grab the prefork_child at the head of the idle list
+				cur_child = forker->idle_list;
+				forker->idle_list = cur_child->next;
+				cur_child->next = NULL;
+
 				osrfLogInternal( OSRF_LOG_MARK,
 						"Searching for available child. cur_child->pid = %d", cur_child->pid );
-				osrfLogInternal( OSRF_LOG_MARK, "Current num children %d and loop %d",
-						forker->current_num_children, k);
+				osrfLogInternal( OSRF_LOG_MARK, "Current num children %d",
+						forker->current_num_children );
 
-				if( cur_child->available ) {
-					osrfLogDebug( OSRF_LOG_MARK, "forker sending data to %d", cur_child->pid );
+				osrfLogDebug( OSRF_LOG_MARK, "forker sending data to %d", cur_child->pid );
+				osrfLogInternal( OSRF_LOG_MARK, "Writing to child fd %d",
+						cur_child->write_data_fd );
 
-					message_prepare_xml( cur_msg );
-					char* data = cur_msg->msg_xml;
-					if( ! data || strlen(data) < 1 )
-						break;
+				int written = write(cur_child->write_data_fd, msg_data, strlen(msg_data) + 1);
+				if( written < 0 ) {
+					// This child appears to be dead or unusable.  Discard it.
+					osrfLogWarning( OSRF_LOG_MARK, "Write returned error %d: %s",
+							errno, strerror( errno ) );
+					kill( cur_child->pid, SIGKILL );
+					del_prefork_child( forker, cur_child->pid );
+					continue;
+				}
 
-					cur_child->available = 0;
-					osrfLogInternal( OSRF_LOG_MARK, "Writing to child fd %d",
-							cur_child->write_data_fd );
-
-					int written = 0;
-					if( (written = write( cur_child->write_data_fd, data, strlen(data) + 1 )) < 0 ) {
-						osrfLogWarning( OSRF_LOG_MARK, "Write returned error %d", errno);
-						cur_child = cur_child->next;
-						continue;
-					}
-
-					forker->first_child = cur_child->next;
-					honored = 1;
-					break;
-				} else
-					cur_child = cur_child->next;
+				add_prefork_child( forker, cur_child );  // Add it to active list
+				honored = 1;
+				break;
 			}
 
 			/* if none available, add a new child if we can */
@@ -610,25 +721,28 @@
 					osrfLogDebug( OSRF_LOG_MARK,  "Launching new child with current_num = %d",
 							forker->current_num_children );
 
-					prefork_child* new_child = launch_child( forker );
-					if( new_child ) {
+					launch_child( forker );  // Put a new child into the idle list
+					if( forker->idle_list ) {
 
-						message_prepare_xml( cur_msg );
-						char* data = cur_msg->msg_xml;
+						// Take the new child from the idle list
+						prefork_child* new_child = forker->idle_list;
+						forker->idle_list = new_child->next;
+						new_child->next = NULL;
 
-						if( data ) {
-							int len = strlen(data);
+						osrfLogDebug( OSRF_LOG_MARK, "Writing to new child fd %d : pid %d",
+								new_child->write_data_fd, new_child->pid );
 
-							if( len > 0 ) {
-								new_child->available = 0;
-								osrfLogDebug( OSRF_LOG_MARK, "Writing to new child fd %d : pid %d",
-										new_child->write_data_fd, new_child->pid );
-
-								if( write( new_child->write_data_fd, data, len + 1 ) >= 0 ) {
-									forker->first_child = new_child->next;
-									honored = 1;
-								}
-							}
+						int written = write(
+								new_child->write_data_fd, msg_data, strlen(msg_data) + 1);
+						if( written < 0 ) {
+							// This child appears to be dead or unusable.  Discard it.
+							osrfLogWarning( OSRF_LOG_MARK, "Write returned error %d: %s",
+											errno, strerror( errno ) );
+							kill( cur_child->pid, SIGKILL );
+							del_prefork_child( forker, cur_child->pid );
+						} else {
+							add_prefork_child( forker, new_child );
+							honored = 1;
 						}
 					}
 
@@ -636,52 +750,67 @@
 			}
 
 			if( !honored ) {
-				osrfLogWarning( OSRF_LOG_MARK,  "No children available, waiting...");
-
-				check_children( forker, 1 );  /* non-poll version */
-				/* tell the loop not to call check_children again, since we're calling it now */
+				osrfLogWarning( OSRF_LOG_MARK, "No children available, waiting...");
+				check_children( forker, 1 );
+				// Tell the loop not to call check_children again, since we're calling it now
 				no_recheck = 1;
 			}
 
 			if( child_dead )
 				reap_children(forker);
 
-		} // honored?
+		} // end while( ! honored )
 
 		message_free( cur_msg );
 
 	} /* end top level listen loop */
-
 }
 
 
-/** XXX Add a flag which tells select() to wait forever on children
+/* XXX Add a flag which tells select() to wait forever on children
 	in the best case, this will be faster than calling usleep(x), and
 	in the worst case it won't be slower and will do less logging...
 */
+/**
+	@brief See if any children have become available.
+	@param forker Pointer to the prefork_simple that owns the children.
+	@param forever Boolean: true if we should wait indefinitely.
+	@return 
+
+	Call select() for all the children in the active list.  Read each active file
+	descriptor and move the corresponding child to the idle list.
+
+	If @a forever is true, wait indefinitely for input.  Otherwise return immediately if
+	there are no active file descriptors.
+*/
 static void check_children( prefork_simple* forker, int forever ) {
 
-	//check_begin:
+	if( child_dead )
+		reap_children( forker );
 
+	if( NULL == forker->first_child ) {
+		// If forever is true, then we're here because we've run out of idle
+		// processes, so there should be some active ones around.
+		// If forever is false, then the children may all be idle, and that's okay.
+		if( forever )
+ 			osrfLogError( OSRF_LOG_MARK, "No active child processes to check" );
+		return;
+	}
+
 	int select_ret;
 	fd_set read_set;
 	FD_ZERO(&read_set);
 	int max_fd = 0;
 	int n;
 
-	if( child_dead )
-		reap_children(forker);
-
+	// Prepare to select() on pipes from all the active children
 	prefork_child* cur_child = forker->first_child;
-
-	int i;
-	for( i = 0; i!= forker->current_num_children; i++ ) {
-
+	do {
 		if( cur_child->read_status_fd > max_fd )
 			max_fd = cur_child->read_status_fd;
 		FD_SET( cur_child->read_status_fd, &read_set );
 		cur_child = cur_child->next;
-	}
+	} while( cur_child != forker->first_child );
 
 	FD_CLR(0,&read_set); /* just to be sure */
 
@@ -689,8 +818,9 @@
 		osrfLogWarning(OSRF_LOG_MARK,
 				"We have no children available - waiting for one to show up...");
 
-		if( (select_ret=select( max_fd + 1 , &read_set, NULL, NULL, NULL)) == -1 ) {
-			osrfLogWarning( OSRF_LOG_MARK,  "Select returned error %d on check_children", errno );
+		if( (select_ret=select( max_fd + 1, &read_set, NULL, NULL, NULL)) == -1 ) {
+			osrfLogWarning( OSRF_LOG_MARK, "Select returned error %d on check_children: %s",
+					errno, strerror( errno ) );
 		}
 		osrfLogInfo(OSRF_LOG_MARK,
 				"select() completed after waiting on children to become available");
@@ -701,22 +831,23 @@
 		tv.tv_sec   = 0;
 		tv.tv_usec  = 0;
 
-		if( (select_ret=select( max_fd + 1 , &read_set, NULL, NULL, &tv)) == -1 ) {
-			osrfLogWarning( OSRF_LOG_MARK,  "Select returned error %d on check_children", errno );
+		if( (select_ret=select( max_fd + 1, &read_set, NULL, NULL, &tv)) == -1 ) {
+			osrfLogWarning( OSRF_LOG_MARK, "Select returned error %d on check_children: %s",
+					errno, strerror( errno ) );
 		}
 	}
 
 	if( select_ret == 0 )
 		return;
 
-	/* see if one of a child has told us it's done */
+	// Check each child in the active list.
+	// If it has responded, move it to the idle list.
 	cur_child = forker->first_child;
-	int j;
+	prefork_child* next_child = NULL;
 	int num_handled = 0;
-	for( j = 0; j!= forker->current_num_children && num_handled < select_ret ; j++ ) {
-
+	do {
+		next_child = cur_child->next;
 		if( FD_ISSET( cur_child->read_status_fd, &read_set ) ) {
-			//printf( "Server received status from a child %d\n", cur_child->pid );
 			osrfLogDebug( OSRF_LOG_MARK,
 					"Server received status from a child %d", cur_child->pid );
 
@@ -726,20 +857,47 @@
 			char buf[64];
 			if( (n=read(cur_child->read_status_fd, buf, sizeof(buf) - 1)) < 0 ) {
 				osrfLogWarning( OSRF_LOG_MARK,
-						"Read error after select in child status read with errno %d", errno);
+						"Read error after select in child status read with errno %d: %s",
+						errno, strerror( errno ) );
 			}
 			else {
 				buf[n] = '\0';
 				osrfLogDebug( OSRF_LOG_MARK,  "Read %d bytes from status buffer: %s", n, buf );
 			}
-			cur_child->available = 1;
+
+			// Remove the child from the active list
+			if( forker->first_child == cur_child ) {
+				if( cur_child->next == cur_child )
+					forker->first_child = NULL;   // only child in the active list
+				else
+					forker->first_child = cur_child->next;
+			}
+			cur_child->next->prev = cur_child->prev;
+			cur_child->prev->next = cur_child->next;
+
+			// Add it to the idle list
+			cur_child->prev = NULL;
+			cur_child->next = forker->idle_list;
+			forker->idle_list = cur_child;
 		}
-		cur_child = cur_child->next;
-	}
-
+		cur_child = next_child;
+	} while( forker->first_child && forker->first_child != next_child );
 }
 
+/**
+	@brief Service up a set maximum number of requests; then shut down.
+	@param child Pointer to the prefork_child representing the child process.
 
+	Called only by child process.
+
+	Enter a loop, for up to max_requests iterations.  On each iteration:
+	- Wait indefinitely for a request from the parent.
+	- Service the request.
+	- Increment a counter.  If the limit hasn't been reached, notify the parent that you
+	are available for another request.
+
+	After exiting the loop, shut down and terminate the process.
+*/
 static void prefork_child_wait( prefork_child* child ) {
 
 	int i,n;
@@ -769,19 +927,36 @@
 			break;
 		}
 
+		int terminate_now = 0;     // Boolean
+
 		if( n < 0 ) {
 			osrfLogWarning( OSRF_LOG_MARK,
 					"Prefork child read returned error with errno %d", errno );
 			break;
 
 		} else if( gotdata ) {
-			osrfLogDebug(OSRF_LOG_MARK, "Prefork child got a request.. processing..");
-			prefork_child_process_request(child, gbuf->buf);
+			osrfLogDebug( OSRF_LOG_MARK, "Prefork child got a request.. processing.." );
+			terminate_now = prefork_child_process_request( child, gbuf->buf );
 			buffer_reset( gbuf );
 		}
 
-		if( i < child->max_requests - 1 )
-			write( child->write_status_fd, "available" /*less than 64 bytes*/, 9 );
+		if( terminate_now ) {
+			osrfLogWarning( OSRF_LOG_MARK, "Prefork child terminating abruptly" );
+			break;
+		}
+
+		if( i < child->max_requests - 1 ) {
+			size_t msg_len = 9;
+			ssize_t len = write(
+				child->write_status_fd, "available" /*less than 64 bytes*/, msg_len );
+			if( len != msg_len ) {
+				osrfLogError( OSRF_LOG_MARK, 
+					"Drone terminating: unable to notify listener of availability: %s",
+					strerror( errno ));
+				buffer_free(gbuf);
+				osrf_prefork_child_exit(child);
+			}
+		}
 	}
 
 	buffer_free(gbuf);
@@ -789,11 +964,11 @@
 	osrfLogDebug( OSRF_LOG_MARK, "Child with max-requests=%d, num-served=%d exiting...[%ld]",
 			child->max_requests, i, (long) getpid() );
 
-	osrf_prefork_child_exit(child); /* just to be sure */
+	osrf_prefork_child_exit(child);
 }
 
 /**
-	@brief Add a prefork_child to the end of the list.
+	@brief Add a prefork_child to the end of the active list.
 	@param forker Pointer to the prefork_simple that owns the list.
 	@param child Pointer to the prefork_child to be added.
 */
@@ -816,43 +991,57 @@
 	}
 }
 
-/**
-	@brief Remove a prefork_child from the child list.
-	@param forker Pointer to the prefork_simple that owns the child.
-	@param pid Process ID of the child to be removed.
-
-	Besides removing the node from the list, we also close its file descriptors.
-*/
 static void del_prefork_child( prefork_simple* forker, pid_t pid ) {
 
-	if( forker->first_child == NULL )
-		return;  // Empty list; bail out.
-
 	osrfLogDebug( OSRF_LOG_MARK, "Deleting Child: %d", pid );
 
-	// Find the node in question
-	prefork_child* cur_child = forker->first_child; /* current pointer */
-	while( cur_child->pid != pid && cur_child->next != forker->first_child )
-		cur_child = cur_child->next;
+	prefork_child* cur_child = NULL;
+	
+	// Look first in the active list
+	if( forker->first_child ) {
+		cur_child = forker->first_child; /* current pointer */
+		while( cur_child->pid != pid && cur_child->next != forker->first_child )
+			cur_child = cur_child->next;
 
-	if( cur_child->pid == pid ) {
-		// We found the right node.  Remove it from the list.
-		if( cur_child->next == cur_child )
-			forker->first_child = NULL;    // only child in the list
-		else {
-			if( forker->first_child == cur_child )
-				forker->first_child = cur_child->next;  // Reseat forker->first_child
-			
-			// Stitch the nodes on either side together
-			cur_child->prev->next = cur_child->next;
-			cur_child->next->prev = cur_child->prev;
+		if( cur_child->pid == pid ) {
+			// We found the right node.  Remove it from the list.
+			if( cur_child->next == cur_child )
+				forker->first_child = NULL;    // only child in the list
+			else {
+				if( forker->first_child == cur_child )
+					forker->first_child = cur_child->next;  // Reseat forker->first_child
+
+				// Stitch the adjacent nodes together
+				cur_child->prev->next = cur_child->next;
+				cur_child->next->prev = cur_child->prev;
+			}
+		} else
+			cur_child = NULL;  // Didn't find it in the active list
+	}
+
+	if( ! cur_child ) {
+		// Maybe it's in the idle list.  This can happen if, for example,
+		// a child is killed by a signal while it's between requests.
+
+		prefork_child* prev = NULL;
+		cur_child = forker->idle_list;
+		while( cur_child && cur_child->pid != pid ) {
+			prev = cur_child;
+			cur_child = cur_child->next;
 		}
-		--forker->current_num_children;
-		
-		//Destroy the node
+
+		if( cur_child ) {
+			// Detach from the list
+			if( prev )
+				prev->next = cur_child->next;
+			else
+				forker->idle_list = cur_child->next;
+		} // else we can't find it
+	}
+
+	// If we found the node, destroy it.
+	if( cur_child )
 		prefork_child_free( forker, cur_child );
-		
-	} // else we didn't find a matching node; bail out
 }
 
 /**
@@ -878,14 +1067,13 @@
 		child = forker->free_list;
 		forker->free_list = child->next;
 	} else
-		child = (prefork_child*) safe_malloc(sizeof(prefork_child));
+		child = safe_malloc(sizeof(prefork_child));
 
 	child->pid              = 0;
 	child->read_data_fd     = read_data_fd;
 	child->write_data_fd    = write_data_fd;
 	child->read_status_fd   = read_status_fd;
 	child->write_status_fd  = write_status_fd;
-	child->available        = 1;
 	child->max_requests     = forker->max_requests;
 	child->appname          = forker->appname;  // We don't make a separate copy
 	child->keepalive        = forker->keepalive;
@@ -895,7 +1083,6 @@
 	return child;
 }
 
-
 /**
 	@brief Terminate all child processes and clear out a prefork_simple.
 	@param prefork Pointer to the prefork_simple to be cleared out.
@@ -904,33 +1091,47 @@
 */
 static void prefork_clear( prefork_simple* prefork ) {
 
-	// Kill all the child processes with a single call, not by killing each one separately.
-	// Implication: we can't have more than one prefork_simple outstanding, because
-	// destroying one would kill the children of all.
-	while( prefork->first_child != NULL ) {
-		osrfLogInfo( OSRF_LOG_MARK, "Killing child processes ..." );
-		kill( 0, SIGKILL );
+	// Kill all the active children, and move their prefork_child nodes to the free list.
+	while( prefork->first_child ) {
+		kill( prefork->first_child->pid, SIGKILL );
+		del_prefork_child( prefork, prefork->first_child->pid );
 	}
 
-	// Bury the children so that they won't be zombies.  WNOHANG means that waitpid() returns
-	// immediately if there are no waitable children, instead of waiting for more to die.
-	// Ignore the return code of the child.  We don't do an autopsy.
-	pid_t child_pid;
-	while( (child_pid = waitpid(-1, NULL, WNOHANG)) > 0)
-		del_prefork_child( prefork, child_pid );
+	// Kill all the idle prefork children, close their file
+	// descriptors, and move them to the free list.
+	prefork_child* child = prefork->idle_list;
+	prefork->idle_list = NULL;
+	while( child ) {
+		prefork_child* temp = child->next;
+		kill( child->pid, SIGKILL );
+		prefork_child_free( prefork, child );
+		child = temp;
+	}
+	//prefork->current_num_children = 0;
 
-    // Close the Jabber connection
-	client_free(prefork->connection);
-	
 	// Physically free the free list of prefork_children.
-	prefork_child* child = prefork->first_child;
+	child = prefork->free_list;
+	prefork->free_list = NULL;
 	while( child ) {
 		prefork_child* temp = child->next;
 		free( child );
 		child = temp;
 	}
 
+	// Close the Jabber connection
+	client_free( prefork->connection );
+	prefork->connection = NULL;
+
+	// After giving the child processes a second to terminate, wait on them so that they
+	// don't become zombies.  We don't wait indefinitely, so it's possible that some
+	// children will survive a bit longer.
+	sleep( 1 );
+	while( (waitpid(-1, NULL, WNOHANG)) > 0) {
+		--prefork->current_num_children;
+	}
+
 	free(prefork->appname);
+	prefork->appname = NULL;
 }
 
 /**

Modified: branches/rel_1_4/src/libopensrf/osrf_system.c
===================================================================
--- branches/rel_1_4/src/libopensrf/osrf_system.c	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/src/libopensrf/osrf_system.c	2010-07-01 02:05:08 UTC (rev 1970)
@@ -51,6 +51,9 @@
 /** Boolean: set to true when we finish shutting down. */
 static int shutdownComplete = 0;
 
+/** Name of file to which to write the process ID of the child process */
+char* pidfile_name = NULL;
+
 static void add_child( pid_t pid, const char* app, const char* libfile );
 static void delete_child( ChildNode* node );
 static void delete_all_children( void );
@@ -122,6 +125,27 @@
 }
 
 /**
+	@brief Save a copy of a file name to be used for writing a process ID.
+	@param name Designated file name, or NULL.
+
+	Save a file name for later use in saving a process ID.  If @a name is NULL, leave
+	the file name NULL.
+
+	When the parent process spawns a child, the child becomes a daemon.  The parent writes the
+	child's process ID to the PID file, if one has been designated, so that some other process
+	can retrieve the PID later and kill the daemon.
+*/
+void osrfSystemSetPidFile( const char* name ) {
+	if( pidfile_name )
+		free( pidfile_name );
+
+	if( name )
+		pidfile_name = strdup( name );
+	else
+		pidfile_name = NULL;
+}
+
+/**
 	@brief Discard the global transport_client, but without disconnecting from Jabber.
 
 	To be called by a child process in order to disregard the parent's connection without
@@ -241,6 +265,7 @@
 		jsonObjectFree(apps);
 
 		const char* appname = NULL;
+		int first_launch = 1;             // Boolean
 		i = 0;
 		while( (appname = osrfStringArrayGetString(arr, i++)) ) {
 
@@ -266,9 +291,35 @@
 					osrfLogInfo( OSRF_LOG_MARK, "Running application child %s: process id %ld",
 								 appname, (long) pid );
 
+					if( first_launch ) {
+						if( pidfile_name ) {
+							// Write our own PID to a PID file so that somebody can use it to
+							// send us a signal later.  If we don't find any C apps to launch,
+							// then we will quietly exit without writing a PID file, and without
+							// waiting to be killed by a signal.
+
+							FILE* pidfile = fopen( pidfile_name, "w" );
+							if( !pidfile ) {
+								osrfLogError( OSRF_LOG_MARK, "Unable to open PID file \"%s\": %s",
+									pidfile_name, strerror( errno ) );
+								free( pidfile_name );
+								pidfile_name = NULL;
+								return -1;
+							} else {
+								fprintf( pidfile, "%ld\n", (long) getpid() );
+								fclose( pidfile );
+							}
+						}
+						first_launch = 0;
+					}
+
 				} else {         // if child, run the application
 
 					osrfLogInfo( OSRF_LOG_MARK, " * Running application %s\n", appname);
+					if( pidfile_name ) {
+						free( pidfile_name );    // tidy up some debris from the parent
+						pidfile_name = NULL;
+					}
 					if( osrfAppRegisterApplication( appname, libfile ) == 0 )
 						osrf_prefork_run(appname);
 
@@ -299,6 +350,10 @@
 				osrfLogError(OSRF_LOG_MARK, "Exiting top-level system loop with error: %s",
 						strerror( errno ) );
 
+			// Since we're not being killed by a signal as usual, delete the PID file
+			// so that no one will try to kill us when we're already dead.
+			if( pidfile_name )
+				remove( pidfile_name );
 			break;
 		} else {
 			report_child_status( pid, status );
@@ -309,6 +364,8 @@
 	osrfConfigCleanup();
 	osrf_system_disconnect_client();
 	osrf_settings_free_host_config(NULL);
+	free( pidfile_name );
+	pidfile_name = NULL;
 	return 0;
 }
 
@@ -588,8 +645,6 @@
 	snprintf(buf, len - 1, "%s_%s_%s_%ld", resource, host, tbuf, (long) getpid() );
 
 	if(client_connect( client, username, password, buf, 10, AUTH_DIGEST )) {
-		/* child nodes will leak the parents client... but we can't free
-			it without disconnecting the parents client :( */
 		osrfGlobalTransportClient = client;
 	}
 

Modified: branches/rel_1_4/src/libopensrf/transport_session.c
===================================================================
--- branches/rel_1_4/src/libopensrf/transport_session.c	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/src/libopensrf/transport_session.c	2010-07-01 02:05:08 UTC (rev 1970)
@@ -64,38 +64,38 @@
 // Tells the SAX parser which functions will be used as event callbacks
 // ---------------------------------------------------------------------------------
 static xmlSAXHandler SAXHandlerStruct = {
-   NULL,							/* internalSubset */
-   NULL,							/* isStandalone */
-   NULL,							/* hasInternalSubset */
-   NULL,							/* hasExternalSubset */
-   NULL,							/* resolveEntity */
-   NULL,							/* getEntity */
-   NULL,							/* entityDecl */
-   NULL,							/* notationDecl */
-   NULL,							/* attributeDecl */
-   NULL,							/* elementDecl */
-   NULL,							/* unparsedEntityDecl */
-   NULL,							/* setDocumentLocator */
-   NULL,							/* startDocument */
-   NULL,							/* endDocument */
-   startElementHandler,		/* startElement */
-   endElementHandler,		/* endElement */
-   NULL,							/* reference */
-   characterHandler,			/* characters */
-   NULL,							/* ignorableWhitespace */
-   NULL,							/* processingInstruction */
-   NULL,							/* comment */
-   parseWarningHandler,		/* xmlParserWarning */
-   parseErrorHandler,		/* xmlParserError */
-   NULL,							/* xmlParserFatalError : unused */
-   NULL,							/* getParameterEntity */
-   NULL,							/* cdataBlock; */
-   NULL,							/* externalSubset; */
-   1,
-   NULL,
-   NULL,							/* startElementNs */
-   NULL,							/* endElementNs */
-   NULL							/* xmlStructuredErrorFunc */
+	NULL,                  /* internalSubset */
+	NULL,                  /* isStandalone */
+	NULL,                  /* hasInternalSubset */
+	NULL,                  /* hasExternalSubset */
+	NULL,                  /* resolveEntity */
+	NULL,                  /* getEntity */
+	NULL,                  /* entityDecl */
+	NULL,                  /* notationDecl */
+	NULL,                  /* attributeDecl */
+	NULL,                  /* elementDecl */
+	NULL,                  /* unparsedEntityDecl */
+	NULL,                  /* setDocumentLocator */
+	NULL,                  /* startDocument */
+	NULL,                  /* endDocument */
+	startElementHandler,   /* startElement */
+	endElementHandler,     /* endElement */
+	NULL,                  /* reference */
+	characterHandler,      /* characters */
+	NULL,                  /* ignorableWhitespace */
+	NULL,                  /* processingInstruction */
+	NULL,                  /* comment */
+	parseWarningHandler,   /* xmlParserWarning */
+	parseErrorHandler,     /* xmlParserError */
+	NULL,                  /* xmlParserFatalError : unused */
+	NULL,                  /* getParameterEntity */
+	NULL,                  /* cdataBlock; */
+	NULL,                  /* externalSubset; */
+	1,
+	NULL,
+	NULL,                  /* startElementNs */
+	NULL,                  /* endElementNs */
+	NULL                   /* xmlStructuredErrorFunc */
 };
 
 // ---------------------------------------------------------------------------------
@@ -144,23 +144,23 @@
 	session->component = component;
 
 	/* initialize the data buffers */
-	session->body_buffer		= buffer_init( JABBER_BODY_BUFSIZE );
-	session->subject_buffer		= buffer_init( JABBER_SUBJECT_BUFSIZE );
-	session->thread_buffer		= buffer_init( JABBER_THREAD_BUFSIZE );
-	session->from_buffer		= buffer_init( JABBER_JID_BUFSIZE );
-	session->status_buffer		= buffer_init( JABBER_STATUS_BUFSIZE );
-	session->recipient_buffer	= buffer_init( JABBER_JID_BUFSIZE );
+	session->body_buffer        = buffer_init( JABBER_BODY_BUFSIZE );
+	session->subject_buffer     = buffer_init( JABBER_SUBJECT_BUFSIZE );
+	session->thread_buffer      = buffer_init( JABBER_THREAD_BUFSIZE );
+	session->from_buffer        = buffer_init( JABBER_JID_BUFSIZE );
+	session->status_buffer      = buffer_init( JABBER_STATUS_BUFSIZE );
+	session->recipient_buffer   = buffer_init( JABBER_JID_BUFSIZE );
 	session->message_error_type = buffer_init( JABBER_JID_BUFSIZE );
-	session->session_id			= buffer_init( 64 );
+	session->session_id         = buffer_init( 64 );
 
 	session->message_error_code = 0;
 
 	/* for OpenSRF extensions */
-	session->router_to_buffer	= buffer_init( JABBER_JID_BUFSIZE );
-	session->router_from_buffer	= buffer_init( JABBER_JID_BUFSIZE );
-	session->osrf_xid_buffer	= buffer_init( JABBER_JID_BUFSIZE );
-	session->router_class_buffer	= buffer_init( JABBER_JID_BUFSIZE );
-	session->router_command_buffer	= buffer_init( JABBER_JID_BUFSIZE );
+	session->router_to_buffer   = buffer_init( JABBER_JID_BUFSIZE );
+	session->router_from_buffer = buffer_init( JABBER_JID_BUFSIZE );
+	session->osrf_xid_buffer    = buffer_init( JABBER_JID_BUFSIZE );
+	session->router_class_buffer    = buffer_init( JABBER_JID_BUFSIZE );
+	session->router_command_buffer  = buffer_init( JABBER_JID_BUFSIZE );
 
 	session->router_broadcast   = 0;
 
@@ -187,7 +187,7 @@
 	session->sock_mgr->data_received = &grab_incoming;
 	session->sock_mgr->on_socket_closed = NULL;
 	session->sock_mgr->socket = NULL;
-	session->sock_mgr->blob	= session;
+	session->sock_mgr->blob = session;
 
 	session->port = port;
 	session->server = strdup(server);
@@ -227,7 +227,7 @@
 	that would disconnect the parent).
 
 	The only error condition is a NULL pointer argument.
- */
+*/
 int session_discard( transport_session* session ) {
 	if( ! session )
 		return 0;
@@ -372,7 +372,7 @@
 
 	// Open a client socket connecting to the Jabber server
 	if(session->port > 0) {   // use TCP
-		session->sock_id = socket_open_tcp_client( 
+		session->sock_id = socket_open_tcp_client(
 				session->sock_mgr, session->port, session->server );
 		if( session->sock_id <= 0 ) {
 			session->sock_id = 0;
@@ -694,7 +694,7 @@
 	@param attr_name Name of the attribute you're looking for.
 	@return The value of the attribute if found, or NULL if not.
 
-	In the array to which @a atts points, the zeroth entry is an attribute name, and the 
+	In the array to which @a atts points, the zeroth entry is an attribute name, and the
 	one after that is its value.  Subsequent entries alternate between names and values.
 	The last entry is NULL to terminate the list.
 */
@@ -882,10 +882,12 @@
 	}
 
 	if( machine->in_error ) {
-		/* for now... */
-		osrfLogWarning( OSRF_LOG_MARK,  "ERROR XML fragment: %s\n", ch );
+		char msg[ len + 1 ];
+		strncpy( msg, p, len );
+		msg[ len ] = '\0';
+		osrfLogWarning( OSRF_LOG_MARK,
+			"Text of error message received from Jabber: %s", msg );
 	}
-
 }
 
 /**

Modified: branches/rel_1_4/src/libopensrf/utils.c
===================================================================
--- branches/rel_1_4/src/libopensrf/utils.c	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/src/libopensrf/utils.c	2010-07-01 02:05:08 UTC (rev 1970)
@@ -647,9 +647,8 @@
 	@brief Become a proper daemon.
 	@return 0 if successful, or -1 if not.
 
-	Call fork().  The parent exits.  The child moves to the root
-	directory, detaches from the terminal, and redirects the
-	standard streams (stdin, stdout, stderr) to /dev/null.
+	Call fork().  The parent exits.  The child moves to the root directory, detaches from
+	the terminal, and redirects the standard streams (stdin, stdout, stderr) to /dev/null.
 */
 int daemonize( void ) {
 	pid_t f = fork();

Modified: branches/rel_1_4/src/python/osrf/gateway.py
===================================================================
--- branches/rel_1_4/src/python/osrf/gateway.py	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/src/python/osrf/gateway.py	2010-07-01 02:05:08 UTC (rev 1970)
@@ -69,14 +69,15 @@
         obj = to_object(data)
 
         if obj['status'] != 200:
-            sys.stderr.write('JSON gateway returned status %d:\n%s\n' % (obj['status'], s))
+            sys.stderr.write('JSON gateway returned status %d:\n' % (obj['status']))
             return None
 
         # the gateway wraps responses in an array to handle streaming data
         # if there is only one item in the array, it (probably) wasn't a streaming request
         p = obj['payload']
         if len(p) > 1: return p
-        return p[0]
+        if len(p): return p[0]
+        return None
 
     def encodeParam(self, param):
         return osrf.json.to_json(param)

Modified: branches/rel_1_4/src/router/osrf_router.c
===================================================================
--- branches/rel_1_4/src/router/osrf_router.c	2010-06-24 16:56:45 UTC (rev 1969)
+++ branches/rel_1_4/src/router/osrf_router.c	2010-07-01 02:05:08 UTC (rev 1970)
@@ -794,7 +794,7 @@
 
 	// Translate the JSON into a list of osrfMessages
 	router->message_list = osrfMessageDeserialize( msg->body, router->message_list );
-	osrfMessage* omsg = NULL;
+	const osrfMessage* omsg = NULL;
 
 	// Process each osrfMessage
 	int i;
@@ -816,10 +816,9 @@
 				default:
 					break;
 			}
-
-			osrfMessageFree( omsg );
 		}
 	}
+	osrfListClear( router->message_list );
 
 	return;
 }



More information about the opensrf-commits mailing list