diff --git a/Apache/SOGo-debian.conf b/Apache/SOGo-debian.conf
index eb01a886f..02e30d996 100644
--- a/Apache/SOGo-debian.conf
+++ b/Apache/SOGo-debian.conf
@@ -1,9 +1,9 @@
-Alias /sogo.woa/WebServerResources/ \
- /usr/lib/GNUstep/SOGo/WebServerResources/
Alias /SOGo.woa/WebServerResources/ \
- /usr/lib/GNUstep/SOGo/WebServerResources/
-Alias /SOGO.woa/WebServerResources/ \
- /usr/lib/GNUstep/SOGo/WebServerResources/
+ /usr/lib/GNUstep/SOGo/WebServerResources/
+Alias /SOGo/WebServerResources/ \
+ /usr/lib/GNUstep/SOGo/WebServerResources/
+AliasMatch /SOGo/so/ControlPanel/Products/(.*)/Resources/(.*) \
+ /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2
SetHandler default-handler
@@ -25,13 +25,24 @@ Alias /SOGO.woa/WebServerResources/ \
SetHandler default-handler
-AliasMatch /SOGo/so/ControlPanel/Products/(.*)/Resources/(.*) \
- /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2
+## Uncomment the following to enable proxy-side authentication, you will then
+## need to set the "SOGoTrustProxyAuthentication" SOGo user default to YES and
+## adjust the "x-webobjects-remote-user" proxy header in the "Proxy" section
+## below.
+#
+# AuthType XXX
+# Require valid-user
+# SetEnv proxy-nokeepalive 1
+# Allow from all
+#
-
- RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
- RequestHeader set "x-webobjects-remote-host" "127.0.0.1"
+ProxyRequests Off
+SetEnv proxy-nokeepalive 1
+ProxyPreserveHost On
+ProxyPassInterpolateEnv On
+ProxyPass /SOGo http://127.0.0.1:20000/SOGo interpolate
+
## adjust the following to your configuration
RequestHeader set "x-webobjects-server-port" "443"
RequestHeader set "x-webobjects-server-name" "yourhostname"
@@ -41,18 +52,9 @@ AliasMatch /SOGo/so/ControlPanel/Products/(.*)/Resources/(.*) \
## adjust the following line:
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e"
- BalancerMember http://127.0.0.1:20000 retry=1 max=1 timeout=120
-# If you enable those, don't forget the enable the spawning of multiple SOGo
-# processes. With Redhat-based distributions, this is done by setting the
-# "PREFORK" variable in /etc/sysconfig/sogo to the amount of processes as
-# value.
-# BalancerMember http://127.0.0.1:20001 retry=1 max=1 timeout=120
-# BalancerMember http://127.0.0.1:20002 retry=1 max=1 timeout=120
- ProxySet lbmethod=byrequests maxattempts=1
+ RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
+ RequestHeader set "x-webobjects-remote-host" "127.0.0.1"
+
Order allow,deny
Allow from all
-
-SetEnv proxy-nokeepalive 1
-ProxyRequests Off
-ProxyPass /SOGo balancer://sogocluster/SOGo
diff --git a/Apache/SOGo.conf b/Apache/SOGo.conf
index cf6ed7043..2fbc166a1 100644
--- a/Apache/SOGo.conf
+++ b/Apache/SOGo.conf
@@ -7,11 +7,11 @@ AliasMatch /SOGo/so/ControlPanel/Products/(.*)/Resources/(.*) \
## For Debian-based distributions, use the following instead of the above:
# Alias /SOGo.woa/WebServerResources/ \
-# /usr/lib/GNUstep/SOGo/WebServerResources/
+# /usr/lib/GNUstep/SOGo/WebServerResources/
# Alias /SOGo/WebServerResources/ \
-# /usr/lib/GNUstep/SOGo/WebServerResources/
+# /usr/lib/GNUstep/SOGo/WebServerResources/
# AliasMatch /SOGo/so/ControlPanel/Products/(.*)/Resources/(.*) \
-# /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2
+# /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2
SetHandler default-handler
@@ -47,12 +47,10 @@ AliasMatch /SOGo/so/ControlPanel/Products/(.*)/Resources/(.*) \
ProxyRequests Off
SetEnv proxy-nokeepalive 1
ProxyPreserveHost On
-ProxyPass /SOGo balancer://sogocluster/SOGo
-
-
- RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
- RequestHeader set "x-webobjects-remote-host" "127.0.0.1"
+ProxyPassInterpolateEnv On
+ProxyPass /SOGo http://127.0.0.1:20000/SOGo interpolate
+
## adjust the following to your configuration
RequestHeader set "x-webobjects-server-port" "443"
RequestHeader set "x-webobjects-server-name" "yourhostname"
@@ -62,15 +60,9 @@ ProxyPass /SOGo balancer://sogocluster/SOGo
## adjust the following line:
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e"
- BalancerMember http://127.0.0.1:20000 retry=1 max=1 timeout=120
-## If you enable those, don't forget the enable the spawning of multiple SOGo
-## processes. With Redhat-based distributions, this is done by setting the
-## "PREFORK" variable in /etc/sysconfig/sogo to the amount of processes.
-## In Debian-based distributions, you should do the same in the
-## /etc/default/sogo file instead.
-# BalancerMember http://127.0.0.1:20001 retry=1 max=1 timeout=120
-# BalancerMember http://127.0.0.1:20002 retry=1 max=1 timeout=120
- ProxySet lbmethod=byrequests maxattempts=1
+ RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
+ RequestHeader set "x-webobjects-remote-host" "127.0.0.1"
+
Order allow,deny
Allow from all
diff --git a/SOPE/sope-patchset-r1660.diff b/SOPE/sope-patchset-r1660.diff
index 629a5b5b2..b629bc431 100644
--- a/SOPE/sope-patchset-r1660.diff
+++ b/SOPE/sope-patchset-r1660.diff
@@ -1,7 +1,7 @@
Index: sope-ldap/NGLdap/NGLdapEntry.m
===================================================================
---- sope-ldap/NGLdap/NGLdapEntry.m (revision 1660)
-+++ sope-ldap/NGLdap/NGLdapEntry.m (working copy)
+--- sope-ldap/NGLdap/NGLdapEntry.m (révision 1660)
++++ sope-ldap/NGLdap/NGLdapEntry.m (copie de travail)
@@ -105,14 +105,16 @@
- (NGLdapAttribute *)attributeWithName:(NSString *)_name {
NSEnumerator *e;
@@ -23,8 +23,8 @@ Index: sope-ldap/NGLdap/NGLdapEntry.m
return nil;
Index: sope-ldap/NGLdap/ChangeLog
===================================================================
---- sope-ldap/NGLdap/ChangeLog (revision 1660)
-+++ sope-ldap/NGLdap/ChangeLog (working copy)
+--- sope-ldap/NGLdap/ChangeLog (révision 1660)
++++ sope-ldap/NGLdap/ChangeLog (copie de travail)
@@ -1,3 +1,8 @@
+2009-08-13 Wolfgang Sourdeau
+
@@ -36,8 +36,8 @@ Index: sope-ldap/NGLdap/ChangeLog
* NGLdapConnection.m (useSSL,startTLS): new method enabling
Index: sope-gdl1/PostgreSQL/PostgreSQL72Channel.m
===================================================================
---- sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (revision 1660)
-+++ sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (working copy)
+--- sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (révision 1660)
++++ sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (copie de travail)
@@ -713,6 +713,39 @@
return ms;
}
@@ -80,8 +80,8 @@ Index: sope-gdl1/PostgreSQL/PostgreSQL72Channel.m
@implementation PostgreSQL72Channel(PrimaryKeyGeneration)
Index: sope-gdl1/MySQL/MySQL4Channel.m
===================================================================
---- sope-gdl1/MySQL/MySQL4Channel.m (revision 1660)
-+++ sope-gdl1/MySQL/MySQL4Channel.m (working copy)
+--- sope-gdl1/MySQL/MySQL4Channel.m (révision 1660)
++++ sope-gdl1/MySQL/MySQL4Channel.m (copie de travail)
@@ -755,6 +755,39 @@
return pkey;
}
@@ -124,8 +124,8 @@ Index: sope-gdl1/MySQL/MySQL4Channel.m
void __link_MySQL4Channel() {
Index: sope-gdl1/Oracle8/OracleAdaptorChannel.m
===================================================================
---- sope-gdl1/Oracle8/OracleAdaptorChannel.m (revision 1660)
-+++ sope-gdl1/Oracle8/OracleAdaptorChannel.m (working copy)
+--- sope-gdl1/Oracle8/OracleAdaptorChannel.m (révision 1660)
++++ sope-gdl1/Oracle8/OracleAdaptorChannel.m (copie de travail)
@@ -1,7 +1,7 @@
/*
** OracleAdaptorChannel.m
@@ -389,8 +389,8 @@ Index: sope-gdl1/Oracle8/OracleAdaptorChannel.m
@" c_lastmodified INTEGER NOT NULL,\n"
Index: sope-gdl1/Oracle8/OracleAdaptorChannelController.m
===================================================================
---- sope-gdl1/Oracle8/OracleAdaptorChannelController.m (revision 1660)
-+++ sope-gdl1/Oracle8/OracleAdaptorChannelController.m (working copy)
+--- sope-gdl1/Oracle8/OracleAdaptorChannelController.m (révision 1660)
++++ sope-gdl1/Oracle8/OracleAdaptorChannelController.m (copie de travail)
@@ -31,6 +31,8 @@
#import
#import
@@ -437,8 +437,8 @@ Index: sope-gdl1/Oracle8/OracleAdaptorChannelController.m
Index: sope-mime/NGImap4/NGImap4Functions.m
===================================================================
---- sope-mime/NGImap4/NGImap4Functions.m (revision 1660)
-+++ sope-mime/NGImap4/NGImap4Functions.m (working copy)
+--- sope-mime/NGImap4/NGImap4Functions.m (révision 1660)
++++ sope-mime/NGImap4/NGImap4Functions.m (copie de travail)
@@ -367,3 +367,16 @@
}
@@ -458,8 +458,8 @@ Index: sope-mime/NGImap4/NGImap4Functions.m
+}
Index: sope-mime/NGImap4/NGImap4Client.h
===================================================================
---- sope-mime/NGImap4/NGImap4Client.h (revision 1660)
-+++ sope-mime/NGImap4/NGImap4Client.h (working copy)
+--- sope-mime/NGImap4/NGImap4Client.h (révision 1660)
++++ sope-mime/NGImap4/NGImap4Client.h (copie de travail)
@@ -62,6 +62,8 @@
NGImap4ResponseNormalizer *normer;
NSMutableArray *responseReceiver;
@@ -488,8 +488,8 @@ Index: sope-mime/NGImap4/NGImap4Client.h
- (NSDictionary *)copyUid:(unsigned)_uid toFolder:(NSString *)_folder;
Index: sope-mime/NGImap4/NGImap4Client.m
===================================================================
---- sope-mime/NGImap4/NGImap4Client.m (revision 1660)
-+++ sope-mime/NGImap4/NGImap4Client.m (working copy)
+--- sope-mime/NGImap4/NGImap4Client.m (révision 1660)
++++ sope-mime/NGImap4/NGImap4Client.m (copie de travail)
@@ -24,6 +24,8 @@
#include "NGImap4Client.h"
#include "NGImap4Context.h"
@@ -1001,8 +1001,8 @@ Index: sope-mime/NGImap4/NGImap4Client.m
- (void)setContext:(NGImap4Context *)_ctx {
Index: sope-mime/NGImap4/NGSieveClient.m
===================================================================
---- sope-mime/NGImap4/NGSieveClient.m (revision 1660)
-+++ sope-mime/NGImap4/NGSieveClient.m (working copy)
+--- sope-mime/NGImap4/NGSieveClient.m (révision 1660)
++++ sope-mime/NGImap4/NGSieveClient.m (copie de travail)
@@ -294,8 +294,8 @@
return con;
}
@@ -1037,8 +1037,8 @@ Index: sope-mime/NGImap4/NGSieveClient.m
/* write */
Index: sope-mime/NGImap4/NGImap4Connection.h
===================================================================
---- sope-mime/NGImap4/NGImap4Connection.h (revision 1660)
-+++ sope-mime/NGImap4/NGImap4Connection.h (working copy)
+--- sope-mime/NGImap4/NGImap4Connection.h (révision 1660)
++++ sope-mime/NGImap4/NGImap4Connection.h (copie de travail)
@@ -89,6 +89,9 @@
- (NSArray *)subfoldersForURL:(NSURL *)_url;
@@ -1051,8 +1051,8 @@ Index: sope-mime/NGImap4/NGImap4Connection.h
Index: sope-mime/NGImap4/NGImap4Connection.m
===================================================================
---- sope-mime/NGImap4/NGImap4Connection.m (revision 1660)
-+++ sope-mime/NGImap4/NGImap4Connection.m (working copy)
+--- sope-mime/NGImap4/NGImap4Connection.m (révision 1660)
++++ sope-mime/NGImap4/NGImap4Connection.m (copie de travail)
@@ -22,6 +22,7 @@
#include "NGImap4Connection.h"
#include "NGImap4MailboxInfo.h"
@@ -1191,8 +1191,8 @@ Index: sope-mime/NGImap4/NGImap4Connection.m
/* create */
Index: sope-mime/NGImap4/NGImap4ResponseNormalizer.m
===================================================================
---- sope-mime/NGImap4/NGImap4ResponseNormalizer.m (revision 1660)
-+++ sope-mime/NGImap4/NGImap4ResponseNormalizer.m (working copy)
+--- sope-mime/NGImap4/NGImap4ResponseNormalizer.m (révision 1660)
++++ sope-mime/NGImap4/NGImap4ResponseNormalizer.m (copie de travail)
@@ -76,22 +76,6 @@
return self;
}
@@ -1290,8 +1290,8 @@ Index: sope-mime/NGImap4/NGImap4ResponseNormalizer.m
if (objs) free(objs);
Index: sope-mime/NGImap4/EOQualifier+IMAPAdditions.m
===================================================================
---- sope-mime/NGImap4/EOQualifier+IMAPAdditions.m (revision 1660)
-+++ sope-mime/NGImap4/EOQualifier+IMAPAdditions.m (working copy)
+--- sope-mime/NGImap4/EOQualifier+IMAPAdditions.m (révision 1660)
++++ sope-mime/NGImap4/EOQualifier+IMAPAdditions.m (copie de travail)
@@ -53,13 +53,13 @@
if (FlagKeyWords) return;
@@ -1451,8 +1451,8 @@ Index: sope-mime/NGImap4/EOQualifier+IMAPAdditions.m
[search appendString:[lvalue stringValue]];
Index: sope-mime/NGImap4/NGImap4ResponseParser.m
===================================================================
---- sope-mime/NGImap4/NGImap4ResponseParser.m (revision 1660)
-+++ sope-mime/NGImap4/NGImap4ResponseParser.m (working copy)
+--- sope-mime/NGImap4/NGImap4ResponseParser.m (révision 1660)
++++ sope-mime/NGImap4/NGImap4ResponseParser.m (copie de travail)
@@ -31,6 +31,7 @@
@interface NGImap4ResponseParser(ParsingPrivates)
- (BOOL)_parseNumberUntaggedResponse:(NGMutableHashMap *)result_;
@@ -1931,8 +1931,8 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
self->serverResponseDebug =
Index: sope-mime/NGImap4/ChangeLog
===================================================================
---- sope-mime/NGImap4/ChangeLog (revision 1660)
-+++ sope-mime/NGImap4/ChangeLog (working copy)
+--- sope-mime/NGImap4/ChangeLog (révision 1660)
++++ sope-mime/NGImap4/ChangeLog (copie de travail)
@@ -1,3 +1,61 @@
+2009-10-06 Wolfgang Sourdeau
+
@@ -1997,8 +1997,8 @@ Index: sope-mime/NGImap4/ChangeLog
* NGImap4Connection.m: some fix for folders ending with a slash (OGo
Index: sope-mime/NGImap4/NGImap4ConnectionManager.m
===================================================================
---- sope-mime/NGImap4/NGImap4ConnectionManager.m (revision 1660)
-+++ sope-mime/NGImap4/NGImap4ConnectionManager.m (working copy)
+--- sope-mime/NGImap4/NGImap4ConnectionManager.m (révision 1660)
++++ sope-mime/NGImap4/NGImap4ConnectionManager.m (copie de travail)
@@ -38,6 +38,9 @@
debugCache = [ud boolForKey:@"NGImap4EnableIMAP4CacheDebug"];
poolingOff = [ud boolForKey:@"NGImap4DisableIMAP4Pooling"];
@@ -2124,8 +2124,8 @@ Index: sope-mime/NGImap4/NGImap4ConnectionManager.m
/* client object */
Index: sope-mime/NGImap4/NSString+Imap4.m
===================================================================
---- sope-mime/NGImap4/NSString+Imap4.m (revision 1660)
-+++ sope-mime/NGImap4/NSString+Imap4.m (working copy)
+--- sope-mime/NGImap4/NSString+Imap4.m (révision 1660)
++++ sope-mime/NGImap4/NSString+Imap4.m (copie de travail)
@@ -20,117 +20,86 @@
02111-1307, USA.
*/
@@ -2688,8 +2688,8 @@ Index: sope-mime/NGImap4/NSString+Imap4.m
-}
Index: sope-mime/NGImap4/NGImap4Functions.h
===================================================================
---- sope-mime/NGImap4/NGImap4Functions.h (revision 1660)
-+++ sope-mime/NGImap4/NGImap4Functions.h (working copy)
+--- sope-mime/NGImap4/NGImap4Functions.h (révision 1660)
++++ sope-mime/NGImap4/NGImap4Functions.h (copie de travail)
@@ -58,4 +58,6 @@
id_folder);
BOOL _createSubFolderWithName(id self, NSString *_name, BOOL _app);
@@ -2699,8 +2699,8 @@ Index: sope-mime/NGImap4/NGImap4Functions.h
#endif /* __NGMime_NGImap4_NGImap4Functions_H__ */
Index: sope-mime/NGMail/NGMailAddressParser.h
===================================================================
---- sope-mime/NGMail/NGMailAddressParser.h (revision 1660)
-+++ sope-mime/NGMail/NGMailAddressParser.h (working copy)
+--- sope-mime/NGMail/NGMailAddressParser.h (révision 1660)
++++ sope-mime/NGMail/NGMailAddressParser.h (copie de travail)
@@ -24,7 +24,9 @@
#import
@@ -2737,8 +2737,8 @@ Index: sope-mime/NGMail/NGMailAddressParser.h
Index: sope-mime/NGMail/NGMimeMessageGenerator.m
===================================================================
---- sope-mime/NGMail/NGMimeMessageGenerator.m (revision 1660)
-+++ sope-mime/NGMail/NGMimeMessageGenerator.m (working copy)
+--- sope-mime/NGMail/NGMimeMessageGenerator.m (révision 1660)
++++ sope-mime/NGMail/NGMimeMessageGenerator.m (copie de travail)
@@ -86,37 +86,40 @@
char *des = NULL;
unsigned int cnt;
@@ -2803,8 +2803,8 @@ Index: sope-mime/NGMail/NGMimeMessageGenerator.m
unsigned isoEndLen = 2;
Index: sope-mime/NGMail/NGMailAddressParser.m
===================================================================
---- sope-mime/NGMail/NGMailAddressParser.m (revision 1660)
-+++ sope-mime/NGMail/NGMailAddressParser.m (working copy)
+--- sope-mime/NGMail/NGMailAddressParser.m (révision 1660)
++++ sope-mime/NGMail/NGMailAddressParser.m (copie de travail)
@@ -52,9 +52,9 @@
StrClass = [NSString class];
}
@@ -2948,8 +2948,8 @@ Index: sope-mime/NGMail/NGMailAddressParser.m
self->dataPos = 0;
Index: sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m
===================================================================
---- sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m (revision 1660)
-+++ sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m (working copy)
+--- sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m (révision 1660)
++++ sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m (copie de travail)
@@ -19,88 +19,45 @@
02111-1307, USA.
*/
@@ -3353,8 +3353,8 @@ Index: sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m
#if 0
Index: sope-mime/NGMime/NGMimeMultipartBodyParser.m
===================================================================
---- sope-mime/NGMime/NGMimeMultipartBodyParser.m (revision 1660)
-+++ sope-mime/NGMime/NGMimeMultipartBodyParser.m (working copy)
+--- sope-mime/NGMime/NGMimeMultipartBodyParser.m (révision 1660)
++++ sope-mime/NGMime/NGMimeMultipartBodyParser.m (copie de travail)
@@ -428,6 +428,7 @@
NSString *boundary = nil;
NSArray *rawBodyParts = nil;
@@ -3378,8 +3378,8 @@ Index: sope-mime/NGMime/NGMimeMultipartBodyParser.m
if (rawBodyParts) {
Index: sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m
===================================================================
---- sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m (revision 1660)
-+++ sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m (working copy)
+--- sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m (révision 1660)
++++ sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m (copie de travail)
@@ -77,6 +77,7 @@
[rfc822Set setGenerator:gen forField:@"bcc"];
[rfc822Set setGenerator:gen forField:Fields->from];
@@ -3390,8 +3390,8 @@ Index: sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m
Index: sope-mime/NGMime/NGMimeType.m
===================================================================
---- sope-mime/NGMime/NGMimeType.m (revision 1660)
-+++ sope-mime/NGMime/NGMimeType.m (working copy)
+--- sope-mime/NGMime/NGMimeType.m (révision 1660)
++++ sope-mime/NGMime/NGMimeType.m (copie de travail)
@@ -120,30 +120,30 @@
/* some unsupported, but known encoding */
@@ -3496,8 +3496,8 @@ Index: sope-mime/NGMime/NGMimeType.m
- (NSString *)stringValue {
Index: sope-mime/NGMime/NGMimeBodyPart.m
===================================================================
---- sope-mime/NGMime/NGMimeBodyPart.m (revision 1660)
-+++ sope-mime/NGMime/NGMimeBodyPart.m (working copy)
+--- sope-mime/NGMime/NGMimeBodyPart.m (révision 1660)
++++ sope-mime/NGMime/NGMimeBodyPart.m (copie de travail)
@@ -31,18 +31,6 @@
return 2;
}
@@ -3534,8 +3534,8 @@ Index: sope-mime/NGMime/NGMimeBodyPart.m
- (NSString *)contentId {
Index: sope-mime/NGMime/ChangeLog
===================================================================
---- sope-mime/NGMime/ChangeLog (revision 1660)
-+++ sope-mime/NGMime/ChangeLog (working copy)
+--- sope-mime/NGMime/ChangeLog (révision 1660)
++++ sope-mime/NGMime/ChangeLog (copie de travail)
@@ -1,3 +1,25 @@
+2008-09-08 Wolfgang Sourdeau
+
@@ -3564,8 +3564,8 @@ Index: sope-mime/NGMime/ChangeLog
* fixes for OGo bug #789 (reply-to QP encoding)
Index: sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m
===================================================================
---- sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m (revision 1660)
-+++ sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m (working copy)
+--- sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m (révision 1660)
++++ sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m (copie de travail)
@@ -36,8 +36,7 @@
NGMimeType *type = nil; // only one content-type field
NSString *tmp = nil;
@@ -3704,8 +3704,8 @@ Index: sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m
}
Index: sope-mime/NGMime/NGMimePartGenerator.m
===================================================================
---- sope-mime/NGMime/NGMimePartGenerator.m (revision 1660)
-+++ sope-mime/NGMime/NGMimePartGenerator.m (working copy)
+--- sope-mime/NGMime/NGMimePartGenerator.m (révision 1660)
++++ sope-mime/NGMime/NGMimePartGenerator.m (copie de travail)
@@ -155,8 +155,9 @@
BOOL isMultiValue, isFirst;
@@ -3729,8 +3729,8 @@ Index: sope-mime/NGMime/NGMimePartGenerator.m
Index: sope-mime/NGMime/NGMimeBodyParser.m
===================================================================
---- sope-mime/NGMime/NGMimeBodyParser.m (revision 1660)
-+++ sope-mime/NGMime/NGMimeBodyParser.m (working copy)
+--- sope-mime/NGMime/NGMimeBodyParser.m (révision 1660)
++++ sope-mime/NGMime/NGMimeBodyParser.m (copie de travail)
@@ -67,7 +67,10 @@
if (_data == nil) return nil;
@@ -3768,8 +3768,8 @@ Index: sope-mime/NGMime/NGMimeBodyParser.m
}
Index: sope-mime/NGMime/NGMimePartParser.h
===================================================================
---- sope-mime/NGMime/NGMimePartParser.h (revision 1660)
-+++ sope-mime/NGMime/NGMimePartParser.h (working copy)
+--- sope-mime/NGMime/NGMimePartParser.h (révision 1660)
++++ sope-mime/NGMime/NGMimePartParser.h (copie de travail)
@@ -117,6 +117,7 @@
BOOL parserParseRawBodyDataOfPart:1;
BOOL parserBodyParserForPart:1;
@@ -3790,8 +3790,8 @@ Index: sope-mime/NGMime/NGMimePartParser.h
@interface NSObject(NGMimePartParser)
Index: sope-mime/NGMime/NGMimePartParser.m
===================================================================
---- sope-mime/NGMime/NGMimePartParser.m (revision 1660)
-+++ sope-mime/NGMime/NGMimePartParser.m (working copy)
+--- sope-mime/NGMime/NGMimePartParser.m (révision 1660)
++++ sope-mime/NGMime/NGMimePartParser.m (copie de travail)
@@ -227,7 +227,7 @@
}
@@ -3815,8 +3815,8 @@ Index: sope-mime/NGMime/NGMimePartParser.m
: [NGMimeType mimeType:[ctype stringValue]];
Index: sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m
===================================================================
---- sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m (revision 1660)
-+++ sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m (working copy)
+--- sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m (révision 1660)
++++ sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m (copie de travail)
@@ -105,10 +105,10 @@
}
@@ -3901,8 +3901,8 @@ Index: sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m
return data;
Index: sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m
===================================================================
---- sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m (revision 1660)
-+++ sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m (working copy)
+--- sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m (révision 1660)
++++ sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m (copie de travail)
@@ -49,80 +49,70 @@
// TODO: move the stuff below to some NSString or NSData category?
@@ -4037,8 +4037,8 @@ Index: sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m
}
Index: sope-core/NGExtensions/NGExtensions/NSString+Ext.h
===================================================================
---- sope-core/NGExtensions/NGExtensions/NSString+Ext.h (revision 1660)
-+++ sope-core/NGExtensions/NGExtensions/NSString+Ext.h (working copy)
+--- sope-core/NGExtensions/NGExtensions/NSString+Ext.h (révision 1660)
++++ sope-core/NGExtensions/NGExtensions/NSString+Ext.h (copie de travail)
@@ -30,6 +30,7 @@
@interface NSString(GSAdditions)
@@ -4075,8 +4075,8 @@ Index: sope-core/NGExtensions/NGExtensions/NSString+Ext.h
/* specific to libFoundation */
Index: sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m
===================================================================
---- sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m (revision 1660)
-+++ sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m (working copy)
+--- sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m (révision 1660)
++++ sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m (copie de travail)
@@ -39,18 +39,6 @@
: (NSString *)[[self copy] autorelease];
}
@@ -4164,8 +4164,8 @@ Index: sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m
- (BOOL)isAbsoluteURL
Index: sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m
===================================================================
---- sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (revision 1660)
-+++ sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (working copy)
+--- sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (révision 1660)
++++ sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (copie de travail)
@@ -140,8 +140,12 @@
@@ -4207,8 +4207,8 @@ Index: sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m
static char *iconv_wrapper(id self, char *_src, unsigned _srcLen,
Index: sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m
===================================================================
---- sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m (revision 1660)
-+++ sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m (working copy)
+--- sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m (révision 1660)
++++ sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m (copie de travail)
@@ -19,6 +19,7 @@
02111-1307, USA.
*/
@@ -4217,10 +4217,84 @@ Index: sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m
#import
#import
+Index: sope-core/NGStreams/NGStreams/NGDatagramSocket.h
+===================================================================
+--- sope-core/NGStreams/NGStreams/NGDatagramSocket.h (révision 1660)
++++ sope-core/NGStreams/NGStreams/NGDatagramSocket.h (copie de travail)
+@@ -69,7 +69,7 @@
+ + (id)socketBoundToAddress:(id)_address;
+
+ #if !defined(WIN32)
+-+ (BOOL)socketPair:(id[2])_pair inDomain:(id)_domain;
+++ (BOOL)socketPair:(id[2])_pair;
+ #endif
+
+ // accessors
+Index: sope-core/NGStreams/NGStreams/NGActiveSocket.h
+===================================================================
+--- sope-core/NGStreams/NGStreams/NGActiveSocket.h (révision 1660)
++++ sope-core/NGStreams/NGStreams/NGActiveSocket.h (copie de travail)
+@@ -60,7 +60,7 @@
+ - (id)initWithDomain:(id)_domain; // designated initializer
+
+ #if !defined(WIN32)
+-+ (BOOL)socketPair:(id[2])_pair inDomain:(id)_domain;
+++ (BOOL)socketPair:(id[2])_pair;
+ #endif
+
+ // ******************** operations ********************
+Index: sope-core/NGStreams/NGDatagramSocket.m
+===================================================================
+--- sope-core/NGStreams/NGDatagramSocket.m (révision 1660)
++++ sope-core/NGStreams/NGDatagramSocket.m (copie de travail)
+@@ -25,6 +25,8 @@
+ #endif
+
+ #include
++#include
++#include
+ #include "NGDatagramSocket.h"
+ #include "NGDatagramPacket.h"
+ #include "NGSocketExceptions.h"
+@@ -55,19 +57,21 @@
+
+ #if !defined(WIN32) || defined(__CYGWIN32__)
+
+-+ (BOOL)socketPair:(id[2])_pair inDomain:(id)_domain {
+++ (BOOL)socketPair:(id[2])_pair {
+ int fds[2];
++ NGLocalSocketDomain *domain;
+
+ _pair[0] = nil;
+ _pair[1] = nil;
+
+- if (socketpair([_domain socketDomain], SOCK_DGRAM, [_domain protocol],
++ domain = [NGLocalSocketDomain domain];
++ if (socketpair([domain socketDomain], SOCK_DGRAM, [domain protocol],
+ fds) == 0) {
+ NGDatagramSocket *s1 = nil;
+ NGDatagramSocket *s2 = nil;
+
+- s1 = [[self alloc] _initWithDomain:_domain descriptor:fds[0]];
+- s2 = [[self alloc] _initWithDomain:_domain descriptor:fds[1]];
++ s1 = [[self alloc] _initWithDomain:domain descriptor:fds[0]];
++ s2 = [[self alloc] _initWithDomain:domain descriptor:fds[1]];
+ s1 = AUTORELEASE(s1);
+ s2 = AUTORELEASE(s2);
+
+@@ -112,7 +116,7 @@
+ break;
+ }
+ [[[NGCouldNotCreateSocketException alloc]
+- initWithReason:reason domain:_domain] raise];
++ initWithReason:reason domain:domain] raise];
+ return NO;
+ }
+ }
Index: sope-core/NGStreams/GNUmakefile.preamble
===================================================================
---- sope-core/NGStreams/GNUmakefile.preamble (revision 1660)
-+++ sope-core/NGStreams/GNUmakefile.preamble (working copy)
+--- sope-core/NGStreams/GNUmakefile.preamble (révision 1660)
++++ sope-core/NGStreams/GNUmakefile.preamble (copie de travail)
@@ -1,6 +1,7 @@
# compilation settings
@@ -4230,10 +4304,119 @@ Index: sope-core/NGStreams/GNUmakefile.preamble
libNGStreams_INCLUDE_DIRS += \
-I$(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS) \
+Index: sope-core/NGStreams/ChangeLog
+===================================================================
+--- sope-core/NGStreams/ChangeLog (révision 1660)
++++ sope-core/NGStreams/ChangeLog (copie de travail)
+@@ -1,3 +1,14 @@
++2009-11-11 Wolfgang Sourdeau
++
++ * NGActiveSocket.m (+socketPair): removed the domain: parameter as
++ only AF_LOCAL is permitted. Assign a default instance of
++ NGLocalSocketAddress to the sockets to "declare" the sockets as
++ connected.
++
++ * NGActiveSocket.m (-setSendTimeout, -setReceiveTimeout): make use
++ of those methods to actually configure the timeouts on the socket
++ objects (via setsockopt and SO_RCVTIMEO and SO_SNDTIMEO).
++
+ 2009-03-24 Wolfgang Sourdeau
+
+ * GNUmakefile.preamble: add machine-type to include path (eg i386) (v4.7.57)
+Index: sope-core/NGStreams/NGActiveSocket.m
+===================================================================
+--- sope-core/NGStreams/NGActiveSocket.m (révision 1660)
++++ sope-core/NGStreams/NGActiveSocket.m (copie de travail)
+@@ -62,6 +62,8 @@
+ #include "common.h"
+
+ #include
++#include
++#include
+ #include "NGActiveSocket.h"
+ #include "NGSocketExceptions.h"
+ #include "NGSocket+private.h"
+@@ -83,29 +85,35 @@
+
+ #if !defined(WIN32) || defined(__CYGWIN32__)
+
+-+ (BOOL)socketPair:(id[2])_pair inDomain:(id)_domain {
+++ (BOOL)socketPair:(id[2])_pair {
+ int fds[2];
++ NGLocalSocketDomain *domain;
+
+ _pair[0] = nil;
+ _pair[1] = nil;
+
+- if (socketpair([_domain socketDomain], SOCK_STREAM, [_domain protocol],
++ domain = [NGLocalSocketDomain domain];
++ if (socketpair([domain socketDomain], SOCK_STREAM, [domain protocol],
+ fds) == 0) {
+ NGActiveSocket *s1 = nil;
+ NGActiveSocket *s2 = nil;
++ NGLocalSocketAddress *address;
+
+- s1 = [[self alloc] _initWithDomain:_domain descriptor:fds[0]];
+- s2 = [[self alloc] _initWithDomain:_domain descriptor:fds[1]];
++ s1 = [[self alloc] _initWithDomain:domain descriptor:fds[0]];
++ s2 = [[self alloc] _initWithDomain:domain descriptor:fds[1]];
+ s1 = [s1 autorelease];
+ s2 = [s2 autorelease];
+
++ address = [NGLocalSocketAddress address];
+ if ((s1 != nil) && (s2 != nil)) {
+ s1->mode = NGStreamMode_readWrite;
+ s1->receiveTimeout = 0.0;
+ s1->sendTimeout = 0.0;
++ ASSIGN(s1->remoteAddress, address);
+ s2->mode = NGStreamMode_readWrite;
+ s2->receiveTimeout = 0.0;
+ s2->sendTimeout = 0.0;
++ ASSIGN(s2->remoteAddress, address);
+
+ _pair[0] = s1;
+ _pair[1] = s2;
+@@ -152,7 +160,7 @@
+ break;
+ }
+ [[[NGCouldNotCreateSocketException alloc]
+- initWithReason:reason domain:_domain] raise];
++ initWithReason:reason domain:domain] raise];
+ return NO;
+ }
+ }
+@@ -507,6 +515,13 @@
+ }
+
+ - (void)setSendTimeout:(NSTimeInterval)_timeout {
++ struct timeval tv;
++
++ if ([self isConnected]) {
++ tv.tv_sec = (int) _timeout;
++ tv.tv_usec = 0;
++ setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof (struct timeval));
++ }
+ self->sendTimeout = _timeout;
+ }
+ - (NSTimeInterval)sendTimeout {
+@@ -514,6 +529,13 @@
+ }
+
+ - (void)setReceiveTimeout:(NSTimeInterval)_timeout {
++ struct timeval tv;
++
++ if ([self isConnected]) {
++ tv.tv_sec = (int) _timeout;
++ tv.tv_usec = 0;
++ setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof (struct timeval));
++ }
+ self->receiveTimeout = _timeout;
+ }
+ - (NSTimeInterval)receiveTimeout {
Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h
===================================================================
---- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h (revision 1660)
-+++ sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h (working copy)
+--- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h (révision 1660)
++++ sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h (copie de travail)
@@ -19,6 +19,8 @@
02111-1307, USA.
*/
@@ -4254,8 +4437,8 @@ Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h
id entityResolver;
Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m
===================================================================
---- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m (revision 1660)
-+++ sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m (working copy)
+--- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m (révision 1660)
++++ sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m (copie de travail)
@@ -200,10 +200,10 @@
return self->entityResolver;
}
@@ -4271,8 +4454,8 @@ Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m
Index: sope-appserver/mod_ngobjweb/GNUmakefile
===================================================================
---- sope-appserver/mod_ngobjweb/GNUmakefile (revision 1660)
-+++ sope-appserver/mod_ngobjweb/GNUmakefile (working copy)
+--- sope-appserver/mod_ngobjweb/GNUmakefile (révision 1660)
++++ sope-appserver/mod_ngobjweb/GNUmakefile (copie de travail)
@@ -82,7 +82,7 @@
CFLAGS = -Wall -I. -fPIC \
@@ -4292,10 +4475,1270 @@ Index: sope-appserver/mod_ngobjweb/GNUmakefile
install-usr-libexec :: all
$(INSTALL_PROGRAM) $(product) /usr/libexec/httpd/
+Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m
+===================================================================
+--- sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m (révision 1660)
++++ sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m (copie de travail)
+@@ -1,5 +1,6 @@
+ /*
+ Copyright (C) 2000-2005 SKYRIX Software AG
++ Copyright (C) 2009 Inverse inc.
+
+ This file is part of SOPE.
+
+@@ -19,9 +20,29 @@
+ 02111-1307, USA.
+ */
+
+-#import
+-#include
++#import
++#import
++#import
++#import
++#import
++#import
++#import
++#import
++#import
++#import
++#import
+
++#import
++#import
++#import
++#import
++#import
++#import
++#import
++#import
++
++#import "UnixSignalHandler.h"
++
+ #if defined(__CYGWIN32__) || defined(__MINGW32__)
+
+ int WOWatchDogApplicationMain
+@@ -39,199 +60,795 @@
+ #include
+ #include
+
+-static pid_t child = -1;
+-static NSString *pidFile = nil;
+-static time_t lastFailExit = 0;
+-static unsigned failExitCount = 0;
+-static BOOL killedChild = NO;
++static NSTimeInterval respawnDelay; /* seconds */
+
+-static void killChild(void) {
+- if (child > 0) {
+- int status;
+-
+- fprintf(stderr, "watchdog[%i]: terminating child %i ..\n", getpid(), child);
+-
+- if (kill(child, SIGTERM) == 0) {
+- waitpid(child, &status, 0);
+- killedChild = YES;
+-
+- fprintf(stderr, " terminated child %i", child);
+-
+- if (WIFEXITED(status))
+- fprintf(stderr, " exit=%i", WEXITSTATUS(status));
+- if (WIFSIGNALED(status))
+- fprintf(stderr, " signal=%i", WTERMSIG(status));
+-
+- fprintf(stderr, ".\n");
+- fflush(stderr);
+-
+- child = -1;
+- return;
++typedef enum {
++ WOChildStatusDown = 0,
++ WOChildStatusSpawning,
++ WOChildStatusReady,
++ WOChildStatusBusy,
++ WOChildStatusExcessive,
++ WOChildStatusMax
++} WOChildStatus;
++
++@class WOWatchDog;
++
++@interface WOWatchDogChild : NSObject
++{
++ int pid;
++ int counter;
++ NGActiveSocket *controlSocket;
++ WOChildStatus status;
++ WOWatchDog *watchDog;
++ NSCalendarDate *lastSpawn;
++}
++
++- (void) setWatchDog: (WOWatchDog *) newWatchDog;
++
++- (void) setPid: (int) newPid;
++- (int) pid;
++
++- (void) setControlSocket: (NGActiveSocket *) newSocket;
++- (NGActiveSocket *) controlSocket;
++
++- (void) setStatus: (WOChildStatus) newStatus;
++- (WOChildStatus) status;
++
++- (void) setLastSpawn: (NSCalendarDate *) newLastSpawn;
++- (NSCalendarDate *) lastSpawn;
++
++- (BOOL) readMessage;
++
++- (void) notify;
++- (void) terminate;
++
++@end
++
++@interface WOWatchDog : NSObject
++{
++ NSString *appName;
++ int argc;
++ const char **argv;
++
++ BOOL terminate;
++ BOOL willTerminate;
++
++ NGPassiveSocket *listeningSocket;
++
++ int numberOfChildren;
++ NSMutableArray *children;
++ NSMutableArray *readyChildren;
++ NSMutableArray *downChildren;
++}
++
+++ (id) sharedWatchDog;
++
++- (void) declareChildReady: (WOWatchDogChild *) readyChild;
++- (void) declareChildDown: (WOWatchDogChild *) readyChild;
++
++- (int) run: (NSString *) appName
++ argc: (int) argc
++ argv: (const char **) argv;
++
++@end
++
++@implementation WOWatchDogChild
++
+++ (WOWatchDogChild *) watchDogChild
++{
++ WOWatchDogChild *newChild;
++
++ newChild = [self new];
++ [newChild autorelease];
++
++ return newChild;
++}
++
++- (id) init
++{
++ if ((self = [super init]))
++ {
++ pid = -1;
++ controlSocket = nil;
++ status = WOChildStatusDown;
++ counter = 0;
++ lastSpawn = nil;
+ }
+- else if (kill(child, SIGKILL)) {
+- waitpid(child, &status, 0);
+- killedChild = YES;
+-
+- fprintf(stderr, " killed child %i", child);
+-
+- if (WIFEXITED(status))
+- fprintf(stderr, " exit=%i", WEXITSTATUS(status));
+- if (WIFSIGNALED(status))
+- fprintf(stderr, " signal=%i", WTERMSIG(status));
+-
+- fprintf(stderr, ".\n");
+- fflush(stderr);
+-
+- child = -1;
+- return;
++
++ return self;
++}
++
++- (void) dealloc
++{
++ NSRunLoop *runLoop;
++
++ runLoop = [NSRunLoop currentRunLoop];
++ [runLoop removeEvent: (void *) [controlSocket fileDescriptor]
++ type: ET_RDESC
++ forMode: NSDefaultRunLoopMode
++ all: YES];
++ [controlSocket release];
++ [lastSpawn release];
++ [super dealloc];
++}
++
++- (void) setWatchDog: (WOWatchDog *) newWatchDog
++{
++ watchDog = newWatchDog;
++}
++
++- (void) setPid: (int) newPid
++{
++ pid = newPid;
++}
++
++- (int) pid
++{
++ return pid;
++}
++
++- (void) setControlSocket: (NGActiveSocket *) newSocket
++{
++ NSRunLoop *runLoop;
++
++ runLoop = [NSRunLoop currentRunLoop];
++ if (controlSocket)
++ [runLoop removeEvent: (void *) [controlSocket fileDescriptor]
++ type: ET_RDESC
++ forMode: NSDefaultRunLoopMode
++ all: YES];
++ ASSIGN (controlSocket, newSocket);
++ if (controlSocket)
++ [runLoop addEvent: (void *) [controlSocket fileDescriptor]
++ type: ET_RDESC
++ watcher: self
++ forMode: NSDefaultRunLoopMode];
++}
++
++- (NGActiveSocket *) controlSocket
++{
++ return controlSocket;
++}
++
++- (void) setStatus: (WOChildStatus) newStatus
++{
++ status = newStatus;
++}
++
++- (WOChildStatus) status
++{
++ return status;
++}
++
++- (void) setLastSpawn: (NSCalendarDate *) newLastSpawn
++{
++ ASSIGN(lastSpawn, newLastSpawn);
++}
++
++- (NSCalendarDate *) lastSpawn
++{
++ return lastSpawn;
++}
++
++// - (void) logStatus
++// {
++// NSLog (@"%d served %d requests", pid, counter);
++// if (status == WOChildStatusBusy)
++// NSLog (@"child (%d) is busy", pid);
++// else if (status == WOChildStatusReady)
++// NSLog (@"child (%d) is ready", pid);
++// else if (status == WOChildStatusDown)
++// NSLog (@"child (%d) has shutdown", pid);
++// }
++
++- (BOOL) readMessage
++{
++ WOChildMessage message;
++ BOOL rc;
++
++ if ([controlSocket readBytes: &message
++ count: sizeof (WOChildMessage)] == NGStreamError) {
++ rc = NO;
++ NSLog (@"FAILURE receiving status for child %d", pid);
++ }
++ else {
++ rc = YES;
++ if (message == WOChildMessageAccept) {
++ status = WOChildStatusBusy;
+ }
++ else if (message == WOChildMessageReady) {
++ status = WOChildStatusReady;
++ [watchDog declareChildReady: self];
++ }
++ else if (message == WOChildMessageShutdown) {
++ status = WOChildStatusDown;
++ [watchDog declareChildDown: self];
++ }
++ // NSLog (@"message read status (%d):", pid);
++ // [self logStatus];
+ }
++
++ return rc;
+ }
+
+-static void _writePid(NSString *pidFile) {
+- if ([pidFile length] > 0) {
+- FILE *pf;
+-
+- if ((pf = fopen([pidFile cString], "w"))) {
+- fprintf(pf, "%i\n", getpid());
+- fflush(pf);
+- fclose(pf);
++- (BOOL) _sendMessage: (WOChildMessage) message
++{
++ return ([controlSocket writeBytes: &message
++ count: sizeof (WOChildMessage)] != NGStreamError
++ && [self readMessage]);
++}
++
++- (void) _kill
++{
++ NSLog (@"we send a terminate signal to child %d", pid);
++ status = WOChildStatusDown;
++ kill (pid, SIGTERM);
++ [NSThread sleepForTimeInterval: 1];
++ kill (pid, SIGKILL);
++}
++
++- (void) notify
++{
++ WOChildMessage message;
++
++ counter++;
++ message = WOChildMessageAccept;
++ if (![self _sendMessage: message]) {
++ NSLog (@"FAILURE notifying child %d", pid);
++ [self _kill];
++ }
++}
++
++- (void) terminate
++{
++ WOChildMessage message;
++
++ if (status == WOChildStatusDown) {
++ NSLog (@"child is already down");
++ } else {
++ // NSLog (@"terminating child %d", pid);
++ [controlSocket setSendTimeout: 1.0];
++ [controlSocket setReceiveTimeout: 4.0];
++
++ message = WOChildMessageShutdown;
++ if (!([self _sendMessage: message])) {
++ NSLog (@"FAILURE terminating child %d", pid);
++ [self _kill];
+ }
+ }
+ }
+-static void _delPid(void) {
+- if ([pidFile length] > 0) {
+- if (unlink([pidFile cString]) == 0)
+- pidFile = nil;
++
++- (void) delayedTerminate
++{
++ // NSLog (@"delayed terminate on child %d (wait: %d)", pid,
++ // waitpid(pid, NULL, WNOHANG));
++ [NSTimer scheduledTimerWithTimeInterval: 0.1
++ target: self
++ selector: @selector (terminate)
++ userInfo: nil
++ repeats: NO];
++}
++
++- (void) receivedEvent: (void*)data
++ type: (RunLoopEventType)type
++ extra: (void*)extra
++ forMode: (NSString*)mode
++{
++ [self readMessage];
++}
++
++@end
++
++@implementation WOWatchDog
++
+++ (id) sharedWatchDog
++{
++ static WOWatchDog *sharedWatchDog = nil;
++
++ if (!sharedWatchDog)
++ sharedWatchDog = [self new];
++
++ return sharedWatchDog;
++}
++
++- (id) init
++{
++ if ((self = [super init]))
++ {
++ listeningSocket = NULL;
++ terminate = NO;
++ willTerminate = NO;
++
++ numberOfChildren = 0;
++ children = [[NSMutableArray alloc] initWithCapacity: 10];
++ readyChildren = [[NSMutableArray alloc] initWithCapacity: 10];
++ downChildren = [[NSMutableArray alloc] initWithCapacity: 10];
++ }
++
++ return self;
++}
++
++- (void) _releaseListeningSocket
++{
++ if (listeningSocket) {
++ [[NSRunLoop currentRunLoop] removeEvent: (void *) [listeningSocket fileDescriptor]
++ type: ET_RDESC
++ forMode: NSDefaultRunLoopMode
++ all: YES];
++ [listeningSocket release];
++ listeningSocket = nil;
+ }
+ }
+
+-static void exitWatchdog(void) {
+- killChild();
+- _delPid();
++- (void) dealloc
++{
++ [self _releaseListeningSocket];
++ [appName release];
++ [children release];
++ [super dealloc];
+ }
+
+-static void wsignalHandler(int _signal) {
+- switch (_signal) {
+- case SIGINT:
+- /* Control-C */
+- fprintf(stderr, "[%i]: watchdog handling signal ctrl-c ..\n", getpid());
+- killChild();
+- exit(0);
+- /* shouldn't get here */
+- abort();
++- (void) _runChildWithControlSocket: (NGActiveSocket *) controlSocket
++{
++ WOApplication *app;
++ extern char **environ;
+
+- case SIGSEGV:
+- /* Coredump ! */
+- fprintf(stderr,
+- "[%i]: watchdog handling segmentation fault "
+- "(SERIOUS PROBLEM) ..\n",
+- getpid());
+- killChild();
+- exit(123);
+- /* shouldn't get here */
+- abort();
++ [NSProcessInfo initializeWithArguments: (char **) argv
++ count: argc
++ environment: environ];
++ NGInitTextStdio();
++ app = [NSClassFromString(appName) new];
++ [app autorelease];
++ [app setListeningSocket: listeningSocket];
++ [app setControlSocket: controlSocket];
++ [app run];
++}
+
+- case SIGTERM:
+- /* TERM signal (kill 'pid') */
+- fprintf(stderr, "[%i]: watchdog handling SIGTERM ..\n", getpid());
+- killChild();
+- exit(0);
+- /* shouldn't get here */
+- abort();
+-
+- case SIGHUP:
+- /* HUP signal (restart children) */
+- fprintf(stderr, "[%i]: watchdog handling SIGHUP ..\n", getpid());
+- killChild();
+- killedChild = YES;
+- signal(_signal, wsignalHandler);
+- return;
+-
+- case SIGCHLD:
+- break;
+-
+- default:
+- fprintf(stderr, "[%i]: watchdog handling signal %i ..\n",
+- getpid(), _signal);
+- break;
++- (void) receivedEvent: (void*)data
++ type: (RunLoopEventType)type
++ extra: (void*)extra
++ forMode: (NSString*)mode
++{
++ int nextId;
++ WOWatchDogChild *child;
++
++ // NSLog (@"have a child accept the connection");
++ nextId = [readyChildren count] - 1;
++ if (nextId > -1)
++ {
++ child = [readyChildren objectAtIndex: nextId];
++ [readyChildren removeObjectAtIndex: nextId];
++ [child notify];
++ }
++ // else
++ // NSLog (@"all children busy");
++}
++
++- (void) _cleanupSignalAndEventHandlers
++{
++ int count;
++ NGActiveSocket *controlSocket;
++ NSRunLoop *runLoop;
++
++ [[UnixSignalHandler sharedHandler] removeObserver: self];
++
++ runLoop = [NSRunLoop currentRunLoop];
++ [runLoop removeEvent: (void *) [listeningSocket fileDescriptor]
++ type: ET_RDESC
++ forMode: NSDefaultRunLoopMode
++ all: YES];
++
++ for (count = 0; count < numberOfChildren; count++) {
++ controlSocket = [[children objectAtIndex: count] controlSocket];
++ if (controlSocket)
++ [runLoop removeEvent: (void *) [controlSocket fileDescriptor]
++ type: ET_RDESC
++ forMode: NSDefaultRunLoopMode
++ all: YES];
+ }
+- fflush(stderr);
+-
+- switch (_signal) {
+- case SIGTERM:
+- case SIGINT:
+- case SIGKILL:
+- case SIGILL:
+- killChild();
+- exit(0);
+- break;
+-
+- case SIGHUP:
+- killChild();
+- break;
+-
+- case SIGCHLD: {
+- int returnStatus;
+- pid_t result;
+-
+- // NSLog(@"SIGNAL: SIGCHLD");
+- // fetch return state
+-
+- do {
+- result = waitpid(-1, &returnStatus, WNOHANG);
+- if (result > 0) {
+- fprintf(stderr, "[%i]: process %i exited with code %i",
+- getpid(), (int)result, WEXITSTATUS(returnStatus));
++}
+
+- if (WIFSIGNALED(returnStatus)) {
+- fprintf(stderr, " (terminated due to signal %i%s)",
+- WTERMSIG(returnStatus),
+- WCOREDUMP(returnStatus) ? ", coredump" : "");
+- }
+- if (WIFSTOPPED(returnStatus)) {
+- fprintf(stderr, " (stopped due to signal %i)",
+- WSTOPSIG(returnStatus));
+- }
+-
+- fprintf(stderr, "\n");
+- fflush(stderr);
++- (BOOL) _spawnChild: (WOWatchDogChild *) child
++{
++ NGActiveSocket *pair[2];
++ BOOL isChild;
++ int childPid;
++ extern char **environ;
++
++ isChild = NO;
++
++ if ([NGActiveSocket socketPair: pair]) {
++ childPid = fork ();
++ if (childPid == 0) {
++ setsid ();
++ // stdin = freopen ("/dev/null", "w+", stdin);
++ // stderr = freopen ("/dev/null", "w+", stderr);
++ isChild = YES;
++ [self _cleanupSignalAndEventHandlers];
++ [self _runChildWithControlSocket: pair[0]];
++ } else if (childPid > 0) {
++ [self logWithFormat: @"child spawned with pid %d", childPid];
++ [child setPid: childPid];
++ [child setStatus: WOChildStatusSpawning];
++ [child setControlSocket: pair[1]];
++ [child setLastSpawn: [NSCalendarDate date]];
++ // [self logWithFormat: @"parent ready for child: %d", childPid];
++ } else {
++ perror ("fork");
++ }
++ }
++
++ return isChild;
++}
++
++- (void) _ensureNumberOfChildren
++{
++ int currentNumber, delta, count, min, max;
++ WOWatchDogChild *child;
++
++ currentNumber = [children count];
++ if (currentNumber < numberOfChildren) {
++ delta = numberOfChildren - currentNumber;
++ for (count = 0; count < delta; count++) {
++ child = [WOWatchDogChild watchDogChild];
++ [child setWatchDog: self];
++ [children addObject: child];
++ [downChildren addObject: child];
++ }
++ [self logWithFormat: @"preparing %d children", delta];
++ }
++ else if (currentNumber > numberOfChildren) {
++ delta = currentNumber - numberOfChildren;
++ max = [downChildren count];
++ if (max > delta)
++ min = max - delta;
++ else
++ min = 0;
++ for (count = max - 1; count >= min; count--) {
++ child = [downChildren objectAtIndex: count];
++ [downChildren removeObjectAtIndex: count];
++ [children removeObject: child];
++ delta--;
++ [self logWithFormat: @"%d processes purged from pool", delta];
++ }
++
++ max = [readyChildren count];
++ if (max > delta)
++ max -= delta;
++ for (count = max - 1; count > -1; count--) {
++ child = [readyChildren objectAtIndex: count];
++ [readyChildren removeObjectAtIndex: count];
++ [child terminate];
++ [child setStatus: WOChildStatusExcessive];
++ delta--;
++ }
++ [self logWithFormat: @"%d processes left to terminate", delta];
++ }
++}
++
++- (void) _noop
++{
++}
++
++- (BOOL) _ensureChildren
++{
++ int count, max;
++ WOWatchDogChild *child;
++ BOOL isChild, delayed;
++ NSCalendarDate *now, *nextSpawn;
++
++ isChild = NO;
++
++ if (!willTerminate) {
++ [self _ensureNumberOfChildren];
++ max = [downChildren count];
++ for (count = max - 1; !isChild && count > -1; count--) {
++ delayed = NO;
++ child = [downChildren objectAtIndex: count];
++
++ if ([child status] == WOChildStatusExcessive)
++ [children removeObject: child];
++ else {
++ now = [NSCalendarDate date];
++ nextSpawn = [[child lastSpawn] addYear: 0 month: 0 day: 0
++ hour: 0 minute: 0
++ second: respawnDelay];
++ if ([nextSpawn earlierDate: now] == nextSpawn)
++ isChild = [self _spawnChild: child];
++ else {
++ delayed = YES;
++ [self logWithFormat:
++ @"avoiding to respawn child before %@", nextSpawn];
++ [NSTimer
++ scheduledTimerWithTimeInterval: respawnDelay
++ target: self
++ selector: @selector (_noop)
++ userInfo: nil
++ repeats: NO];
+ }
+ }
+- while (result > 0);
+-
+- break;
++ if (!delayed)
++ [downChildren removeObjectAtIndex: count];
+ }
+-
+- default:
+- fprintf(stderr, "watchdog[%i]: caught signal %i\n", getpid(), _signal);
+- break;
+ }
+- signal(_signal, wsignalHandler);
++
++ return isChild;
+ }
+
+-static void signalHandler(int _signal) {
+- fprintf(stderr, "[%i]: handling signal %i ..\n",
+- getpid(), _signal);
+- fflush(stderr);
+-
+- switch (_signal) {
+- case SIGPIPE:
+- fprintf(stderr, "[%i]: caught signal SIGPIPE\n", getpid());
+- break;
+-
+- default:
+- fprintf(stderr, "[%i]: caught signal %i\n", getpid(), _signal);
+- break;
++/* SOPE on GNUstep does not need to parse the argument line, since the
++ arguments will be put in the NSArgumentDomain. I don't know about
++ libFoundation but OSX is supposed to act the same way. */
++- (NGInternetSocketAddress *) _listeningAddress
++{
++ NGInternetSocketAddress *listeningAddress;
++ id port, allow;
++
++ listeningAddress = nil;
++
++ allow
++ = [[NSUserDefaults standardUserDefaults] objectForKey:@"WOHttpAllowHost"];
++ port = [NSClassFromString(appName) port];
++ if ([port isKindOfClass: [NSString class]]) {
++ if ([port isEqualToString: @"auto"]) {
++ listeningAddress
++ = [[NGInternetSocketAddress alloc] initWithPort:0 onHost:@"127.0.0.1"];
++ [listeningAddress autorelease];
++ } else if ([port rangeOfString: @":"].location == NSNotFound && !allow)
++ port = [NSString stringWithFormat: @"127.0.0.1:%@", port];
+ }
+- signal(_signal, signalHandler);
++ else {
++ if (allow)
++ listeningAddress =
++ [NGInternetSocketAddress wildcardAddressWithPort:[port intValue]];
++ else
++ port = [NSString stringWithFormat: @"127.0.0.1:%@", port];
++ }
++
++ if (!listeningAddress)
++ listeningAddress = (NGInternetSocketAddress *) NGSocketAddressFromString(port);
++
++ return listeningAddress;
+ }
+
++- (BOOL) _prepareListeningSocket
++{
++ NGInternetSocketAddress *addr;
++ BOOL rc;
++ int backlog;
++
++ addr = [self _listeningAddress];
++ NS_DURING {
++ listeningSocket = [[NGPassiveSocket alloc] initWithDomain: [addr domain]];
++ [listeningSocket bindToAddress: addr];
++ backlog = [[NSUserDefaults standardUserDefaults]
++ integerForKey: @"WOListenQueueSize"];
++ if (!backlog)
++ backlog = 5;
++ [listeningSocket listenWithBacklog: backlog];
++ [self logWithFormat: @"listening on %@:%d", [addr address], [addr port]];
++ [[NSRunLoop currentRunLoop] addEvent: (void *) [listeningSocket fileDescriptor]
++ type: ET_RDESC
++ watcher: self
++ forMode: NSDefaultRunLoopMode];
++ rc = YES;
++ }
++ NS_HANDLER {
++ // [self logWithFormat:@"failure listening on address 127.0.0.1:%d", port];
++ rc = NO;
++ }
++ NS_ENDHANDLER;
++
++ return rc;
++}
++
++- (WOWatchDogChild *) _childWithPID: (pid_t) childPid
++{
++ WOWatchDogChild *currentChild, *child;
++ int count;
++
++ child = nil;
++ for (count = 0; !child && count < numberOfChildren; count++) {
++ currentChild = [children objectAtIndex: count];
++ if ([currentChild pid] == childPid)
++ child = currentChild;
++ }
++
++ return child;
++}
++
++- (void) _handleSIGPIPE:(NSNumber *)_signal {
++ // NSLog (@"received SIGPIPE");
++}
++
++/* BUG:
++ - when relying only on SIGCHLD, we miss some of them (signal blocking?)
++ - when relying on [WOWatchDogChild terminate], we exit before all processes
++ are down, this is the least worse of the two. */
++- (void) _handleSIGCHLD:(NSNumber *)_signal {
++ WOWatchDogChild *child;
++ pid_t childPid;
++ int status, code;
++
++ // NSLog (@"received SIGCHLD");
++ childPid = wait(&status);
++ if (childPid > -1) {
++ code = WEXITSTATUS(status);
++ if (code != 0)
++ NSLog (@"child %d exited with code %i", childPid, code);
++ if (WIFSIGNALED(status))
++ NSLog (@" (terminated due to signal %i%@)",
++ WTERMSIG(status),
++ WCOREDUMP(status) ? @", coredump" : @"");
++ if (WIFSTOPPED(status))
++ NSLog (@" (stopped due to signal %i)", WSTOPSIG(status));
++ child = [self _childWithPID: childPid];
++ if (child) {
++ [child setStatus: WOChildStatusDown];
++ [self declareChildDown: child];
++ if (willTerminate && [downChildren count] == numberOfChildren) {
++ NSLog (@"all child exited");
++ terminate = YES;
++ }
++ }
++ }
++ else
++ NSLog (@"no pid received");
++}
++
++- (void) _handleTermination:(NSNumber *)_signal {
++ WOWatchDogChild *child;
++ int count, max;
++
++ if (!willTerminate) {
++ NSLog (@"Terminating with signal %@", _signal);
++ [self _releaseListeningSocket];
++ willTerminate = YES;
++ max = [children count];
++ for (count = 0; count < max; count++) {
++ child = [children objectAtIndex: count];
++ if ([child status] != WOChildStatusDown)
++ [child delayedTerminate];
++ }
++ }
++}
++
++- (void) _handleSIGHUP:(NSNumber *)_signal {
++ [NSTimer scheduledTimerWithTimeInterval: 1.0
++ target: self
++ selector: @selector (_ensureWorkersCount)
++ userInfo: nil
++ repeats: NO];
++}
++
++- (void) _setupSignals
++{
++#if !defined(__MINGW32__) && !defined(NeXT_Foundation_LIBRARY)
++ UnixSignalHandler *us;
++
++ us = [UnixSignalHandler sharedHandler];
++ [us addObserver:self selector:@selector(_handleSIGPIPE:)
++ forSignal:SIGPIPE immediatelyNotifyOnSignal:YES];
++ [us addObserver:self selector:@selector(_handleSIGCHLD:)
++ forSignal:SIGCHLD immediatelyNotifyOnSignal:YES];
++ [us addObserver:self selector:@selector(_handleTermination:)
++ forSignal:SIGINT immediatelyNotifyOnSignal:YES];
++ [us addObserver:self selector:@selector(_handleTermination:)
++ forSignal:SIGTERM immediatelyNotifyOnSignal:YES];
++ // [us addObserver:self selector:@selector(_handleSIGKILL:)
++ // forSignal:SIGKILL immediatelyNotifyOnSignal:YES];
++ [us addObserver:self selector:@selector(_handleSIGHUP:)
++ forSignal:SIGHUP immediatelyNotifyOnSignal:YES];
++#endif
++}
++
++- (void) declareChildReady: (WOWatchDogChild *) readyChild
++{
++ [readyChildren addObject: readyChild];
++}
++
++- (void) declareChildDown: (WOWatchDogChild *) downChild
++{
++ if (![downChildren containsObject: downChild])
++ [downChildren addObject: downChild];
++}
++
++- (void) _ensureWorkersCount
++{
++ int newNumberOfChildren;
++ NSUserDefaults *ud;
++
++ ud = [NSUserDefaults standardUserDefaults];
++ [ud synchronize];
++ newNumberOfChildren = [ud integerForKey: @"WOHttpAdaptorForkCount"];
++ if (newNumberOfChildren)
++ [self logWithFormat: @"user default 'WOHttpAdaptorForkCount' has been"
++ " replaced with 'WOWorkersCount'"];
++ else
++ newNumberOfChildren = [ud integerForKey: @"WOWorkersCount"];
++ if (newNumberOfChildren < 1)
++ newNumberOfChildren = 1;
++ numberOfChildren = newNumberOfChildren;
++ [NSTimer scheduledTimerWithTimeInterval: 0.1
++ target: self
++ selector: @selector (_noop)
++ userInfo: nil
++ repeats: NO];
++}
++
++/* WOPidFile, WOPort */
++- (void) _processArguments
++{
++ NSArray *arguments;
++ NSProcessInfo *processInfo;
++
++ processInfo = [NSProcessInfo processInfo];
++ arguments = [processInfo arguments];
++}
++
++- (int) run: (NSString *) newAppName
++ argc: (int) newArgC argv: (const char **) newArgV
++{
++ NSRunLoop *runLoop;
++ NSDate *limitDate;
++
++ willTerminate = NO;
++
++ ASSIGN(appName, newAppName);
++ argc = newArgC;
++ argv = newArgV;
++
++ [self _processArguments];
++ if ([self _prepareListeningSocket]) {
++ [self _setupSignals];
++ [self _ensureWorkersCount];
++
++ // NSLog (@"ready to process requests");
++ runLoop = [NSRunLoop currentRunLoop];
++ terminate = NO;
++ while (!terminate) {
++ // [self logWithFormat: @"watchdog loop"];
++ NS_DURING {
++ terminate = [self _ensureChildren];
++ if (!terminate) {
++ limitDate = [runLoop limitDateForMode:NSDefaultRunLoopMode];
++ [runLoop runMode: NSDefaultRunLoopMode beforeDate: limitDate];
++ }
++ }
++ NS_HANDLER {
++ terminate = YES;
++ [self errorWithFormat:
++ @"an exception occured in runloop %@", localException];
++ }
++ NS_ENDHANDLER;
++ }
++
++ [[UnixSignalHandler sharedHandler] removeObserver: self];
++ }
++
++ return 0;
++}
++
++@end
++
++static BOOL _writePid(NSString *pidFile) {
++ NSString *pid;
++ BOOL rc;
++
++ pid = [NSString stringWithFormat: @"%d", getpid()];
++ rc = [pid writeToFile: pidFile atomically: NO];
++
++ return rc;
++}
++
+ int WOWatchDogApplicationMain
+ (NSString *appName, int argc, const char *argv[])
+ {
+ NSAutoreleasePool *pool;
+ NSUserDefaults *ud;
++ NSString *logFile, *pidFile;
++ int rc, stdErrNo;
++ pid_t childPid;
++ NSProcessInfo *processInfo;
+
+ pool = [[NSAutoreleasePool alloc] init];
+ #if LIB_FOUNDATION_LIBRARY || defined(GS_PASS_ARGUMENTS)
+@@ -241,179 +858,61 @@
+ environment:(void*)environ];
+ }
+ #endif
+-
++
+ ud = [NSUserDefaults standardUserDefaults];
+-
+- /* default is to use the watch dog! */
+- /* Note: the Defaults.plist is not yet loaded at this stage! */
+- if ([ud objectForKey:@"WOUseWatchDog"] != nil) {
+- if (![ud boolForKey:@"WOUseWatchDog"])
+- return WOApplicationMain(appName, argc, argv);
+- }
+-
+- /* watch dog */
+- {
+- int failCount = 0;
+- int forkCount = 0;
+- BOOL repeat = YES;
+- BOOL isVerbose = NO;
+-
+- isVerbose = [[ud objectForKey:@"watchdog_verbose"] boolValue];
+- pidFile = [[[ud objectForKey:@"watchdog_pidfile"] stringValue] copy];
+-
+- /* write current pid to pidfile */
+- _writePid(pidFile);
+-
+- /* register exit handler */
+- atexit(exitWatchdog);
+-
+- /* register signal handlers of watch dog */
+- signal(SIGPIPE, wsignalHandler);
+- signal(SIGCHLD, wsignalHandler);
+- signal(SIGINT, wsignalHandler);
+- signal(SIGTERM, wsignalHandler);
+- signal(SIGKILL, wsignalHandler);
+- signal(SIGHUP, wsignalHandler);
+-
+- /* loop */
+-
+- while (repeat) {
+- time_t clientStartTime;
+-
+- clientStartTime = time(NULL);
+- killedChild = NO;
+-
+- if ((child = fork()) == -1) {
+- fprintf(stderr, "[%i]: fork failed: %s\n", getpid(), strerror(errno));
+- failCount++;
+-
+- if (failCount > 5) {
+- fprintf(stderr, " fork failed %i times, sleeping 60 seconds ..\n",
+- failCount);
+- sleep(60);
+- }
+- else {
+- sleep(1);
+- }
+- }
+- else {
+- if (child == 0) {
+- /* child process */
+- signal(SIGPIPE, SIG_DFL);
+- signal(SIGCHLD, SIG_DFL);
+- signal(SIGINT, SIG_DFL);
+- signal(SIGTERM, SIG_DFL);
+- signal(SIGKILL, SIG_DFL);
+-
+- if (isVerbose)
+- fprintf(stderr, "starting child %i ..\n", getpid());
++ processInfo = [NSProcessInfo processInfo];
+
+- pidFile = [pidFile stringByAppendingPathExtension:@"child"];
+- _writePid(pidFile);
+-
+- atexit(_delPid);
+-
+- exit(WOApplicationMain(appName, argc, argv));
+-
+- /* shouldn't even get here ! */
+- fprintf(stderr, "internal server error !\n");
+- abort();
+- }
+- else {
+- /* parent (watch dog) */
+- int status = 0;
+- pid_t result = 0;
+- time_t clientStopTime;
+- unsigned uptime;
+-
+- forkCount++;
+-
+- if (isVerbose) {
+- fprintf(stderr, "forked child process %i (#%i) ..\n",
+- child, forkCount);
+- }
+-
+- failCount = 0;
+- status = 0;
+-
+- if ((result = waitpid(child, &status, 0)) == -1) {
+- if (killedChild) {
+- killedChild = NO;
+- continue;
+- }
+-
+- fprintf(stderr,
+- "### waiting for child %i (#%i) failed: %s\n",
+- child, forkCount, strerror(errno));
+- continue;
+- }
++ logFile = [ud objectForKey: @"WOLogFile"];
++ if (!logFile)
++ logFile = [NSString stringWithFormat: @"/var/log/%@/%@.log",
++ [processInfo processName],
++ [processInfo processName]];
++ stdErrNo = dup(fileno(stderr));
++ stdout = freopen([logFile cString], "a", stdout);
++ stderr = freopen([logFile cString], "a", stderr);
++ if (stdout && stderr) {
++ if ([ud boolForKey: @"WONoDetach"])
++ childPid = 0;
++ else
++ childPid = fork();
+
+- clientStopTime = time(NULL);
+- uptime = clientStopTime - clientStartTime;
+-
+- if (WIFSIGNALED(status)) {
+- fprintf(stderr,
+- "### child %i (#%i) was terminated by signal %i "
+- "(uptime=%ds).\n",
+- child, forkCount, WTERMSIG(status), uptime);
+-
+- lastFailExit = time(NULL);
+- failExitCount++;
+- }
+- else if (WIFEXITED(status)) {
+- unsigned exitCode;
+-
+- if ((exitCode = WEXITSTATUS(status)) != 0) {
+- time_t now;
+-
+- now = time(NULL);
+-
+- if (uptime < 3) {
+- if (failExitCount > 0) {
+- unsigned secsSinceLastFail;
+-
+- secsSinceLastFail = (now - lastFailExit);
+-
+- if (secsSinceLastFail > 120) {
+- /* reset fail count */
+- failExitCount = 0;
+- }
+- else if (failExitCount > 20) {
+- printf("### child %i (#%i) already failed %i times "
+- "in the last %i seconds, stopping watchdog !\n",
+- child, forkCount, failExitCount, secsSinceLastFail);
+- repeat = NO;
+- }
+- }
+- }
+- failExitCount++;
+- lastFailExit = now;
+-
+- fprintf(stderr,
+- "### child %i (#%i) exited with status %i "
+- "(#fails=%i, uptime=%ds).\n",
+- child, forkCount, exitCode, failExitCount, uptime);
+- }
+- else {
+- fprintf(stderr,
+- "### child %i (#%i) exited successfully (uptime=%ds).\n",
+- child, forkCount, uptime);
+- }
+-
+- if (exitCode == 123) // ???
+- repeat = NO;
+- }
+- else {
+- fprintf(stderr,
+- "### abnormal termination of child %i (#%i) status=%i"
+- "(was not signaled nor exited).",
+- child, forkCount, status);
+- }
+- }
++ if (childPid) {
++ rc = 0;
++ }
++ else {
++ pidFile = [ud objectForKey: @"WOPidFile"];
++ if (!pidFile)
++ pidFile = [NSString stringWithFormat: @"/var/run/%@/%@.pid",
++ [processInfo processName],
++ [processInfo processName]];
++ if (_writePid(pidFile)) {
++ respawnDelay = [ud integerForKey: @"WORespawnDelay"];
++ if (!respawnDelay)
++ respawnDelay = 5;
++ /* default is to use the watch dog! */
++ /* Note: the Defaults.plist is not yet loaded at this stage! */
++ if ([ud objectForKey:@"WOUseWatchDog"] != nil
++ && ![ud boolForKey:@"WOUseWatchDog"])
++ rc = WOApplicationMain(appName, argc, argv);
++ else
++ rc = [[WOWatchDog sharedWatchDog] run: appName argc: argc argv: argv];
+ }
++ else {
++ NSLog (@"unable to open pid file: %@", pidFile);
++ rc = -1;
++ }
+ }
+- return 0;
+ }
++ else {
++ stdout = fdopen(stdErrNo, "a");
++ stderr = fdopen(stdErrNo, "a");
++ fprintf(stderr, "failed to redirect output channels to log file '%s'\n",
++ [logFile cString]);
++ }
++
++ [pool release];
++
++ return rc;
+ }
+ #endif
+
+@@ -421,8 +920,8 @@
+
+ @interface NSUserDefaults(ServerDefaults)
+ + (id)hackInServerDefaults:(NSUserDefaults *)_ud
+- withAppDomainPath:(NSString *)_appDomainPath
+- globalDomainPath:(NSString *)_globalDomainPath;
++ withAppDomainPath:(NSString *)_appDomainPath
++ globalDomainPath:(NSString *)_globalDomainPath;
+ @end
+
+ int WOWatchDogApplicationMainWithServerDefaults
+@@ -437,7 +936,7 @@
+ {
+ extern char **environ;
+ [NSProcessInfo initializeWithArguments:(void*)argv count:argc
+- environment:(void*)environ];
++ environment:(void*)environ];
+ }
+ #endif
+
+@@ -446,8 +945,8 @@
+
+ ud = [NSUserDefaults standardUserDefaults];
+ sd = [defClass hackInServerDefaults:ud
+- withAppDomainPath:appDomainPath
+- globalDomainPath:globalDomainPath];
++ withAppDomainPath:appDomainPath
++ globalDomainPath:globalDomainPath];
+
+ #if 0
+ if (((sd == nil) || (sd == ud)) && (appDomainPath != nil)) {
Index: sope-appserver/NGObjWeb/GNUmakefile.postamble
===================================================================
---- sope-appserver/NGObjWeb/GNUmakefile.postamble (revision 1660)
-+++ sope-appserver/NGObjWeb/GNUmakefile.postamble (working copy)
+--- sope-appserver/NGObjWeb/GNUmakefile.postamble (révision 1660)
++++ sope-appserver/NGObjWeb/GNUmakefile.postamble (copie de travail)
@@ -23,14 +23,20 @@
# install makefiles
@@ -4326,8 +5769,8 @@ Index: sope-appserver/NGObjWeb/GNUmakefile.postamble
+ $(DESTDIR)/$(GNUSTEP_MAKEFILES)/wobundle.make
Index: sope-appserver/NGObjWeb/WOMessage+XML.m
===================================================================
---- sope-appserver/NGObjWeb/WOMessage+XML.m (revision 1660)
-+++ sope-appserver/NGObjWeb/WOMessage+XML.m (working copy)
+--- sope-appserver/NGObjWeb/WOMessage+XML.m (révision 1660)
++++ sope-appserver/NGObjWeb/WOMessage+XML.m (copie de travail)
@@ -84,7 +84,7 @@
id builder;
@@ -4339,9 +5782,32 @@ Index: sope-appserver/NGObjWeb/WOMessage+XML.m
/* cache DOM structure */
Index: sope-appserver/NGObjWeb/ChangeLog
===================================================================
---- sope-appserver/NGObjWeb/ChangeLog (revision 1660)
-+++ sope-appserver/NGObjWeb/ChangeLog (working copy)
-@@ -1,3 +1,33 @@
+--- sope-appserver/NGObjWeb/ChangeLog (révision 1660)
++++ sope-appserver/NGObjWeb/ChangeLog (copie de travail)
+@@ -1,3 +1,56 @@
++2009-11-11 Wolfgang Sourdeau
++
++ * WOCoreApplication.m (-setControlSocket, -controlSocket)
++ (-setListeningSocket, -listeningSocke): new helper accessors for
++ the new watchdog mechanism.
++
++ * WOHttpAdaptor/WOHttpAdaptor.m: slightly refactored to use the
++ control socket provided by the watchdog.
++
++ * WOWatchDogApplicationMain.m: rewritten the watchdog mechanism:
++ - added WOWatchDog and WOWatchDogChild classes
++ - make use of UnixSignalHandler
++ - added support for preforked preocesses (WOWorkersCount)
++ - detach watchdog processes from terminal by default (WONoDetach)
++ - redirect stderr and stdout to file
++ (WOLogFile = /var/log/[name]/[name].log)
++ - write pid file
++ (WOPidFile = /var/run/[name]/[name].pid)
++ - use "127.0.0.1:port" as default bind address, unless
++ WOHTTPAllowHost is specified
++ - added support for delaying process respawning
++ (WORespawnDelay = 5 seconds)
++
+2009-10-26 Wolfgang Sourdeau
+
+ * WOMessage+XML.m (-contentAsDOMDocument): do not retain "dom" as
@@ -4377,8 +5843,8 @@ Index: sope-appserver/NGObjWeb/ChangeLog
* DAVPropMap.plist: mapped {DAV:}current-user-principal (v4.9.37)
Index: sope-appserver/NGObjWeb/DAVPropMap.plist
===================================================================
---- sope-appserver/NGObjWeb/DAVPropMap.plist (revision 1660)
-+++ sope-appserver/NGObjWeb/DAVPropMap.plist (working copy)
+--- sope-appserver/NGObjWeb/DAVPropMap.plist (révision 1660)
++++ sope-appserver/NGObjWeb/DAVPropMap.plist (copie de travail)
@@ -157,6 +157,7 @@
"{urn:ietf:params:xml:ns:caldav}supported-calendar-data" =
davSupportedCalendarDataTypes;
@@ -4389,8 +5855,8 @@ Index: sope-appserver/NGObjWeb/DAVPropMap.plist
"{urn:ietf:params:xml:ns:carddav}addressbook-home-set" = davAddressbookHomeSet;
Index: sope-appserver/NGObjWeb/WebDAV/SoObjectResultEntry.m
===================================================================
---- sope-appserver/NGObjWeb/WebDAV/SoObjectResultEntry.m (revision 1660)
-+++ sope-appserver/NGObjWeb/WebDAV/SoObjectResultEntry.m (working copy)
+--- sope-appserver/NGObjWeb/WebDAV/SoObjectResultEntry.m (révision 1660)
++++ sope-appserver/NGObjWeb/WebDAV/SoObjectResultEntry.m (copie de travail)
@@ -25,7 +25,14 @@
@implementation SoObjectResultEntry
@@ -4448,8 +5914,8 @@ Index: sope-appserver/NGObjWeb/WebDAV/SoObjectResultEntry.m
Index: sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m
===================================================================
---- sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m (revision 1660)
-+++ sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m (working copy)
+--- sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m (révision 1660)
++++ sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m (copie de travail)
@@ -49,6 +49,8 @@
#define XMLNS_INTTASK \
@"{http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-C000-000000000046}/}"
@@ -4514,8 +5980,8 @@ Index: sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m
}
Index: sope-appserver/NGObjWeb/WODirectAction.m
===================================================================
---- sope-appserver/NGObjWeb/WODirectAction.m (revision 1660)
-+++ sope-appserver/NGObjWeb/WODirectAction.m (working copy)
+--- sope-appserver/NGObjWeb/WODirectAction.m (révision 1660)
++++ sope-appserver/NGObjWeb/WODirectAction.m (copie de travail)
@@ -46,7 +46,7 @@
}
- (id)initWithContext:(WOContext *)_ctx {
@@ -4549,8 +6015,8 @@ Index: sope-appserver/NGObjWeb/WODirectAction.m
Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m
===================================================================
---- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (revision 1660)
-+++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (working copy)
+--- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (révision 1660)
++++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (copie de travail)
@@ -216,6 +216,12 @@
assocCount++;
}
@@ -4566,8 +6032,8 @@ Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m
Index: sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m
===================================================================
---- sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m (revision 1660)
-+++ sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m (working copy)
+--- sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m (révision 1660)
++++ sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m (copie de travail)
@@ -41,6 +41,7 @@
WOAssociation *string;
WOAssociation *target;
@@ -4599,8 +6065,8 @@ Index: sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m
return NO;
Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h
===================================================================
---- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h (revision 1660)
-+++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h (working copy)
+--- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h (révision 1660)
++++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h (copie de travail)
@@ -41,7 +41,8 @@
WOAssociation *pageName;
WOAssociation *actionClass;
@@ -4613,8 +6079,8 @@ Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h
/* 'ivar' associations */
Index: sope-appserver/NGObjWeb/WOMessage.m
===================================================================
---- sope-appserver/NGObjWeb/WOMessage.m (revision 1660)
-+++ sope-appserver/NGObjWeb/WOMessage.m (working copy)
+--- sope-appserver/NGObjWeb/WOMessage.m (révision 1660)
++++ sope-appserver/NGObjWeb/WOMessage.m (copie de travail)
@@ -182,7 +182,7 @@
NSString *key;
@@ -4695,8 +6161,8 @@ Index: sope-appserver/NGObjWeb/WOMessage.m
}
Index: sope-appserver/NGObjWeb/SoObjects/SoObject.m
===================================================================
---- sope-appserver/NGObjWeb/SoObjects/SoObject.m (revision 1660)
-+++ sope-appserver/NGObjWeb/SoObjects/SoObject.m (working copy)
+--- sope-appserver/NGObjWeb/SoObjects/SoObject.m (révision 1660)
++++ sope-appserver/NGObjWeb/SoObjects/SoObject.m (copie de travail)
@@ -39,22 +39,34 @@
static int debugLookup = -1;
static int debugBaseURL = -1;
@@ -4844,11 +6310,115 @@ Index: sope-appserver/NGObjWeb/SoObjects/SoObject.m
}
}
+Index: sope-appserver/NGObjWeb/NGObjWeb/WOAdaptor.h
+===================================================================
+--- sope-appserver/NGObjWeb/NGObjWeb/WOAdaptor.h (révision 1660)
++++ sope-appserver/NGObjWeb/NGObjWeb/WOAdaptor.h (copie de travail)
+@@ -27,6 +27,13 @@
+ @class NSString, NSDictionary;
+ @class WOCoreApplication;
+
++typedef enum {
++ WOChildMessageAccept = 0,
++ WOChildMessageReady,
++ WOChildMessageShutdown,
++ WOChildMessageMax
++} WOChildMessage;
++
+ @interface WOAdaptor : NSObject
+ {
+ @protected
+Index: sope-appserver/NGObjWeb/NGObjWeb/WOCoreApplication.h
+===================================================================
+--- sope-appserver/NGObjWeb/NGObjWeb/WOCoreApplication.h (révision 1660)
++++ sope-appserver/NGObjWeb/NGObjWeb/WOCoreApplication.h (copie de travail)
+@@ -31,6 +31,8 @@
+ @class WOAdaptor, WORequest, WOResponse, WORequestHandler;
+ @class NSBundle;
+
++@class NGActiveSocket, NGPassiveSocket;
++
+ NGObjWeb_EXPORT NSString *WOApplicationWillFinishLaunchingNotification;
+ NGObjWeb_EXPORT NSString *WOApplicationDidFinishLaunchingNotification;
+ NGObjWeb_EXPORT NSString *WOApplicationWillTerminateNotification;
+@@ -41,6 +43,9 @@
+ NSRecursiveLock *lock;
+ NSLock *requestLock;
+
++ NGActiveSocket *controlSocket;
++ NGPassiveSocket *listeningSocket;
++
+ struct {
+ BOOL isTerminating:1;
+ } cappFlags;
+@@ -55,6 +60,14 @@
+ - (void)activateApplication;
+ - (void)deactivateApplication;
+
++/* Watchdog helpers */
++
++- (void)setControlSocket: (NGActiveSocket *) newSocket;
++- (NGActiveSocket *)controlSocket;
++
++- (void)setListeningSocket: (NGPassiveSocket *) newSocket;
++- (NGPassiveSocket *)listeningSocket;
++
+ /* adaptors */
+
+ - (NSArray *)adaptors;
+Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.h
+===================================================================
+--- sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.h (révision 1660)
++++ sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.h (copie de travail)
+@@ -46,7 +46,6 @@
+ NSMutableArray *delayedResponses;
+ }
+
+-+ (BOOL)optionLogStream;
+ + (BOOL)optionLogPerf;
+
+ @end
Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m
===================================================================
---- sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m (revision 1660)
-+++ sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m (working copy)
-@@ -696,7 +696,7 @@
+--- sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m (révision 1660)
++++ sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m (copie de travail)
+@@ -48,8 +48,8 @@
+ NSString *WOAsyncResponseReadyNotificationName =
+ @"WOAsyncResponseReadyNotification";
+ NSString *WOAsyncResponse = @"WOAsyncResponse";
++static BOOL WOHttpAdaptor_LogStream = NO;
+
+-
+ @interface WOCoreApplication(SimpleParserSelection)
+
+ - (BOOL)shouldUseSimpleHTTPParserForTransaction:(id)_tx;
+@@ -85,13 +85,14 @@
+ ud = [NSUserDefaults standardUserDefaults];
+ useSimpleParser = [ud boolForKey:@"WOHttpTransactionUseSimpleParser"];
+ doCore = [[ud objectForKey:@"WOCoreOnHTTPAdaptorException"] boolValue]?1:0;
++ WOHttpAdaptor_LogStream = [ud boolForKey:@"WOHttpAdaptor_LogStream"];
+
+ adLogPath = [[ud stringForKey:@"WOAdaptorLogPath"] copy];
+ if (adLogPath == nil) adLogPath = @"";
+ }
+
+ - (BOOL)optionLogStream {
+- return [WOHttpAdaptor optionLogStream];
++ return WOHttpAdaptor_LogStream;
+ }
+ - (BOOL)optionLogPerf {
+ return perfLogger ? YES : NO;
+@@ -108,6 +109,9 @@
+ NSAssert(_app, @"missing application ...");
+ self->socket = [_socket retain];
+ self->application = [_app retain];
++ if ([[_app recordingPath] length] > 0)
++ WOHttpAdaptor_LogStream = YES;
++
+ return self;
+ }
+
+@@ -696,7 +700,7 @@
*(&out) = nil;
[self _httpValidateResponse:_response];
@@ -4857,7 +6427,7 @@ Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m
out = [(NGCTextStream *)[NGCTextStream alloc] initWithSource:_out];
NS_DURING {
-@@ -705,6 +705,7 @@
+@@ -705,6 +709,7 @@
id body;
BOOL doZip;
BOOL isok = YES;
@@ -4865,7 +6435,7 @@ Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m
doZip = [_response shouldZipResponseToRequest:_request];
-@@ -738,7 +739,11 @@
+@@ -738,7 +743,11 @@
/* add content length header */
@@ -4878,7 +6448,7 @@ Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m
t1 = [[NSString alloc] initWithCString:(char *)buf];
[_response setHeader:t1 forKey:@"content-length"];
[t1 release]; t1 = nil;
-@@ -766,7 +771,7 @@
+@@ -766,7 +775,7 @@
NSString *value;
if (!hasConnectionHeader) {
@@ -4887,3 +6457,478 @@ Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m
hasConnectionHeader = YES;
}
+Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.m
+===================================================================
+--- sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.m (révision 1660)
++++ sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.m (copie de travail)
+@@ -71,18 +71,13 @@
+
+ static NGLogger *logger = nil;
+ static NGLogger *perfLogger = nil;
+-static BOOL WOHttpAdaptor_LogStream = NO;
+ static BOOL WOContactSNS = NO;
+ static BOOL WOCoreOnHTTPAdaptorException = NO;
+ static int WOHttpAdaptorSendTimeout = 10;
+ static int WOHttpAdaptorReceiveTimeout = 10;
+-static int WOHttpAdaptorForkCount = 0;
+ static id allow = nil;
+ static BOOL debugOn = NO;
+
+-+ (BOOL)optionLogStream {
+- return WOHttpAdaptor_LogStream;
+-}
+ + (BOOL)optionLogPerf {
+ return perfLogger != nil ? YES : NO;
+ }
+@@ -108,8 +103,6 @@
+ logger = [lm loggerForClass:self];
+ perfLogger = [lm loggerForDefaultKey:@"WOProfileHttpAdaptor"];
+
+- WOHttpAdaptor_LogStream = [ud boolForKey:@"WOHttpAdaptor_LogStream"];
+-
+ // TODO: this should be queried on demand to allow different defaults
+ WOContactSNS = [[ud objectForKey:@"WOContactSNS"] boolValue];
+
+@@ -134,9 +127,6 @@
+ allow = [allow copy];
+ }
+
+- WOHttpAdaptorForkCount =
+- [[ud objectForKey:@"WOHttpAdaptorForkCount"] intValue];
+-
+ if (WOCoreOnHTTPAdaptorException)
+ [logger warnWithFormat:@"will dump core on HTTP adaptor exception!"];
+ }
+@@ -219,33 +209,31 @@
+ application:_application])) {
+ id arg = nil;
+
+- if ([[_application recordingPath] length] > 0)
+- WOHttpAdaptor_LogStream = YES;
+-
+ [self _registerForSignals];
++ if (![_application controlSocket]) {
++ if ([_args count] < 1)
++ self->address = [self addressFromDefaultsOfApplication:_application];
++ else
++ self->address = [self addressFromArguments:_args];
+
+- if ([_args count] < 1)
+- self->address = [self addressFromDefaultsOfApplication:_application];
+- else
+- self->address = [self addressFromArguments:_args];
++ self->address = [self->address retain];
+
+- self->address = [self->address retain];
++ if (self->address == nil) {
++ [_application errorWithFormat:
++ @"got no address for HTTP server (using arg '%@')", arg];
++ [self release];
++ return nil;
++ }
+
+- if (self->address == nil) {
+- [_application errorWithFormat:
+- @"got no address for HTTP server (using arg '%@')", arg];
+- [self release];
+- return nil;
+- }
+-
+- if (!WOContactSNS) {
+- [_application logWithFormat:@"%@ listening on address %@",
++ if (!WOContactSNS) {
++ [_application logWithFormat:@"%@ listening on address %@",
+ NSStringFromClass([self class]),
+ [(id)self->address stringValue]];
++ }
+ }
+
+ self->lock = [[NSRecursiveLock alloc] init];
+-
++
+ self->maxThreadCount = [[WOCoreApplication workerThreadCount] intValue];
+
+ [self setSendTimeout:WOHttpAdaptorSendTimeout];
+@@ -270,145 +258,76 @@
+ return self->address;
+ }
+
+-/* forking */
+-
+-static pid_t *childPIDs = NULL;
+-static BOOL isForkMaster = YES;
+-
+-- (void)forkChildren {
+- unsigned i;
+-
+- if (WOHttpAdaptorForkCount == 0)
+- return;
+-
+- [self logWithFormat:@"Note: forking %d children for socket processing.",
+- WOHttpAdaptorForkCount];
+-
+-#if !defined(__MINGW32__)
+- [[UnixSignalHandler sharedHandler]
+- addObserver:self selector:@selector(handleSIGCHLD:)
+- forSignal:SIGCHLD immediatelyNotifyOnSignal:NO];
+-#endif
+-
+- childPIDs = calloc(WOHttpAdaptorForkCount + 1, sizeof(pid_t));
+- for (i = 0; i < WOHttpAdaptorForkCount; i++) {
+- childPIDs[i] = fork();
+-
+- if (childPIDs[i] == 0) {
+- /* child */
+- isForkMaster = NO;
+- return;
+- }
+- else if (childPIDs[i] > 0)
+- printf("Note: successfully forked child: %i\n", childPIDs[i]);
+- else
+- [self errorWithFormat:@"failed to fork child %i.", i];
+- }
+-}
+-- (void)killChildren {
+- int i;
+-
+- if (!isForkMaster)
+- return;
+-
+- for (i = 0; i < WOHttpAdaptorForkCount; i++) {
+- if (childPIDs[i] != 0)
+- kill(childPIDs[i], SIGKILL);
+- }
+-}
+-
+-- (void)checkStatusOfChildren {
+- /*
+- Note: currently this does not refork crashed processes. Reforking is harder
+- than it may sound because the crash can happen at arbitary execution
+- states.
+- That is, the "master process" is not virgin anymore, eg it might have
+- open database connections.
+-
+- So the solution might be to refork the whole cluster once a minimum
+- backend threshold is reached.
+- */
+- unsigned int i;
+-
+- if (!isForkMaster)
+- return;
+-
+- for (i = 0; i < WOHttpAdaptorForkCount; i++) {
+- pid_t result;
+- int status;
+-
+- if (childPIDs[i] == 0)
+- continue;
+-
+- result = waitpid(childPIDs[i], &status, WNOHANG);
+- if (result == 0) /* did not exit yet */
+- continue;
+-
+- if (result == -1) { /* error */
+- [self errorWithFormat:@"failed to get status of child %i: %s",
+- childPIDs[i], strerror(errno)];
+- continue;
+- }
+-
+- [self logWithFormat:@"Note: child %i terminated.", childPIDs[i]];
+- childPIDs[i] = 0;
+- }
+-}
+-
+ /* events */
+
+ - (void)handleSIGPIPE:(int)_signal {
+ [self warnWithFormat:@"caught SIGPIPE !"];
+ }
+-- (void)handleSIGCHLD:(int)_signal {
+- [self checkStatusOfChildren];
+-}
+
+ - (void)registerForEvents {
+ int backlog;
++ NGActiveSocket *controlSocket;
++ WOChildMessage message;
++
++ controlSocket = [[WOCoreApplication application] controlSocket];
++ if (controlSocket) {
++ ASSIGN(self->socket, [[WOCoreApplication application] listeningSocket]);
++ [[NSNotificationCenter defaultCenter]
++ addObserver:self
++ selector:@selector(acceptControlMessage:)
++ name:NSFileObjectBecameActiveNotificationName
++ object:nil];
++ [(WORunLoop *)[WORunLoop currentRunLoop]
++ addFileObject:controlSocket
++ activities:NSPosixReadableActivity
++ forMode:NSDefaultRunLoopMode];
++ message = WOChildMessageReady;
++ [controlSocket safeWriteBytes: &message
++ count: sizeof (WOChildMessage)];
++ // [self logWithFormat: @"notified the watchdog that we are ready"];
++ }
++ else {
++ backlog = [[WOCoreApplication listenQueueSize] intValue];
+
+- backlog = [[WOCoreApplication listenQueueSize] intValue];
++ if (backlog == 0)
++ backlog = 5;
+
+- if (backlog == 0)
+- backlog = 5;
++ [self->socket release]; self->socket = nil;
+
+- [self->socket release]; self->socket = nil;
++ self->socket =
++ [[NGPassiveSocket alloc] initWithDomain:[self->address domain]];
+
+- self->socket =
+- [[NGPassiveSocket alloc] initWithDomain:[self->address domain]];
++ [self->socket bindToAddress:self->address];
+
+- [self->socket bindToAddress:self->address];
+-
+- if ([[self->address domain] isEqual:[NGInternetSocketDomain domain]]) {
+- if ([(NGInternetSocketAddress *)self->address port] == 0) {
+- /* let the kernel choose an IP address */
++ if ([[self->address domain] isEqual:[NGInternetSocketDomain domain]]) {
++ if ([(NGInternetSocketAddress *)self->address port] == 0) {
++ /* let the kernel choose an IP address */
+
+- [self debugWithFormat:@"bound to wildcard: %@", self->address];
+- [self debugWithFormat:@"got local: %@", [self->socket localAddress]];
++ [self debugWithFormat:@"bound to wildcard: %@", self->address];
++ [self debugWithFormat:@"got local: %@", [self->socket localAddress]];
+
+- self->address = [[self->socket localAddress] retain];
++ self->address = [[self->socket localAddress] retain];
+
+- [self logWithFormat:@"bound to kernel assigned address %@: %@",
++ [self logWithFormat:@"bound to kernel assigned address %@: %@",
+ self->address, self->socket];
++ }
+ }
+- }
+
+- [self->socket listenWithBacklog:backlog];
++ [self->socket listenWithBacklog:backlog];
+
+- [[NSNotificationCenter defaultCenter]
++ [[NSNotificationCenter defaultCenter]
+ addObserver:self selector:@selector(acceptConnection:)
+- name:NSFileObjectBecameActiveNotificationName
+- object:self->socket];
+- [(WORunLoop *)[WORunLoop currentRunLoop]
++ name:NSFileObjectBecameActiveNotificationName
++ object:self->socket];
++
++ [(WORunLoop *)[WORunLoop currentRunLoop]
+ addFileObject:self->socket
+ activities:NSPosixReadableActivity
+ forMode:NSDefaultRunLoopMode];
+-
+- [self forkChildren];
++ }
+ }
++
+ - (void)unregisterForEvents {
+- [self killChildren];
+-
+ [(WORunLoop *)[WORunLoop currentRunLoop]
+ removeFileObject:self->socket forMode:NSDefaultRunLoopMode];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+@@ -603,52 +522,97 @@
+ return _connection;
+ }
+
++- (NGActiveSocket *)_accept {
++ NGActiveSocket *connection;
++
++ NS_DURING {
++ connection = [self->socket accept];
++ if (!connection)
++ [self _serverCatched:[self->socket lastException]];
++ else
++ [self debugWithFormat:@"accepted connection: %@", connection];
++ }
++ NS_HANDLER {
++ connection = nil;
++ [self _serverCatched:localException];
++ }
++ NS_ENDHANDLER;
++
++ return connection;
++}
++
++- (void)_handleConnection:(NGActiveSocket *)connection {
++ if (connection != nil) {
++ if (self->maxThreadCount <= 1) {
++ NS_DURING
++ [self _handleAcceptedConnection:[connection retain]];
++ NS_HANDLER
++ [self _serverCatched:localException];
++ NS_ENDHANDLER;
++ }
++ else {
++ [NSThread detachNewThreadSelector:
++ @selector(_handleAcceptedConnectionInThread:)
++ toTarget:self
++ withObject:[connection retain]];
++ [self logWithFormat:@"detached new thread for request."];
++ //[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
++ }
++ connection = nil;
++ }
++}
++
++- (void) acceptControlMessage: (NSNotification *) aNotification
++{
++ NGActiveSocket *controlSocket, *connection;
++ WOChildMessage message;
++ NSAutoreleasePool *pool;
++
++ // NSLog (@"received control message");
++ controlSocket = [aNotification object];
++ // [self logWithFormat:@"child accepting message from socket: %@", controlSocket];
++ while (![controlSocket safeReadBytes: &message
++ count: sizeof (WOChildMessage)])
++ NSLog (@"renotifying watchdog");
++ if (message == WOChildMessageAccept) {
++ pool = [NSAutoreleasePool new];
++ // NSLog (@" accepting");
++ connection = [self _accept];
++ // NSLog (@" AAAAAAAAAAAAAA accepted. Handling request.");
++ if ([controlSocket safeWriteBytes: &message
++ count: sizeof (WOChildMessage)])
++ ;
++ // NSLog (@" 1 notified watchdog");
++ [self _handleConnection: connection];
++ message = WOChildMessageReady;
++ // NSLog (@" BBBBBBBBBBBBBB Request handled. Notify watchdog.");
++ [controlSocket safeWriteBytes: &message count: sizeof (WOChildMessage)];
++ // NSLog (@" 2 notified watchdog");
++ // NSLog (@" CCCCCCCCCCCCCC done.");
++ [pool release];
++ }
++ else if (message == WOChildMessageShutdown) {
++ [controlSocket safeWriteBytes: &message
++ count: sizeof (WOChildMessage)];
++ [[WOCoreApplication application] terminate];
++ }
++}
++
+ - (void)acceptConnection:(id)_notification {
++ NGActiveSocket *connection;
+ #if USE_POOLS
+ NSAutoreleasePool *pool;
+- *(&pool) = [[NSAutoreleasePool alloc] init];
++
++ pool = [[NSAutoreleasePool alloc] init];
+ #endif
+ {
+- NGActiveSocket *connection;
+-
+- NS_DURING {
+- *(&connection) = (NGActiveSocket *)[self->socket accept];
+- if (connection == nil)
+- [self _serverCatched:[self->socket lastException]];
+- else
+- [self debugWithFormat:@"accepted connection: %@", connection];
+- }
+- NS_HANDLER {
+- connection = nil;
+- [self _serverCatched:localException];
+- }
+- NS_ENDHANDLER;
+-
+- connection = (NGActiveSocket *)[self _checkAccessOnConnection:connection];
+-
+- if (connection != nil) {
+- if (self->maxThreadCount <= 1) {
+- NS_DURING
+- [self _handleAcceptedConnection:[connection retain]];
+- NS_HANDLER
+- [self _serverCatched:localException];
+- NS_ENDHANDLER;
+- }
+- else {
+- [NSThread detachNewThreadSelector:
+- @selector(_handleAcceptedConnectionInThread:)
+- toTarget:self
+- withObject:[connection retain]];
+- [self logWithFormat:@"detached new thread for request."];
+- //[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
+- }
+- connection = nil;
+- }
++ connection = [self _checkAccessOnConnection:[self _accept]];
++ [self _handleConnection: connection];
+ }
+ #if USE_POOLS
+ [pool release]; pool = nil;
+ #endif
+-
++
+ if (self->isTerminated) {
+ if (self->socket) {
+ [[NSNotificationCenter defaultCenter]
+Index: sope-appserver/NGObjWeb/WOCoreApplication.m
+===================================================================
+--- sope-appserver/NGObjWeb/WOCoreApplication.m (révision 1660)
++++ sope-appserver/NGObjWeb/WOCoreApplication.m (copie de travail)
+@@ -190,6 +190,9 @@
+ forSignal:SIGHUP immediatelyNotifyOnSignal:NO];
+ }
+ #endif
++
++ controlSocket = nil;
++ listeningSocket = nil;
+ }
+ return self;
+ }
+@@ -202,9 +205,32 @@
+ [self->adaptors release];
+ [self->requestLock release];
+ [self->lock release];
++ [self->listeningSocket release];
++ [self->controlSocket release];
+ [super dealloc];
+ }
+
++/* Watchdog helpers */
++- (void)setControlSocket: (NGActiveSocket *) newSocket
++{
++ ASSIGN(self->controlSocket, newSocket);
++}
++
++- (NGActiveSocket *)controlSocket
++{
++ return self->controlSocket;
++}
++
++- (void)setListeningSocket: (NGPassiveSocket *) newSocket
++{
++ ASSIGN(self->listeningSocket, newSocket);
++}
++
++- (NGPassiveSocket *)listeningSocket
++{
++ return self->listeningSocket;
++}
++
+ /* NGLogging */
+
+ + (id)logger {
+@@ -786,7 +812,9 @@
+ id woport;
+ id addr;
+
+- woport = [[self userDefaults] objectForKey:@"WOPort"];
++ woport = [[self userDefaults] objectForKey:@"p"];
++ if (!woport)
++ woport = [[self userDefaults] objectForKey:@"WOPort"];
+ if ([woport isKindOfClass:[NSNumber class]])
+ return woport;
+ woport = [woport stringValue];
diff --git a/Scripts/sogo-init.d-redhat b/Scripts/sogo-init.d-redhat
index 12db1c858..db3f5600c 100755
--- a/Scripts/sogo-init.d-redhat
+++ b/Scripts/sogo-init.d-redhat
@@ -27,31 +27,20 @@
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
-
-# sogod Scalable OpenGroupware.org (Inverse edition)
-
-PREFORK=1
-SOGO_ARGS=""
-USER=sogo
-
PATH=/sbin:/bin:/usr/sbin:/usr/bin
-. /etc/rc.d/init.d/functions
-
-if [ -z "$GNUSTEP_SYSTEM_ROOT" ]
-then
- . /usr/GNUstep/System/Library/Makefiles/GNUstep.sh
-fi
-
-REAL_DAEMON=sogod
-DAEMON=/usr/sbin/sogod
-NAME=sogod
+NAME=sogo
+DAEMON=/usr/GNUstep/System/Tools/Admin/sogod
DESC="Scalable OpenGroupware.Org (Inverse edition)"
-PIDFILE=/var/run/sogo/sogod.
+USER=$NAME
+PREFORK=1
-if [ -f /etc/sysconfig/sogo ]; then
- . /etc/sysconfig/sogo
+PIDFILE=/var/run/$NAME/$NAME.pid
+LOGFILE=/var/log/$NAME/$NAME.log
+
+if [ -f /etc/sysconfig/$NAME ]; then
+ . /etc/sysconfig/$NAME
fi
if [ ! -x $DAEMON ]; then
@@ -69,114 +58,95 @@ checkDir() {
if [ `/usr/bin/stat "$directory" -c %U` != "$USER" ]
then
- echo "$directory is not owned by the sogo user."
+ echo "$directory is not owned by the '$USER' user."
exit 1
fi
}
-checkDir /var/run/sogo
-checkDir /var/spool/sogo
+checkDir /var/run/$NAME
+checkDir /var/spool/$NAME
+checkDir /var/log/$NAME
-#set -e
+. /etc/rc.d/init.d/functions
+if [ -z "$GNUSTEP_SYSTEM_ROOT" ]
+then
+ . /usr/GNUstep/System/Library/Makefiles/GNUstep.sh
+fi
+
+DAEMON_OPTS="-WOWorkersCount $PREFORK -WOPidFile $PIDFILE -WOLogFile $LOGFILE"
start() {
echo $"Starting $DESC: "
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
+ pid="`cat $PIDFILE 2> /dev/null`"
+ if [ -n "$pid" ]
+ then
+ pid="`ps --pid ${pid} -o pid=`"
+ if [ -n "$pid" ]
then
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
- then
- echo " $DAEMON $a already running. Skipped."
- else
- rm -f ${PIDFILE}${a}
- daemon --user="$USER" "$DAEMON" $a
- echo " $DAEMON $a (stale pid file removed)"
- fi
+ echo " $NAME already running. Skipped."
else
- daemon --user="$USER" "$DAEMON" $a
- echo " $DAEMON $a"
+ rm -f $PIDFILE
+ daemon --user="$USER" --pidfile="$PIDFILE" "$DAEMON" $DAEMON_OPTS
+ echo " $NAME (stale pid file removed)"
fi
- done
+ else
+ daemon --user="$USER" --pidfile="$PIDFILE" "$DAEMON" $DAEMON_OPTS
+ echo " $NAME"
+ fi
}
stop() {
echo $"Stopping $DESC: "
- su "$USER" -c '/usr/bin/killall gdnc >& /dev/null'
# We kill the parent processes with SIGTERM so that they
# can exit gracefully.
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
+ pid="`cat $PIDFILE 2> /dev/null`"
+ if [ -n "$pid" ]
+ then
+ pid="`ps --pid ${pid} -o pid=`"
+ if [ -n "$pid" ]
then
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
+ if kill $pid >& /dev/null
then
- if kill $ppid >& /dev/null
- then
- echo " $DAEMON $a stopped"
- fi
- else
- echo " $DAEMON $a not running"
+ sleep 1
+ pid="`ps --pid ${pid} -o pid=`"
+ if [ -n "$pid" ]
+ then
+ echo " $NAME stopped"
+ else
+ kill -9 $pid >& /dev/null
+ echo " $NAME killed"
+ fi
+ rm -f $PIDFILE
fi
else
- echo " $DAEMON $a not running"
+ echo " $NAME not running"
fi
- done
-
- sleep 1
- # We kill the parent and child processes with SIGKILL to make sure they
- # really are shutdown, and then we remove their pidfile.
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
- then
- ppid="`ps --pid ${ppid} -o pid= 2> /dev/null`"
- if [ -n "$ppid" ]
- then
- kill -9 $ppid >& /dev/null
- pid="`ps --ppid ${ppid} -o pid= 2> /dev/null`"
- if [ -n "$pid" ]
- then
- kill -9 $pid >& /dev/null
- fi
- echo " $DAEMON $a killed"
- fi
- fi
- rm -f ${PIDFILE}${a}
- done
+ else
+ echo " $NAME not running"
+ fi
}
restart() {
echo $"Restarting $DESC: "
- su "$USER" -c '/usr/bin/killall gdnc >& /dev/null'
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
+ pid="`cat $PIDFILE 2> /dev/null`"
+ if [ -n "$pid" ]
+ then
+ pid="`ps --pid ${pid} -o pid=`"
+ if [ -n "$pid" ]
then
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
+ if kill $pid >& /dev/null
then
- kill $ppid >& /dev/null
- sleep 1
+ sleep 1
+ pid="`ps --pid ${pid} -o pid=`"
+ if [ -n "$pid" ]
+ then
+ kill -9 $pid >& /dev/null
+ fi
fi
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
- then
- pid="`ps --ppid ${ppid} -o pid=`"
- kill -9 $ppid >& /dev/null
- kill -9 $pid >& /dev/null
- fi
- rm -f ${PIDFILE}${a}
fi
- daemon --user="$USER" "$DAEMON" $a
- echo " $DAEMON $a"
- done
+ fi
+ daemon --user="$USER" --pidfile="$PIDFILE" "$DAEMON" $DAEMON_OPTS
+ echo " $NAME"
}
case "$1" in
@@ -186,15 +156,15 @@ case "$1" in
stop)
stop
;;
- restart|force-reload)
+ restart)
restart
;;
status)
- status $REAL_DAEMON
+ status -p "$PIDFILE" $DAEMON
;;
*)
N=/etc/init.d/$NAME
- echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
+ echo "Usage: $N {start|stop|restart|status}" >&2
exit 1
;;
esac
diff --git a/Scripts/sogo-init.d-sles b/Scripts/sogo-init.d-sles
index ecf1e18f3..a3ccb2852 100755
--- a/Scripts/sogo-init.d-sles
+++ b/Scripts/sogo-init.d-sles
@@ -27,31 +27,20 @@
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
-
-# sogod Scalable OpenGroupware.org (Inverse edition)
-
-PREFORK=1
-SOGO_ARGS=""
-USER=sogo
-
PATH=/sbin:/bin:/usr/sbin:/usr/bin
-. /lib/lsb/init-functions
-
-if [ -z "$GNUSTEP_SYSTEM_ROOT" ]
-then
- . /usr/GNUstep/System/Library/Makefiles/GNUstep.sh
-fi
-
-REAL_DAEMON=sogod
-DAEMON=/usr/sbin/sogod
-NAME=sogod
+NAME=sogo
+DAEMON=/usr/GNUstep/System/Tools/Admin/sogod
DESC="Scalable OpenGroupware.Org (Inverse edition)"
-PIDFILE=/var/run/sogo/sogod.
+USER=$NAME
+PREFORK=1
-if [ -f /etc/sysconfig/sogo ]; then
- . /etc/sysconfig/sogo
+PIDFILE=/var/run/$NAME/$NAME.pid
+LOGFILE=/var/log/$NAME/$NAME.log
+
+if [ -f /etc/sysconfig/$NAME ]; then
+ . /etc/sysconfig/$NAME
fi
if [ ! -x $DAEMON ]; then
@@ -69,115 +58,95 @@ checkDir() {
if [ `/usr/bin/stat "$directory" -c %U` != "$USER" ]
then
- echo "$directory is not owned by the sogo user."
+ echo "$directory is not owned by the '$USER' user."
exit 1
fi
}
-checkDir /var/run/sogo
-checkDir /var/spool/sogo
+checkDir /var/run/$NAME
+checkDir /var/spool/$NAME
+checkDir /var/log/$NAME
-#set -e
+. /lib/lsb/init-functions
+if [ -z "$GNUSTEP_SYSTEM_ROOT" ]
+then
+ . /usr/GNUstep/System/Library/Makefiles/GNUstep.sh
+fi
+
+DAEMON_OPTS="-WOWorkersCount $PREFORK -WOPidFile $PIDFILE -WOLogFile $LOGFILE"
start() {
echo $"Starting $DESC: "
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
+ pid="`cat $PIDFILE 2> /dev/null`"
+ if [ -n "$pid" ]
+ then
+ pid="`ps --pid ${pid} -o pid=`"
+ if [ -n "$pid" ]
then
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
- then
- echo " $DAEMON $a already running. Skipped."
- else
- rm -f ${PIDFILE}${a}
- startproc -u "$USER" "$DAEMON" $a
- echo " $DAEMON $a (stale pid file removed)"
- fi
+ echo " $NAME already running. Skipped."
else
- startproc -u "$USER" "$DAEMON" $a
- echo " $DAEMON $a"
+ rm -f $PIDFILE
+ startproc -u "$USER" -p $PIDFILE "$DAEMON" $DAEMON_OPTS
+ echo " $NAME (stale pid file removed)"
fi
- sleep 1
- done
+ else
+ startproc -u "$USER" -p $PIDFILE "$DAEMON" $DAEMON_OPTS
+ echo " $NAME"
+ fi
}
stop() {
echo $"Stopping $DESC: "
- su "$USER" -c '/usr/bin/killall gdnc >& /dev/null'
# We kill the parent processes with SIGTERM so that they
# can exit gracefully.
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
+ pid="`cat $PIDFILE 2> /dev/null`"
+ if [ -n "$pid" ]
+ then
+ pid="`ps --pid ${pid} -o pid=`"
+ if [ -n "$pid" ]
then
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
+ if kill $pid >& /dev/null
then
- if kill $ppid >& /dev/null
- then
- echo " $DAEMON $a stopped"
- fi
- else
- echo " $DAEMON $a not running"
+ sleep 1
+ pid="`ps --pid ${pid} -o pid=`"
+ if [ -n "$pid" ]
+ then
+ echo " $NAME stopped"
+ else
+ kill -9 $pid >& /dev/null
+ echo " $NAME killed"
+ fi
+ rm -f $PIDFILE
fi
else
- echo " $DAEMON $a not running"
+ echo " $NAME not running"
fi
- done
-
- sleep 1
- # We kill the parent and child processes with SIGKILL to make sure they
- # really are shutdown, and then we remove their pidfile.
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
- then
- ppid="`ps --pid ${ppid} -o pid= 2> /dev/null`"
- if [ -n "$ppid" ]
- then
- kill -9 $ppid >& /dev/null
- pid="`ps --ppid ${ppid} -o pid= 2> /dev/null`"
- if [ -n "$pid" ]
- then
- kill -9 $pid >& /dev/null
- fi
- echo " $DAEMON $a killed"
- fi
- fi
- rm -f ${PIDFILE}${a}
- done
+ else
+ echo " $NAME not running"
+ fi
}
restart() {
echo $"Restarting $DESC: "
- su "$USER" -c '/usr/bin/killall gdnc >& /dev/null'
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
+ pid="`cat $PIDFILE 2> /dev/null`"
+ if [ -n "$pid" ]
+ then
+ pid="`ps --pid ${pid} -o pid=`"
+ if [ -n "$pid" ]
then
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
+ if kill $pid >& /dev/null
then
- kill $ppid >& /dev/null
- sleep 1
+ sleep 1
+ pid="`ps --pid ${pid} -o pid=`"
+ if [ -n "$pid" ]
+ then
+ kill -9 $pid >& /dev/null
+ fi
fi
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
- then
- pid="`ps --ppid ${ppid} -o pid=`"
- kill -9 $ppid >& /dev/null
- kill -9 $pid >& /dev/null
- fi
- rm -f ${PIDFILE}${a}
fi
- startproc -u "$USER" "$DAEMON" $a
- echo " $DAEMON $a"
- done
+ fi
+ startproc -u "$USER" -p $PIDFILE "$DAEMON" $DAEMON_OPTS
+ echo " $NAME"
}
case "$1" in
@@ -187,15 +156,15 @@ case "$1" in
stop)
stop
;;
- restart|force-reload)
+ restart)
restart
;;
status)
- status $REAL_DAEMON
+ checkproc -p $PIDFILE $DAEMON
;;
*)
N=/etc/init.d/$NAME
- echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
+ echo "Usage: $N {start|stop|restart|status}" >&2
exit 1
;;
esac
diff --git a/Scripts/sogod-wrapper b/Scripts/sogod-wrapper
index 5d11000ca..039563060 100755
--- a/Scripts/sogod-wrapper
+++ b/Scripts/sogod-wrapper
@@ -82,5 +82,4 @@ fi
# echo "SOGOD: $sogod -WOPort $listen" 2>&1
-exec $sogod -WOPort $listen >> /var/log/sogo/sogod-$port.log 2>&1 &
-echo $! > $PIDFILE
+exec $sogod -WOPort $listen -WOLogFile /var/log/sogo/sogod.log -WOPidFile $PIDFILE
diff --git a/debian/sogo.init b/debian/sogo.init
index d2bce3d0f..744a058cd 100644
--- a/debian/sogo.init
+++ b/debian/sogo.init
@@ -30,22 +30,20 @@
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
-
-# specify more if you are using a load-balancer
-PREFORK=1
-SOGO_ARGS=""
-USER=sogo
-
PATH=/sbin:/bin:/usr/sbin:/usr/bin
-DAEMON=/usr/sbin/sogod-wrapper
-NAME=sogod
+NAME=sogo
+DAEMON=/usr/sbin/sogod
DESC="Scalable OpenGroupware.Org"
-PIDFILE=/var/run/sogo/sogod.
+USER=$NAME
+PREFORK=1
-if [ -f /etc/default/sogo ]; then
- . /etc/default/sogo
+PIDFILE=/var/run/$NAME/$NAME.pid
+LOGFILE=/var/log/$NAME/$NAME.log
+
+if [ -f /etc/default/$NAME ]; then
+ . /etc/default/$NAME
fi
if [ ! -x $DAEMON ]; then
@@ -53,128 +51,56 @@ if [ ! -x $DAEMON ]; then
exit 1
fi
-if [ `/usr/bin/stat /var/run/sogo -c %U` != $USER ]; then
- echo "/var/run/sogo is not owned by the ${USER}."
- exit 1
-fi
+checkDir() {
+ directory="$1"
+ if [ ! -d "$directory" ]
+ then
+ echo "$directory does not exist."
+ exit 1
+ fi
-if [ `/usr/bin/stat /var/spool/sogo -c %U` != $USER ]; then
- echo "/var/spool/sogo is not owned by the ${USER}."
- exit 1
-fi
+ if [ `/usr/bin/stat "$directory" -c %U` != "$USER" ]
+ then
+ echo "$directory is not owned by the '$USER' user."
+ exit 1
-if [ `/usr/bin/stat /var/log/sogo -c %U` != $USER ]; then
- echo "/var/log/sogo is not owned by the ${USER}."
- exit 1
-fi
+ fi
+}
+
+checkDir /var/run/$NAME
+checkDir /var/spool/$NAME
+checkDir /var/log/$NAME
+
+set -e
+
+. /lib/lsb/init-functions
+. /usr/share/GNUstep/Makefiles/GNUstep.sh
+
+DAEMON_OPTS="-WOWorkersCount $PREFORK -WOPidFile $PIDFILE -WOLogFile $LOGFILE"
case "$1" in
start)
- echo $"Starting $DESC: "
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
- then
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
- then
- echo " $NAME $a already running. Skipped."
- else
- rm -f ${PIDFILE}${a}
- start-stop-daemon -c $USER \
- -b --start --quiet --exec $DAEMON $a
- echo " $NAME $a (stale pid file removed)"
- fi
- else
- start-stop-daemon -c $USER \
- -b --start --quiet --exec $DAEMON $a
- echo " $NAME $a"
- fi
- done
+ echo -n "Starting $DESC: "
+ start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- $DAEMON_OPTS || true
+ echo "$NAME."
;;
-
stop)
- echo $"Stopping $DESC: "
- su "$USER" -c '/usr/bin/killall gdnc >& /dev/null'
- # We kill the parent processes with SIGTERM so that they
- # can exit gracefully.
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
- then
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
- then
- if kill $ppid >& /dev/null
- then
- echo " $NAME $a stopped"
- fi
- else
- echo " $NAME $a not running"
- fi
- else
- echo " $NAME $a not running"
- fi
- done
-
+ echo -n "Stopping $DESC: "
+ start-stop-daemon --stop --quiet --pidfile $PIDFILE --exec $DAEMON || true
+ echo "$NAME."
+ ;;
+ restart)
+ echo -n "Restarting $DESC: "
+ start-stop-daemon --stop --quiet --pidfile $PIDFILE --exec $DAEMON || true
sleep 1
- # We kill the parent and child processes with SIGKILL to make sure they
- # really are shutdown, and then we remove their pidfile.
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
- then
- ppid="`ps --pid ${ppid} -o pid= 2> /dev/null`"
- if [ -n "$ppid" ]
- then
- kill -9 $ppid >& /dev/null
- pid="`ps --ppid ${ppid} -o pid= 2> /dev/null`"
- if [ -n "$pid" ]
- then
- kill -9 $pid >& /dev/null
- fi
- echo " $NAME $a killed"
- fi
- fi
- rm -f ${PIDFILE}${a}
- done
+ start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- $DAEMON_OPTS || true
+ echo "$NAME."
;;
-
- restart|force-reload)
- echo $"Restarting $DESC: "
- su "$USER" -c '/usr/bin/killall gdnc >& /dev/null'
- for ((a=1; a <= PREFORK ; a++))
- do
- ppid="`cat ${PIDFILE}${a} 2> /dev/null`"
- if [ -n "$ppid" ]
- then
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
- then
- kill $ppid >& /dev/null
- sleep 1
- fi
- ppid="`ps --pid ${ppid} -o pid=`"
- if [ -n "$ppid" ]
- then
- pid="`ps --ppid ${ppid} -o pid=`"
- kill -9 $ppid >& /dev/null
- kill -9 $pid >& /dev/null
- fi
- rm -f ${PIDFILE}${a}
- fi
- start-stop-daemon -c $USER \
- -b --start --quiet --exec $DAEMON $a
- echo " $NAME $a"
- done
+ status)
+ status_of_proc -p $PIDFILE "$DAEMON" $NAME && exit 0 || exit $?
;;
-
*)
- N=/etc/init.d/$NAME
- echo "Usage: $N {start|stop|restart|force-reload}" >&2
+ echo "Usage: $NAME {start|stop|restart|status}" >&2
exit 1
;;
esac
diff --git a/sogo.spec b/sogo.spec
index 1958f8490..ea339bfd5 100644
--- a/sogo.spec
+++ b/sogo.spec
@@ -137,7 +137,7 @@ mkdir -p ${RPM_BUILD_ROOT}/var/spool/sogo
cp Apache/SOGo.conf ${RPM_BUILD_ROOT}/etc/httpd/conf.d/
cp Scripts/tmpwatch ${RPM_BUILD_ROOT}/etc/cron.daily/sogo-tmpwatch
cp Scripts/sogo-init.d-redhat ${RPM_BUILD_ROOT}/etc/init.d/sogod
-cp Scripts/sogod-wrapper ${RPM_BUILD_ROOT}/usr/sbin/sogod
+cp Scripts/sogod-wrapper ${RPM_BUILD_ROOT}/usr/sbin/sogod-wrapper
chmod 755 ${RPM_BUILD_ROOT}/usr/sbin/sogod
chmod 755 ${RPM_BUILD_ROOT}/etc/init.d/sogod
cp Scripts/sogo-default ${RPM_BUILD_ROOT}/etc/sysconfig/sogo