diff options
Diffstat (limited to 'src/libs/xpcom18a4/ipc/ipcd/daemon')
18 files changed, 3059 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/Makefile.in new file mode 100644 index 00000000..ad1a66b7 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/Makefile.in @@ -0,0 +1,52 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher <darin@netscape.com> +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +EXPORTS = \ + ipcModule.h \ + ipcModuleUtil.h \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h new file mode 100644 index 00000000..2f299f70 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h @@ -0,0 +1,240 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef ipcModule_h__ +#define ipcModule_h__ + +#include "nsID.h" + +// +// a client handle is used to efficiently reference a client instance object +// used by the daemon to represent a connection with a particular client app. +// +// modules should treat it as an opaque type. +// +typedef class ipcClient *ipcClientHandle; + +//----------------------------------------------------------------------------- +// interface implemented by the module: +//----------------------------------------------------------------------------- + +// +// the version of ipcModuleMethods data structure. +// +#define IPC_MODULE_METHODS_VERSION (1<<16) // 1.0 + +// +// each module defines the following structure: +// +struct ipcModuleMethods +{ + // + // this field holds the version of the data structure, which is always the + // value of IPC_MODULE_METHODS_VERSION against which the module was built. + // + PRUint32 version; + + // + // called after this module is registered. + // + void (* init) (void); + + // + // called when this module will no longer be accessed. + // + void (* shutdown) (void); + + // + // called when a new message arrives for this module. + // + // params: + // client - an opaque "handle" to an object representing the client that + // sent the message. modules should not store the value of this + // beyond the duration fo this function call. (e.g., the handle + // may be invalid after this function call returns.) modules + // wishing to hold onto a reference to a "client" should store + // the client's ID (see IPC_GetClientID). + // target - message target + // data - message data + // dataLen - message data length + // + void (* handleMsg) (ipcClientHandle client, + const nsID &target, + const void *data, + PRUint32 dataLen); + + // + // called when a new client connects to the IPC daemon. + // + void (* clientUp) (ipcClientHandle client); + + // + // called when a client disconnects from the IPC daemon. + // + void (* clientDown) (ipcClientHandle client); +}; + +//----------------------------------------------------------------------------- +// interface implemented by the daemon: +//----------------------------------------------------------------------------- + +// +// the version of ipcDaemonMethods data structure. +// +#define IPC_DAEMON_METHODS_VERSION (1<<16) // 1.0 + +// +// enumeration functions may return FALSE to stop enumeration. +// +typedef PRBool (* ipcClientEnumFunc) (void *closure, ipcClientHandle client, PRUint32 clientID); +typedef PRBool (* ipcClientNameEnumFunc) (void *closure, ipcClientHandle client, const char *name); +typedef PRBool (* ipcClientTargetEnumFunc) (void *closure, ipcClientHandle client, const nsID &target); + +// +// the daemon provides the following structure: +// +struct ipcDaemonMethods +{ + PRUint32 version; + + // + // called to send a message to another module. + // + // params: + // client - identifies the client from which this message originated. + // target - message target + // data - message data + // dataLen - message data length + // + // returns: + // PR_SUCCESS if message was dispatched. + // PR_FAILURE if message could not be dispatched (possibly because + // no module is registered for the given message target). + // + PRStatus (* dispatchMsg) (ipcClientHandle client, + const nsID &target, + const void *data, + PRUint32 dataLen); + + // + // called to send a message to a particular client or to broadcast a + // message to all clients. + // + // params: + // client - if null, then broadcast message to all clients. otherwise, + // send message to the client specified. + // target - message target + // data - message data + // dataLen - message data length + // + // returns: + // PR_SUCCESS if message was sent (or queued up to be sent later). + // PR_FAILURE if message could not be sent (possibly because the client + // does not have a registered observer for the msg's target). + // + PRStatus (* sendMsg) (ipcClientHandle client, + const nsID &target, + const void *data, + PRUint32 dataLen); + + // + // called to lookup a client handle given its client ID. each client has + // a unique ID. + // + ipcClientHandle (* getClientByID) (PRUint32 clientID); + + // + // called to lookup a client by name or alias. names are not necessary + // unique to individual clients. this function returns the client first + // registered under the given name. + // + ipcClientHandle (* getClientByName) (const char *name); + + // + // called to enumerate all clients. + // + void (* enumClients) (ipcClientEnumFunc func, void *closure); + + // + // returns the client ID of the specified client. + // + PRUint32 (* getClientID) (ipcClientHandle client); + + // + // functions for inspecting the names and targets defined for a particular + // client instance. + // + PRBool (* clientHasName) (ipcClientHandle client, const char *name); + PRBool (* clientHasTarget) (ipcClientHandle client, const nsID &target); + void (* enumClientNames) (ipcClientHandle client, ipcClientNameEnumFunc func, void *closure); + void (* enumClientTargets) (ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure); +}; + +//----------------------------------------------------------------------------- +// interface exported by a DSO implementing one or more modules: +//----------------------------------------------------------------------------- + +struct ipcModuleEntry +{ + // + // identifies the message target of this module. + // + nsID target; + + // + // module methods + // + ipcModuleMethods *methods; +}; + +//----------------------------------------------------------------------------- + +#define IPC_EXPORT extern "C" NS_EXPORT + +// +// IPC_EXPORT int IPC_GetModules(const ipcDaemonMethods *, const ipcModuleEntry **); +// +// params: +// methods - the daemon's methods +// entries - the module entries defined by the DSO +// +// returns: +// length of the |entries| array. +// +typedef int (* ipcGetModulesFunc) (const ipcDaemonMethods *methods, const ipcModuleEntry **entries); + +#endif // !ipcModule_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModuleUtil.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModuleUtil.h new file mode 100644 index 00000000..0d1703a8 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModuleUtil.h @@ -0,0 +1,151 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef ipcModuleUtil_h__ +#define ipcModuleUtil_h__ + +#include "prlog.h" +#include "ipcModule.h" + +extern const ipcDaemonMethods *gIPCDaemonMethods; + +//----------------------------------------------------------------------------- +// inline wrapper functions +// +// these functions may only be called by a module that uses the +// IPC_IMPL_GETMODULES macro. +//----------------------------------------------------------------------------- + +inline PRStatus +IPC_DispatchMsg(ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->dispatchMsg(client, target, data, dataLen); +} + +inline PRStatus +IPC_SendMsg(ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->sendMsg(client, target, data, dataLen); +} + +inline ipcClientHandle +IPC_GetClientByID(PRUint32 id) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->getClientByID(id); +} + +inline ipcClientHandle +IPC_GetClientByName(const char *name) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->getClientByName(name); +} + +inline void +IPC_EnumClients(ipcClientEnumFunc func, void *closure) +{ + PR_ASSERT(gIPCDaemonMethods); + gIPCDaemonMethods->enumClients(func, closure); +} + +inline PRUint32 +IPC_GetClientID(ipcClientHandle client) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->getClientID(client); +} + +inline PRBool +IPC_ClientHasName(ipcClientHandle client, const char *name) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->clientHasName(client, name); +} + +inline PRBool +IPC_ClientHasTarget(ipcClientHandle client, const nsID &target) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->clientHasTarget(client, target); +} + +inline void +IPC_EnumClientNames(ipcClientHandle client, ipcClientNameEnumFunc func, void *closure) +{ + PR_ASSERT(gIPCDaemonMethods); + gIPCDaemonMethods->enumClientNames(client, func, closure); +} + +inline void +IPC_EnumClientTargets(ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure) +{ + PR_ASSERT(gIPCDaemonMethods); + gIPCDaemonMethods->enumClientTargets(client, func, closure); +} + +//----------------------------------------------------------------------------- +// inline composite functions +//----------------------------------------------------------------------------- + +inline PRStatus +IPC_SendMsg(PRUint32 clientID, const nsID &target, const void *data, PRUint32 dataLen) +{ + ipcClient *client = IPC_GetClientByID(clientID); + if (!client) + return PR_FAILURE; + return IPC_SendMsg(client, target, data, dataLen); +} + +//----------------------------------------------------------------------------- +// module factory macros +//----------------------------------------------------------------------------- + +#define IPC_IMPL_GETMODULES(_modName, _modEntries) \ + const ipcDaemonMethods *gIPCDaemonMethods; \ + IPC_EXPORT int \ + IPC_GetModules(const ipcDaemonMethods *dmeths, \ + const ipcModuleEntry **ents) { \ + /* XXX do version checking */ \ + gIPCDaemonMethods = dmeths; \ + *ents = _modEntries; \ + return sizeof(_modEntries) / sizeof(ipcModuleEntry); \ + } + +#endif // !ipcModuleUtil_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore new file mode 100644 index 00000000..8d974b7c --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore @@ -0,0 +1,2 @@ +Makefile +mozilla-ipcd diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in new file mode 100644 index 00000000..e9ef6c38 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in @@ -0,0 +1,88 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher <darin@netscape.com> +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd + +# required for #include "nsID.h" +REQUIRES = \ + xpcom \ + $(NULL) + +CPPSRCS = \ + ipcd.cpp \ + ipcClient.cpp \ + ipcModuleReg.cpp \ + ipcCommandModule.cpp + +ifeq ($(OS_ARCH),WINNT) +CPPSRCS += ipcdWin.cpp +else +ifeq ($(OS_ARCH),BeOS) +CPPSRCS += ipcdStub.cpp +else +CPPSRCS += ipcdUnix.cpp +endif +endif + +PROGRAM = mozilla-ipcd$(BIN_SUFFIX) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../../shared/src \ + $(NULL) + +include $(topsrcdir)/config/config.mk + +LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)ipcdshared_s.$(LIB_SUFFIX) \ + $(EXTRA_DSO_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +# For fruncate +ifeq ($(OS_ARCH),Linux) +DEFINES += -D_BSD_SOURCE +endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp new file mode 100644 index 00000000..4f68d175 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp @@ -0,0 +1,235 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ipcLog.h" +#include "ipcClient.h" +#include "ipcMessage.h" +#include "ipcModuleReg.h" +#include "ipcd.h" +#include "ipcm.h" + +#if defined(XP_UNIX) || defined(XP_OS2) +#include "prio.h" +#endif + +PRUint32 ipcClient::gLastID = 0; + +// +// called to initialize this client context +// +// assumptions: +// - object's memory has already been zero'd out. +// +void +ipcClient::Init() +{ + mID = ++gLastID; + + // every client must be able to handle IPCM messages. + mTargets.Append(IPCM_TARGET); + + // although it is tempting to fire off the NotifyClientUp event at this + // time, we must wait until the client sends us a CLIENT_HELLO event. + // see ipcCommandModule::OnClientHello. +} + +// +// called when this client context is going away +// +void +ipcClient::Finalize() +{ + IPC_NotifyClientDown(this); + + mNames.DeleteAll(); + mTargets.DeleteAll(); + +#if defined(XP_UNIX) || defined(XP_OS2) + mInMsg.Reset(); + mOutMsgQ.DeleteAll(); +#endif +} + +void +ipcClient::AddName(const char *name) +{ + LOG(("adding client name: %s\n", name)); + + if (HasName(name)) + return; + + mNames.Append(name); +} + +PRBool +ipcClient::DelName(const char *name) +{ + LOG(("deleting client name: %s\n", name)); + + return mNames.FindAndDelete(name); +} + +void +ipcClient::AddTarget(const nsID &target) +{ + LOG(("adding client target\n")); + + if (HasTarget(target)) + return; + + mTargets.Append(target); +} + +PRBool +ipcClient::DelTarget(const nsID &target) +{ + LOG(("deleting client target\n")); + + // + // cannot remove the IPCM target + // + if (!target.Equals(IPCM_TARGET)) + return mTargets.FindAndDelete(target); + + return PR_FALSE; +} + +#if defined(XP_UNIX) || defined(XP_OS2) + +// +// called to process a client socket +// +// params: +// fd - the client socket +// poll_flags - the state of the client socket +// +// return: +// 0 - to end session with this client +// PR_POLL_READ - to wait for the client socket to become readable +// PR_POLL_WRITE - to wait for the client socket to become writable +// +int +ipcClient::Process(PRFileDesc *fd, int inFlags) +{ + if (inFlags & (PR_POLL_ERR | PR_POLL_HUP | + PR_POLL_EXCEPT | PR_POLL_NVAL)) { + LOG(("client socket appears to have closed\n")); + return 0; + } + + // expect to wait for more data + int outFlags = PR_POLL_READ; + + if (inFlags & PR_POLL_READ) { + LOG(("client socket is now readable\n")); + + char buf[1024]; // XXX make this larger? + PRInt32 n; + + // find out how much data is available for reading... + // n = PR_Available(fd); + + n = PR_Read(fd, buf, sizeof(buf)); + if (n <= 0) + return 0; // cancel connection + + const char *ptr = buf; + while (n) { + PRUint32 nread; + PRBool complete; + + if (mInMsg.ReadFrom(ptr, PRUint32(n), &nread, &complete) == PR_FAILURE) { + LOG(("message appears to be malformed; dropping client connection\n")); + return 0; + } + + if (complete) { + IPC_DispatchMsg(this, &mInMsg); + mInMsg.Reset(); + } + + n -= nread; + ptr += nread; + } + } + + if (inFlags & PR_POLL_WRITE) { + LOG(("client socket is now writable\n")); + + if (mOutMsgQ.First()) + WriteMsgs(fd); + } + + if (mOutMsgQ.First()) + outFlags |= PR_POLL_WRITE; + + return outFlags; +} + +// +// called to write out any messages from the outgoing queue. +// +int +ipcClient::WriteMsgs(PRFileDesc *fd) +{ + while (mOutMsgQ.First()) { + const char *buf = (const char *) mOutMsgQ.First()->MsgBuf(); + PRInt32 bufLen = (PRInt32) mOutMsgQ.First()->MsgLen(); + + if (mSendOffset) { + buf += mSendOffset; + bufLen -= mSendOffset; + } + + PRInt32 nw = PR_Write(fd, buf, bufLen); + if (nw <= 0) + break; + + LOG(("wrote %d bytes\n", nw)); + + if (nw == bufLen) { + mOutMsgQ.DeleteFirst(); + mSendOffset = 0; + } + else + mSendOffset += nw; + } + + return 0; +} + +#endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h new file mode 100644 index 00000000..12e479cf --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h @@ -0,0 +1,144 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef ipcClientUnix_h__ +#define ipcClientUnix_h__ + +#include "prio.h" +#include "ipcMessageQ.h" +#include "ipcStringList.h" +#include "ipcIDList.h" + +#ifdef XP_WIN +#include <windows.h> +#endif + +//----------------------------------------------------------------------------- +// ipcClient +// +// NOTE: this class is an implementation detail of the IPC daemon. IPC daemon +// modules (other than the built-in IPCM module) must not access methods on +// this class directly. use the API provided via ipcd.h instead. +//----------------------------------------------------------------------------- + +class ipcClient +{ +public: + void Init(); + void Finalize(); + + PRUint32 ID() const { return mID; } + + void AddName(const char *name); + PRBool DelName(const char *name); + PRBool HasName(const char *name) const { return mNames.Find(name) != NULL; } + + void AddTarget(const nsID &target); + PRBool DelTarget(const nsID &target); + PRBool HasTarget(const nsID &target) const { return mTargets.Find(target) != NULL; } + + // list iterators + const ipcStringNode *Names() const { return mNames.First(); } + const ipcIDNode *Targets() const { return mTargets.First(); } + + // returns primary client name (the one specified in the "client hello" message) + const char *PrimaryName() const { return mNames.First() ? mNames.First()->Value() : NULL; } + + void SetExpectsSyncReply(PRBool val) { mExpectsSyncReply = val; } + PRBool GetExpectsSyncReply() const { return mExpectsSyncReply; } + +#ifdef XP_WIN + PRUint32 PID() const { return mPID; } + void SetPID(PRUint32 pid) { mPID = pid; } + + HWND Hwnd() const { return mHwnd; } + void SetHwnd(HWND hwnd) { mHwnd = hwnd; } +#endif + +#if defined(XP_UNIX) || defined(XP_OS2) + // + // called to process a client file descriptor. the value of pollFlags + // indicates the state of the socket. + // + // returns: + // 0 - to cancel client connection + // PR_POLL_READ - to poll for a readable socket + // PR_POLL_WRITE - to poll for a writable socket + // (both flags) - to poll for either a readable or writable socket + // + // the socket is non-blocking. + // + int Process(PRFileDesc *sockFD, int pollFlags); + + // + // on success or failure, this function takes ownership of |msg| and will + // delete it when appropriate. + // + void EnqueueOutboundMsg(ipcMessage *msg) { mOutMsgQ.Append(msg); } +#endif + +private: + static PRUint32 gLastID; + + PRUint32 mID; + ipcStringList mNames; + ipcIDList mTargets; + PRBool mExpectsSyncReply; + +#ifdef XP_WIN + // on windows, we store the PID of the client process to help us determine + // the client from which a message originated. each message has the PID + // encoded in it. + PRUint32 mPID; + + // the hwnd of the client's message window. + HWND mHwnd; +#endif + +#if defined(XP_UNIX) || defined(XP_OS2) + ipcMessage mInMsg; // buffer for incoming message + ipcMessageQ mOutMsgQ; // outgoing message queue + + // keep track of the amount of the first message sent + PRUint32 mSendOffset; + + // utility function for writing out messages. + int WriteMsgs(PRFileDesc *fd); +#endif +}; + +#endif // !ipcClientUnix_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.cpp new file mode 100644 index 00000000..43ac547c --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.cpp @@ -0,0 +1,316 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <stdlib.h> +#include <string.h> +#include "ipcLog.h" +#include "ipcCommandModule.h" +#include "ipcModule.h" +#include "ipcClient.h" +#include "ipcMessage.h" +#include "ipcMessageUtils.h" +#include "ipcModuleReg.h" +#include "ipcd.h" +#include "ipcm.h" + +struct ipcCommandModule +{ + typedef void (* MsgHandler)(ipcClient *, const ipcMessage *); + + // + // helpers + // + + static char ** + BuildStringArray(const ipcStringNode *nodes) + { + size_t count = 0; + + const ipcStringNode *node; + + for (node = nodes; node; node = node->mNext) + count++; + + char **strs = (char **) malloc((count + 1) * sizeof(char *)); + if (!strs) + return NULL; + + count = 0; + for (node = nodes; node; node = node->mNext, ++count) + strs[count] = (char *) node->Value(); + strs[count] = 0; + + return strs; + } + + static nsID ** + BuildIDArray(const ipcIDNode *nodes) + { + size_t count = 0; + + const ipcIDNode *node; + + for (node = nodes; node; node = node->mNext) + count++; + + nsID **ids = (nsID **) calloc(count + 1, sizeof(nsID *)); + if (!ids) + return NULL; + + count = 0; + for (node = nodes; node; node = node->mNext, ++count) + ids[count] = (nsID *) &node->Value(); + + return ids; + } + + // + // message handlers + // + + static void + OnPing(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got PING\n")); + + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK)); + } + + static void + OnClientHello(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got CLIENT_HELLO\n")); + + IPC_SendMsg(client, new ipcmMessageClientID(IPCM_GetRequestIndex(rawMsg), client->ID())); + + // + // NOTE: it would almost make sense for this notification to live + // in the transport layer code. however, clients expect to receive + // a CLIENT_ID as the first message following a CLIENT_HELLO, so we + // must not allow modules to see a client until after we have sent + // the CLIENT_ID message. + // + IPC_NotifyClientUp(client); + } + + static void + OnClientAddName(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got CLIENT_ADD_NAME\n")); + + PRInt32 status = IPCM_OK; + PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg); + + ipcMessageCast<ipcmMessageClientAddName> msg(rawMsg); + const char *name = msg->Name(); + if (name) { + ipcClient *result = IPC_GetClientByName(msg->Name()); + if (result) { + LOG((" client with such name already exists (ID = %d)\n", result->ID())); + status = IPCM_ERROR_ALREADY_EXISTS; + } + else + client->AddName(name); + } + else + status = IPCM_ERROR_INVALID_ARG; + + IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status)); + } + + static void + OnClientDelName(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got CLIENT_DEL_NAME\n")); + + PRInt32 status = IPCM_OK; + PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg); + + ipcMessageCast<ipcmMessageClientDelName> msg(rawMsg); + const char *name = msg->Name(); + if (name) { + if (!client->DelName(name)) { + LOG((" client doesn't have name '%s'\n", name)); + status = IPCM_ERROR_NO_SUCH_DATA; + } + } + else + status = IPCM_ERROR_INVALID_ARG; + + IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status)); + } + + static void + OnClientAddTarget(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got CLIENT_ADD_TARGET\n")); + + PRInt32 status = IPCM_OK; + PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg); + + ipcMessageCast<ipcmMessageClientAddTarget> msg(rawMsg); + if (client->HasTarget(msg->Target())) { + LOG((" target already defined for client\n")); + status = IPCM_ERROR_ALREADY_EXISTS; + } + else + client->AddTarget(msg->Target()); + + IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status)); + } + + static void + OnClientDelTarget(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got CLIENT_DEL_TARGET\n")); + + PRInt32 status = IPCM_OK; + PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg); + + ipcMessageCast<ipcmMessageClientDelTarget> msg(rawMsg); + if (!client->DelTarget(msg->Target())) { + LOG((" client doesn't have the given target\n")); + status = IPCM_ERROR_NO_SUCH_DATA; + } + + IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status)); + } + + static void + OnQueryClientByName(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got QUERY_CLIENT_BY_NAME\n")); + + PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg); + + ipcMessageCast<ipcmMessageQueryClientByName> msg(rawMsg); + + ipcClient *result = IPC_GetClientByName(msg->Name()); + if (result) { + LOG((" client exists w/ ID = %u\n", result->ID())); + IPC_SendMsg(client, new ipcmMessageClientID(requestIndex, result->ID())); + } + else { + LOG((" client does not exist\n")); + IPC_SendMsg(client, new ipcmMessageResult(requestIndex, IPCM_ERROR_NO_CLIENT)); + } + } + +#if 0 + static void + OnQueryClientInfo(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got QUERY_CLIENT_INFO\n")); + + ipcMessageCast<ipcmMessageQueryClientInfo> msg(rawMsg); + ipcClient *result = IPC_GetClientByID(msg->ClientID()); + if (result) { + char **names = BuildStringArray(result->Names()); + nsID **targets = BuildIDArray(result->Targets()); + + IPC_SendMsg(client, new ipcmMessageClientInfo(result->ID(), + msg->RequestIndex(), + (const char **) names, + (const nsID **) targets)); + + free(names); + free(targets); + } + else { + LOG((" client does not exist\n")); + IPC_SendMsg(client, new ipcmMessageError(IPCM_ERROR_NO_CLIENT, msg->RequestIndex())); + } + } +#endif + + static void + OnForward(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got FORWARD\n")); + + ipcMessageCast<ipcmMessageForward> msg(rawMsg); + + ipcClient *dest = IPC_GetClientByID(msg->ClientID()); + if (!dest) { + LOG((" destination client not found!\n")); + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_ERROR_NO_CLIENT)); + return; + } + // inform client that its message will be forwarded + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK)); + + ipcMessage *newMsg = new ipcmMessageForward(IPCM_MSG_PSH_FORWARD, + client->ID(), + msg->InnerTarget(), + msg->InnerData(), + msg->InnerDataLen()); + IPC_SendMsg(dest, newMsg); + } +}; + +void +IPCM_HandleMsg(ipcClient *client, const ipcMessage *rawMsg) +{ + static ipcCommandModule::MsgHandler handlers[] = + { + ipcCommandModule::OnPing, + ipcCommandModule::OnForward, + ipcCommandModule::OnClientHello, + ipcCommandModule::OnClientAddName, + ipcCommandModule::OnClientDelName, + ipcCommandModule::OnClientAddTarget, + ipcCommandModule::OnClientDelTarget, + ipcCommandModule::OnQueryClientByName + }; + + int type = IPCM_GetType(rawMsg); + LOG(("IPCM_HandleMsg [type=%x]\n", type)); + + if (!(type & IPCM_MSG_CLASS_REQ)) { + LOG(("not a request -- ignoring message\n")); + return; + } + + type &= ~IPCM_MSG_CLASS_REQ; + type--; + if (type < 0 || type >= (int) (sizeof(handlers)/sizeof(handlers[0]))) { + LOG(("unknown request -- ignoring message\n")); + return; + } + + (handlers[type])(client, rawMsg); +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.h new file mode 100644 index 00000000..ea146cdc --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.h @@ -0,0 +1,48 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef ipcCommandModule_h__ +#define ipcCommandModule_h__ + +#include "ipcm.h" // for IPCM_TARGET + +class ipcClient; +class ipcMessage; + +void IPCM_HandleMsg(ipcClient *, const ipcMessage *); + +#endif // !ipcCommandModule_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp new file mode 100644 index 00000000..09e60ab9 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp @@ -0,0 +1,245 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <string.h> +#include <stdlib.h> + +#include "prlink.h" +#include "prio.h" +#include "prlog.h" +#include "plstr.h" + +#include "ipcConfig.h" +#include "ipcLog.h" +#include "ipcModuleReg.h" +#include "ipcModule.h" +#include "ipcCommandModule.h" +#include "ipcd.h" + +//----------------------------------------------------------------------------- + +struct ipcModuleRegEntry +{ + nsID target; + ipcModuleMethods *methods; + PRLibrary *lib; +}; + +#define IPC_MAX_MODULE_COUNT 64 + +static ipcModuleRegEntry ipcModules[IPC_MAX_MODULE_COUNT]; +static int ipcModuleCount = 0; + +//----------------------------------------------------------------------------- + +static PRStatus +AddModule(const nsID &target, ipcModuleMethods *methods, const char *libPath) +{ + if (ipcModuleCount == IPC_MAX_MODULE_COUNT) { + LOG(("too many modules!\n")); + return PR_FAILURE; + } + + if (!methods) { + PR_NOT_REACHED("null module methods"); + return PR_FAILURE; + } + + // + // each ipcModuleRegEntry holds a reference to a PRLibrary, and on + // shutdown, each PRLibrary reference will be released. this ensures + // that the library will not be unloaded until all of the modules in + // that library are shutdown. + // + ipcModules[ipcModuleCount].target = target; + ipcModules[ipcModuleCount].methods = methods; + ipcModules[ipcModuleCount].lib = PR_LoadLibrary(libPath); + + ++ipcModuleCount; + return PR_SUCCESS; +} + +static void +InitModuleFromLib(const char *modulesDir, const char *fileName) +{ + LOG(("InitModuleFromLib [%s]\n", fileName)); + + static const ipcDaemonMethods gDaemonMethods = + { + IPC_DAEMON_METHODS_VERSION, + IPC_DispatchMsg, + IPC_SendMsg, + IPC_GetClientByID, + IPC_GetClientByName, + IPC_EnumClients, + IPC_GetClientID, + IPC_ClientHasName, + IPC_ClientHasTarget, + IPC_EnumClientNames, + IPC_EnumClientTargets + }; + + int dLen = strlen(modulesDir); + int fLen = strlen(fileName); + + char *buf = (char *) malloc(dLen + 1 + fLen + 1); + memcpy(buf, modulesDir, dLen); + buf[dLen] = IPC_PATH_SEP_CHAR; + memcpy(buf + dLen + 1, fileName, fLen); + buf[dLen + 1 + fLen] = '\0'; + + PRLibrary *lib = PR_LoadLibrary(buf); + if (lib) { + ipcGetModulesFunc func = + (ipcGetModulesFunc) PR_FindFunctionSymbol(lib, "IPC_GetModules"); + + LOG((" func=%p\n", (void*) func)); + + if (func) { + const ipcModuleEntry *entries = NULL; + int count = func(&gDaemonMethods, &entries); + for (int i=0; i<count; ++i) { + if (AddModule(entries[i].target, entries[i].methods, buf) == PR_SUCCESS) { + if (entries[i].methods->init) + entries[i].methods->init(); + } + } + } + PR_UnloadLibrary(lib); + } + + free(buf); +} + +//----------------------------------------------------------------------------- +// ipcModuleReg API +//----------------------------------------------------------------------------- + +void +IPC_InitModuleReg(const char *exePath) +{ + if (!(exePath && *exePath)) + return; + + // + // register plug-in modules + // + char *p = PL_strrchr(exePath, IPC_PATH_SEP_CHAR); + if (p == NULL) { + LOG(("unexpected exe path\n")); + return; + } + + int baseLen = p - exePath; + int finalLen = baseLen + 1 + sizeof(IPC_MODULES_DIR); + + // build full path to ipc modules + char *modulesDir = (char*) malloc(finalLen); + memcpy(modulesDir, exePath, baseLen); + modulesDir[baseLen] = IPC_PATH_SEP_CHAR; + memcpy(modulesDir + baseLen + 1, IPC_MODULES_DIR, sizeof(IPC_MODULES_DIR)); + + LOG(("loading libraries in %s\n", modulesDir)); + // + // scan directory for IPC modules + // + PRDir *dir = PR_OpenDir(modulesDir); + if (dir) { + PRDirEntry *ent; + while ((ent = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) { + // + // locate extension, and check if dynamic library + // + + const char *p = strrchr(ent->name, '.'); + if (p && PL_strcasecmp(p, MOZ_DLL_SUFFIX) == 0) + InitModuleFromLib(modulesDir, ent->name); + } + PR_CloseDir(dir); + } + + free(modulesDir); +} + +void +IPC_ShutdownModuleReg() +{ + // + // shutdown modules in reverse order + // + while (ipcModuleCount) { + ipcModuleRegEntry &entry = ipcModules[--ipcModuleCount]; + if (entry.methods->shutdown) + entry.methods->shutdown(); + if (entry.lib) + PR_UnloadLibrary(entry.lib); + } +} + +void +IPC_NotifyModulesClientUp(ipcClient *client) +{ + for (int i = 0; i < ipcModuleCount; ++i) { + ipcModuleRegEntry &entry = ipcModules[i]; + if (entry.methods->clientUp) + entry.methods->clientUp(client); + } +} + +void +IPC_NotifyModulesClientDown(ipcClient *client) +{ + for (int i = 0; i < ipcModuleCount; ++i) { + ipcModuleRegEntry &entry = ipcModules[i]; + if (entry.methods->clientDown) + entry.methods->clientDown(client); + } +} + +PRStatus +IPC_DispatchMsg(ipcClient *client, const nsID &target, const void *data, PRUint32 dataLen) +{ + // dispatch message to every module registered under the given target. + for (int i=0; i<ipcModuleCount; ++i) { + ipcModuleRegEntry &entry = ipcModules[i]; + if (entry.target.Equals(target)) { + if (entry.methods->handleMsg) + entry.methods->handleMsg(client, target, data, dataLen); + } + } + return PR_SUCCESS; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h new file mode 100644 index 00000000..d3fecd6c --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h @@ -0,0 +1,70 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef ipcModuleReg_h__ +#define ipcModuleReg_h__ + +#include "ipcModule.h" + +// +// called to init the module registry. this may only be called once at +// startup or once after calling IPC_ShutdownModuleReg. +// +// params: +// exePath - path to the daemon executable. modules are loaded from a +// directory relative to the daemon executable. +// +void IPC_InitModuleReg(const char *exePath); + +// +// called to shutdown the module registry. this may be called more than +// once and need not follow a call to IPC_InitModuleReg. +// +void IPC_ShutdownModuleReg(); + +// +// returns the ipcModuleMethods for the given target. +// +ipcModuleMethods *IPC_GetModuleByTarget(const nsID &target); + +// +// notifies all modules of client connect/disconnect +// +void IPC_NotifyModulesClientUp(ipcClient *); +void IPC_NotifyModulesClientDown(ipcClient *); + +#endif // !ipcModuleReg_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp new file mode 100644 index 00000000..60aca34a --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp @@ -0,0 +1,235 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prlog.h" +#include "prio.h" + +#include "ipcConfig.h" +#include "ipcLog.h" +#include "ipcMessage.h" +#include "ipcClient.h" +#include "ipcModuleReg.h" +#include "ipcModule.h" +#include "ipcCommandModule.h" +#include "ipcdPrivate.h" +#include "ipcd.h" + +//----------------------------------------------------------------------------- + +void +IPC_NotifyParent() +{ + PRFileDesc *fd = PR_GetInheritedFD(IPC_STARTUP_PIPE_NAME); + if (fd) { + char c = IPC_STARTUP_PIPE_MAGIC; + PR_Write(fd, &c, 1); + PR_Close(fd); + } +} + +//----------------------------------------------------------------------------- + +PRStatus +IPC_DispatchMsg(ipcClient *client, const ipcMessage *msg) +{ + PR_ASSERT(client); + PR_ASSERT(msg); + + // remember if client is expecting SYNC_REPLY. we'll add that flag to the + // next message sent to the client. + if (msg->TestFlag(IPC_MSG_FLAG_SYNC_QUERY)) { + PR_ASSERT(client->GetExpectsSyncReply() == PR_FALSE); + // XXX shouldn't we remember the TargetID as well, and only set the + // SYNC_REPLY flag on the next message sent to the same TargetID? + client->SetExpectsSyncReply(PR_TRUE); + } + + if (msg->Target().Equals(IPCM_TARGET)) { + IPCM_HandleMsg(client, msg); + return PR_SUCCESS; + } + + return IPC_DispatchMsg(client, msg->Target(), msg->Data(), msg->DataLen()); +} + +PRStatus +IPC_SendMsg(ipcClient *client, ipcMessage *msg) +{ + PR_ASSERT(msg); + + if (client == NULL) { + // + // broadcast + // + for (int i=0; i<ipcClientCount; ++i) + IPC_SendMsg(&ipcClients[i], msg->Clone()); + delete msg; + return PR_SUCCESS; + } + + // add SYNC_REPLY flag to message if client is expecting... + if (client->GetExpectsSyncReply()) { + msg->SetFlag(IPC_MSG_FLAG_SYNC_REPLY); + client->SetExpectsSyncReply(PR_FALSE); + } + + if (client->HasTarget(msg->Target())) + return IPC_PlatformSendMsg(client, msg); + + LOG((" no registered message handler\n")); + return PR_FAILURE; +} + +void +IPC_NotifyClientUp(ipcClient *client) +{ + LOG(("IPC_NotifyClientUp: clientID=%d\n", client->ID())); + + // notify modules before other clients + IPC_NotifyModulesClientUp(client); + + for (int i=0; i<ipcClientCount; ++i) { + if (&ipcClients[i] != client) + IPC_SendMsg(&ipcClients[i], + new ipcmMessageClientState(client->ID(), IPCM_CLIENT_STATE_UP)); + } +} + +void +IPC_NotifyClientDown(ipcClient *client) +{ + LOG(("IPC_NotifyClientDown: clientID=%d\n", client->ID())); + + // notify modules before other clients + IPC_NotifyModulesClientDown(client); + + for (int i=0; i<ipcClientCount; ++i) { + if (&ipcClients[i] != client) + IPC_SendMsg(&ipcClients[i], + new ipcmMessageClientState(client->ID(), IPCM_CLIENT_STATE_DOWN)); + } +} + +//----------------------------------------------------------------------------- +// IPC daemon methods +//----------------------------------------------------------------------------- + +PRStatus +IPC_SendMsg(ipcClient *client, const nsID &target, const void *data, PRUint32 dataLen) +{ + return IPC_SendMsg(client, new ipcMessage(target, (const char *) data, dataLen)); +} + +ipcClient * +IPC_GetClientByID(PRUint32 clientID) +{ + // linear search OK since number of clients should be small + for (int i = 0; i < ipcClientCount; ++i) { + if (ipcClients[i].ID() == clientID) + return &ipcClients[i]; + } + return NULL; +} + +ipcClient * +IPC_GetClientByName(const char *name) +{ + // linear search OK since number of clients should be small + for (int i = 0; i < ipcClientCount; ++i) { + if (ipcClients[i].HasName(name)) + return &ipcClients[i]; + } + return NULL; +} + +void +IPC_EnumClients(ipcClientEnumFunc func, void *closure) +{ + PR_ASSERT(func); + for (int i = 0; i < ipcClientCount; ++i) { + if (func(closure, &ipcClients[i], ipcClients[i].ID()) == PR_FALSE) + break; + } +} + +PRUint32 +IPC_GetClientID(ipcClient *client) +{ + PR_ASSERT(client); + return client->ID(); +} + +PRBool +IPC_ClientHasName(ipcClient *client, const char *name) +{ + PR_ASSERT(client); + PR_ASSERT(name); + return client->HasName(name); +} + +PRBool +IPC_ClientHasTarget(ipcClient *client, const nsID &target) +{ + PR_ASSERT(client); + return client->HasTarget(target); +} + +void +IPC_EnumClientNames(ipcClient *client, ipcClientNameEnumFunc func, void *closure) +{ + PR_ASSERT(client); + PR_ASSERT(func); + const ipcStringNode *node = client->Names(); + while (node) { + if (func(closure, client, node->Value()) == PR_FALSE) + break; + node = node->mNext; + } +} + +void +IPC_EnumClientTargets(ipcClient *client, ipcClientTargetEnumFunc func, void *closure) +{ + PR_ASSERT(client); + PR_ASSERT(func); + const ipcIDNode *node = client->Targets(); + while (node) { + if (func(closure, client, node->Value()) == PR_FALSE) + break; + node = node->mNext; + } +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h new file mode 100644 index 00000000..5a0f2c2a --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h @@ -0,0 +1,82 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef IPCD_H__ +#define IPCD_H__ + +#include "ipcModule.h" +#include "ipcMessage.h" + +//----------------------------------------------------------------------------- +// IPC daemon methods (see struct ipcDaemonMethods) +// +// these functions may only be called directly from within the daemon. plug-in +// modules must access these through the ipcDaemonMethods structure. +//----------------------------------------------------------------------------- + +PRStatus IPC_DispatchMsg (ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen); +PRStatus IPC_SendMsg (ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen); +ipcClientHandle IPC_GetClientByID (PRUint32 id); +ipcClientHandle IPC_GetClientByName (const char *name); +void IPC_EnumClients (ipcClientEnumFunc func, void *closure); +PRUint32 IPC_GetClientID (ipcClientHandle client); +PRBool IPC_ClientHasName (ipcClientHandle client, const char *name); +PRBool IPC_ClientHasTarget (ipcClientHandle client, const nsID &target); +void IPC_EnumClientNames (ipcClientHandle client, ipcClientNameEnumFunc func, void *closure); +void IPC_EnumClientTargets (ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure); + +//----------------------------------------------------------------------------- +// other internal IPCD methods +//----------------------------------------------------------------------------- + +// +// dispatch message +// +PRStatus IPC_DispatchMsg(ipcClientHandle client, const ipcMessage *msg); + +// +// send message, takes ownership of |msg|. +// +PRStatus IPC_SendMsg(ipcClientHandle client, ipcMessage *msg); + +// +// dispatch notifications about client connects and disconnects +// +void IPC_NotifyClientUp(ipcClientHandle client); +void IPC_NotifyClientDown(ipcClientHandle client); + +#endif // !IPCD_H__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h new file mode 100644 index 00000000..023b3a03 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h @@ -0,0 +1,65 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef ipcdPrivate_h__ +#define ipcdPrivate_h__ + +class ipcClient; + +// +// upper limit on the number of active connections +// XXX may want to make this more dynamic +// +#define IPC_MAX_CLIENTS 10000 + +// +// array of connected clients +// +extern ipcClient *ipcClients; +extern int ipcClientCount; + +// +// platform specific send message function, takes ownership of |msg|. +// +PRStatus IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg); + +// +// notify parent that it can connect to the daemon. +// +void IPC_NotifyParent(); + +#endif // !ipcdPrivate_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp new file mode 100644 index 00000000..10618110 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp @@ -0,0 +1,77 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@meer.net> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ipcd.h" +#include "ipcdPrivate.h" +#include "ipcLog.h" + +#include "prerror.h" + +//----------------------------------------------------------------------------- +// use this file as a template to add server-side IPC connectivity. +// +// NOTE: if your platform supports local domain TCP sockets, then you should +// be able to make use of ipcConnectionUnix.cpp. +//----------------------------------------------------------------------------- + +// these variables are declared in ipcdPrivate.h and must be initialized by +// when the daemon starts up. +ipcClient *ipcClients = NULL; +int ipcClientCount = 0; + +PRStatus +IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg) +{ + const char notimplemented[] = "IPC_PlatformSendMsg not implemented"; + PR_SetErrorText(sizeof(notimplemented), notimplemented); + return PR_FAILURE; +} + +int main(int argc, char **argv) +{ + IPC_InitLog("###"); + + LOG(("daemon started...\n")); + + /* + IPC_InitModuleReg(argv[0]); + IPC_ShutdownModuleReg(); + */ + + // let the parent process know that we are up-and-running + IPC_NotifyParent(); + return 0; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp new file mode 100644 index 00000000..026e9e52 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp @@ -0,0 +1,600 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(VBOX) && !defined(XP_OS2) +# include <sys/resource.h> +# include <errno.h> +#endif + +#ifdef VBOX +# include <iprt/initterm.h> +#endif + +#include "prio.h" +#include "prerror.h" +#include "prthread.h" +#include "prinrval.h" +#include "plstr.h" +#include "prprf.h" + +#include "ipcConfig.h" +#include "ipcLog.h" +#include "ipcMessage.h" +#include "ipcClient.h" +#include "ipcModuleReg.h" +#include "ipcdPrivate.h" +#include "ipcd.h" + +#if 0 +static void +IPC_Sleep(int seconds) +{ + while (seconds > 0) { + LOG(("\rsleeping for %d seconds...", seconds)); + PR_Sleep(PR_SecondsToInterval(1)); + --seconds; + } + LOG(("\ndone sleeping\n")); +} +#endif + +//----------------------------------------------------------------------------- +// ipc directory and locking... +//----------------------------------------------------------------------------- + +// +// advisory file locking is used to ensure that only one IPC daemon is active +// and bound to the local domain socket at a time. +// +// XXX this code does not work on OS/2. +// +#if !defined(XP_OS2) +#define IPC_USE_FILE_LOCK +#endif + +#ifdef IPC_USE_FILE_LOCK + +enum Status +{ + EOk = 0, + ELockFileOpen = -1, + ELockFileLock = -2, + ELockFileOwner = -3, +}; + +static int ipcLockFD = 0; + +static Status AcquireDaemonLock(const char *baseDir) +{ + const char lockName[] = "lock"; + + int dirLen = strlen(baseDir); + int len = dirLen // baseDir + + 1 // "/" + + sizeof(lockName); // "lock" + + char *lockFile = (char *) malloc(len); + memcpy(lockFile, baseDir, dirLen); + lockFile[dirLen] = '/'; + memcpy(lockFile + dirLen + 1, lockName, sizeof(lockName)); + +#ifdef VBOX + // + // Security checks for the directory + // + struct stat st; + if (stat(baseDir, &st) == -1) + { + printf("Cannot stat '%s'.\n", baseDir); + return ELockFileOwner; + } + + if (st.st_uid != getuid() && st.st_uid != geteuid()) + { + printf("Wrong owner (%d) of '%s'", st.st_uid, baseDir); + if ( !stat("/tmp", &st) + && (st.st_mode & 07777) != 01777) + printf(" -- check /tmp permissions (%o should be 1777)\n", + st.st_mode & 07777); + printf(".\n"); + return ELockFileOwner; + } + + if (st.st_mode != (S_IRUSR | S_IWUSR | S_IXUSR | S_IFDIR)) + { + printf("Wrong mode (%o) of '%s'", st.st_mode, baseDir); + if ( !stat("/tmp", &st) + && (st.st_mode & 07777) != 01777) + printf(" -- check /tmp permissions (%o should be 1777)\n", + st.st_mode & 07777); + printf(".\n"); + return ELockFileOwner; + } +#endif + + // + // open lock file. it remains open until we shutdown. + // + ipcLockFD = open(lockFile, O_WRONLY|O_CREAT, S_IWUSR|S_IRUSR); + +#ifndef VBOX + free(lockFile); +#endif + + if (ipcLockFD == -1) + return ELockFileOpen; + +#ifdef VBOX + // + // Security checks for the lock file + // + if (fstat(ipcLockFD, &st) == -1) + { + printf("Cannot stat '%s'.\n", lockFile); + free(lockFile); + return ELockFileOwner; + } + + if (st.st_uid != getuid() && st.st_uid != geteuid()) + { + printf("Wrong owner (%d) of '%s'.\n", st.st_uid, lockFile); + free(lockFile); + return ELockFileOwner; + } + + if (st.st_mode != (S_IRUSR | S_IWUSR | S_IFREG)) + { + printf("Wrong mode (%o) of '%s'.\n", st.st_mode, lockFile); + free(lockFile); + return ELockFileOwner; + } + + free(lockFile); +#endif + + // + // we use fcntl for locking. assumption: filesystem should be local. + // this API is nice because the lock will be automatically released + // when the process dies. it will also be released when the file + // descriptor is closed. + // + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_len = 0; + lock.l_whence = SEEK_SET; + if (fcntl(ipcLockFD, F_SETLK, &lock) == -1) + return ELockFileLock; + + // + // truncate lock file once we have exclusive access to it. + // + ftruncate(ipcLockFD, 0); + + // + // write our PID into the lock file (this just seems like a good idea... + // no real purpose otherwise). + // + char buf[32]; + int nb = PR_snprintf(buf, sizeof(buf), "%u\n", (unsigned long) getpid()); + write(ipcLockFD, buf, nb); + + return EOk; +} + +static Status InitDaemonDir(const char *socketPath) +{ + LOG(("InitDaemonDir [sock=%s]\n", socketPath)); + + char *baseDir = PL_strdup(socketPath); + + // + // make sure IPC directory exists (XXX this should be recursive) + // + char *p = strrchr(baseDir, '/'); + if (p) + p[0] = '\0'; + mkdir(baseDir, 0700); + + // + // if we can't acquire the daemon lock, then another daemon + // must be active, so bail. + // + Status status = AcquireDaemonLock(baseDir); + + PL_strfree(baseDir); + + if (status == EOk) { + // delete an existing socket to prevent bind from failing. + unlink(socketPath); + } + return status; +} + +static void ShutdownDaemonDir() +{ + LOG(("ShutdownDaemonDir\n")); + + // deleting directory and files underneath it allows another process + // to think it has exclusive access. better to just leave the hidden + // directory in /tmp and let the OS clean it up via the usual tmpdir + // cleanup cron job. + + // this removes the advisory lock, allowing other processes to acquire it. + if (ipcLockFD) { + close(ipcLockFD); + ipcLockFD = 0; + } +} + +#endif // IPC_USE_FILE_LOCK + +//----------------------------------------------------------------------------- +// poll list +//----------------------------------------------------------------------------- + +// +// declared in ipcdPrivate.h +// +ipcClient *ipcClients = NULL; +int ipcClientCount = 0; + +// +// the first element of this array is always zero; this is done so that the +// k'th element of ipcClientArray corresponds to the k'th element of +// ipcPollList. +// +static ipcClient ipcClientArray[IPC_MAX_CLIENTS + 1]; + +// +// element 0 contains the "server socket" +// +static PRPollDesc ipcPollList[IPC_MAX_CLIENTS + 1]; + +//----------------------------------------------------------------------------- + +static int AddClient(PRFileDesc *fd) +{ + if (ipcClientCount == IPC_MAX_CLIENTS) { + LOG(("reached maximum client limit\n")); + return -1; + } + + int pollCount = ipcClientCount + 1; + + ipcClientArray[pollCount].Init(); + + ipcPollList[pollCount].fd = fd; + ipcPollList[pollCount].in_flags = PR_POLL_READ; + ipcPollList[pollCount].out_flags = 0; + + ++ipcClientCount; + return 0; +} + +static int RemoveClient(int clientIndex) +{ + PRPollDesc *pd = &ipcPollList[clientIndex]; + + PR_Close(pd->fd); + + ipcClientArray[clientIndex].Finalize(); + + // + // keep the clients and poll_fds contiguous; move the last one into + // the spot held by the one that is going away. + // + int toIndex = clientIndex; + int fromIndex = ipcClientCount; + if (fromIndex != toIndex) { + memcpy(&ipcClientArray[toIndex], &ipcClientArray[fromIndex], sizeof(ipcClient)); + memcpy(&ipcPollList[toIndex], &ipcPollList[fromIndex], sizeof(PRPollDesc)); + } + + // + // zero out the old entries. + // + memset(&ipcClientArray[fromIndex], 0, sizeof(ipcClient)); + memset(&ipcPollList[fromIndex], 0, sizeof(PRPollDesc)); + + --ipcClientCount; + return 0; +} + +//----------------------------------------------------------------------------- + +static void PollLoop(PRFileDesc *listenFD) +{ + // the first element of ipcClientArray is unused. + memset(ipcClientArray, 0, sizeof(ipcClientArray)); + ipcClients = ipcClientArray + 1; + ipcClientCount = 0; + + ipcPollList[0].fd = listenFD; + ipcPollList[0].in_flags = PR_POLL_EXCEPT | PR_POLL_READ; + + while (1) { + PRInt32 rv; + PRIntn i; + + int pollCount = ipcClientCount + 1; + + ipcPollList[0].out_flags = 0; + + // + // poll + // + // timeout after 5 minutes. if no connections after timeout, then + // exit. this timeout ensures that we don't stay resident when no + // clients are interested in connecting after spawning the daemon. + // + // XXX add #define for timeout value + // + LOG(("calling PR_Poll [pollCount=%d]\n", pollCount)); + rv = PR_Poll(ipcPollList, pollCount, PR_SecondsToInterval(60 * 5)); + if (rv == -1) { + LOG(("PR_Poll failed [%d]\n", PR_GetError())); + return; + } + + if (rv > 0) { + // + // process clients that are ready + // + for (i = 1; i < pollCount; ++i) { + if (ipcPollList[i].out_flags != 0) { + ipcPollList[i].in_flags = + ipcClientArray[i].Process(ipcPollList[i].fd, + ipcPollList[i].out_flags); + ipcPollList[i].out_flags = 0; + } + } + + // + // cleanup any dead clients (indicated by a zero in_flags) + // + for (i = pollCount - 1; i >= 1; --i) { + if (ipcPollList[i].in_flags == 0) + RemoveClient(i); + } + + // + // check for new connection + // + if (ipcPollList[0].out_flags & PR_POLL_READ) { + LOG(("got new connection\n")); + + PRNetAddr clientAddr; + memset(&clientAddr, 0, sizeof(clientAddr)); + PRFileDesc *clientFD; + + // @todo : We need to handle errors from accept() especially something like + // EMFILE, which happens when we run out of file descriptors. + // and puts XPCOMIPCD in a poll/accept endless loop! + clientFD = PR_Accept(listenFD, &clientAddr, PR_INTERVAL_NO_WAIT); + if (clientFD == NULL) { + // ignore this error... perhaps the client disconnected. + LOG(("PR_Accept failed [%d]\n", PR_GetError())); + } + else { + // make socket non-blocking + PRSocketOptionData opt; + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_TRUE; + PR_SetSocketOption(clientFD, &opt); + + if (AddClient(clientFD) != 0) + PR_Close(clientFD); + } + } + } + + // + // shutdown if no clients + // + if (ipcClientCount == 0) { + LOG(("shutting down\n")); + break; + } + } +} + +//----------------------------------------------------------------------------- + +PRStatus +IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg) +{ + LOG(("IPC_PlatformSendMsg\n")); + + // + // must copy message onto send queue. + // + client->EnqueueOutboundMsg(msg); + + // + // since our Process method may have already been called, we must ensure + // that the PR_POLL_WRITE flag is set. + // + int clientIndex = client - ipcClientArray; + ipcPollList[clientIndex].in_flags |= PR_POLL_WRITE; + + return PR_SUCCESS; +} + +//----------------------------------------------------------------------------- + +int main(int argc, char **argv) +{ + PRFileDesc *listenFD = NULL; + PRNetAddr addr; + +#ifdef VBOX + /* Set up the runtime without loading the support driver. */ + RTR3InitExe(argc, &argv, 0); +#endif + + // + // ignore SIGINT so <ctrl-c> from terminal only kills the client + // which spawned this daemon. + // + signal(SIGINT, SIG_IGN); + // XXX block others? check cartman + + // ensure strict file permissions + umask(0077); + + IPC_InitLog("###"); + + LOG(("daemon started...\n")); + + //XXX uncomment these lines to test slow starting daemon + //IPC_Sleep(2); + + // set socket address + addr.local.family = PR_AF_LOCAL; + if (argc < 2) + IPC_GetDefaultSocketPath(addr.local.path, sizeof(addr.local.path)); + else + PL_strncpyz(addr.local.path, argv[1], sizeof(addr.local.path)); + +#ifdef IPC_USE_FILE_LOCK + Status status = InitDaemonDir(addr.local.path); + if (status != EOk) { + if (status == ELockFileLock) { + LOG(("Another daemon is already running, exiting.\n")); + // send a signal to the blocked parent to indicate success + IPC_NotifyParent(); + return 0; + } + else { + LOG(("InitDaemonDir failed (status=%d)\n", status)); + // don't notify the parent to cause it to fail in PR_Read() after + // we terminate +#ifdef VBOX + if (status != ELockFileOwner) + printf("Cannot create a lock file for '%s'.\n" + "Check permissions.\n", addr.local.path); +#endif + return 0; + } + } +#endif + + listenFD = PR_OpenTCPSocket(PR_AF_LOCAL); + if (!listenFD) { + LOG(("PR_OpenTCPSocket failed [%d]\n", PR_GetError())); + } + else if (PR_Bind(listenFD, &addr) != PR_SUCCESS) { + LOG(("PR_Bind failed [%d]\n", PR_GetError())); + } + else { + IPC_InitModuleReg(argv[0]); + +#ifdef VBOX + // Use large backlog, as otherwise local sockets can reject connection + // attempts. Usually harmless, but causes an unnecessary start attempt + // of IPCD (which will terminate straight away), and the next attempt + // usually succeeds. But better avoid unnecessary activities. + if (PR_Listen(listenFD, 128) != PR_SUCCESS) { +#else /* !VBOX */ + if (PR_Listen(listenFD, 5) != PR_SUCCESS) { +#endif /* !VBOX */ + LOG(("PR_Listen failed [%d]\n", PR_GetError())); + } + else { +#ifndef VBOX + // redirect all standard file descriptors to /dev/null for + // proper daemonizing + PR_Close(PR_STDIN); + PR_Open("/dev/null", O_RDONLY, 0); + PR_Close(PR_STDOUT); + PR_Open("/dev/null", O_WRONLY, 0); + PR_Close(PR_STDERR); + PR_Open("/dev/null", O_WRONLY, 0); +#endif + + IPC_NotifyParent(); + +#if defined(VBOX) && !defined(XP_OS2) + // Increase the file table size to 10240 or as high as possible. + struct rlimit lim; + if (getrlimit(RLIMIT_NOFILE, &lim) == 0) + { + if ( lim.rlim_cur < 10240 + && lim.rlim_cur < lim.rlim_max) + { + lim.rlim_cur = lim.rlim_max <= 10240 ? lim.rlim_max : 10240; + if (setrlimit(RLIMIT_NOFILE, &lim) == -1) + printf("WARNING: failed to increase file descriptor limit. (%d)\n", errno); + } + } + else + printf("WARNING: failed to obtain per-process file-descriptor limit (%d).\n", errno); +#endif + + PollLoop(listenFD); + } + + IPC_ShutdownModuleReg(); + } + + //IPC_Sleep(5); + +#ifdef IPC_USE_FILE_LOCK + // it is critical that we release the lock before closing the socket, + // otherwise, a client might launch another daemon that would be unable + // to acquire the lock and would then leave the client without a daemon. + + ShutdownDaemonDir(); +#endif + + if (listenFD) { + LOG(("closing socket\n")); + PR_Close(listenFD); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp new file mode 100644 index 00000000..f89fba06 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp @@ -0,0 +1,408 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <windows.h> + +#include "prthread.h" + +#include "ipcConfig.h" +#include "ipcLog.h" +#include "ipcMessage.h" +#include "ipcClient.h" +#include "ipcModuleReg.h" +#include "ipcdPrivate.h" +#include "ipcd.h" +#include "ipcm.h" + +// +// declared in ipcdPrivate.h +// +ipcClient *ipcClients = NULL; +int ipcClientCount = 0; + +static ipcClient ipcClientArray[IPC_MAX_CLIENTS]; + +static HWND ipcHwnd = NULL; +static PRBool ipcShutdown = PR_FALSE; + +#define IPC_PURGE_TIMER_ID 1 +#define IPC_WM_SENDMSG (WM_USER + 1) +#define IPC_WM_SHUTDOWN (WM_USER + 2) + +//----------------------------------------------------------------------------- +// client array manipulation +//----------------------------------------------------------------------------- + +static void +RemoveClient(ipcClient *client) +{ + LOG(("RemoveClient\n")); + + int clientIndex = client - ipcClientArray; + + client->Finalize(); + + // + // move last ipcClient object down into the spot occupied by this client. + // + int fromIndex = ipcClientCount - 1; + int toIndex = clientIndex; + if (toIndex != fromIndex) + memcpy(&ipcClientArray[toIndex], &ipcClientArray[fromIndex], sizeof(ipcClient)); + + memset(&ipcClientArray[fromIndex], 0, sizeof(ipcClient)); + + --ipcClientCount; + LOG((" num clients = %u\n", ipcClientCount)); + + if (ipcClientCount == 0) { + LOG((" shutting down...\n")); + KillTimer(ipcHwnd, IPC_PURGE_TIMER_ID); + PostQuitMessage(0); + ipcShutdown = PR_TRUE; + } +} + +static void +PurgeStaleClients() +{ + if (ipcClientCount == 0) + return; + + LOG(("PurgeStaleClients [num-clients=%u]\n", ipcClientCount)); + // + // walk the list of supposedly active clients, and verify the existance of + // their respective message windows. + // + char wName[IPC_CLIENT_WINDOW_NAME_MAXLEN]; + for (int i=ipcClientCount-1; i>=0; --i) { + ipcClient *client = &ipcClientArray[i]; + + LOG((" checking client at index %u [client-id=%u pid=%u]\n", + i, client->ID(), client->PID())); + + IPC_GetClientWindowName(client->PID(), wName); + + // XXX dougt has ideas about how to make this better + + HWND hwnd = FindWindow(IPC_CLIENT_WINDOW_CLASS, wName); + if (!hwnd) { + LOG((" client window not found; removing client!\n")); + RemoveClient(client); + } + } +} + +static ipcClient * +AddClient(HWND hwnd, PRUint32 pid) +{ + LOG(("AddClient\n")); + + // + // before adding a new client, verify that all existing clients are + // still up and running. remove any stale clients. + // + PurgeStaleClients(); + + if (ipcClientCount == IPC_MAX_CLIENTS) { + LOG((" reached maximum client count!\n")); + return NULL; + } + + ipcClient *client = &ipcClientArray[ipcClientCount]; + client->Init(); + client->SetHwnd(hwnd); + client->SetPID(pid); // XXX one function instead of 3 + + ++ipcClientCount; + LOG((" num clients = %u\n", ipcClientCount)); + + if (ipcClientCount == 1) + SetTimer(ipcHwnd, IPC_PURGE_TIMER_ID, 1000, NULL); + + return client; +} + +static ipcClient * +GetClientByPID(PRUint32 pid) +{ + for (int i=0; i<ipcClientCount; ++i) { + if (ipcClientArray[i].PID() == pid) + return &ipcClientArray[i]; + } + return NULL; +} + +//----------------------------------------------------------------------------- +// message processing +//----------------------------------------------------------------------------- + +static void +ProcessMsg(HWND hwnd, PRUint32 pid, const ipcMessage *msg) +{ + LOG(("ProcessMsg [pid=%u len=%u]\n", pid, msg->MsgLen())); + + ipcClient *client = GetClientByPID(pid); + + if (client) { + // + // if this is an IPCM "client hello" message, then reset the client + // instance object. + // + if (msg->Target().Equals(IPCM_TARGET) && + IPCM_GetType(msg) == IPCM_MSG_REQ_CLIENT_HELLO) { + RemoveClient(client); + client = NULL; + } + } + + if (client == NULL) { + client = AddClient(hwnd, pid); + if (!client) + return; + } + + IPC_DispatchMsg(client, msg); +} + +//----------------------------------------------------------------------------- + +PRStatus +IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg) +{ + LOG(("IPC_PlatformSendMsg [clientID=%u clientPID=%u]\n", + client->ID(), client->PID())); + + // use PostMessage to make this asynchronous; otherwise we might get + // some wierd SendMessage recursion between processes. + + WPARAM wParam = (WPARAM) client->Hwnd(); + LPARAM lParam = (LPARAM) msg; + if (!PostMessage(ipcHwnd, IPC_WM_SENDMSG, wParam, lParam)) { + LOG(("PostMessage failed\n")); + delete msg; + return PR_FAILURE; + } + return PR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// windows message loop +//----------------------------------------------------------------------------- + +static LRESULT CALLBACK +WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LOG(("got message [msg=%x wparam=%x lparam=%x]\n", uMsg, wParam, lParam)); + + if (uMsg == WM_COPYDATA) { + if (ipcShutdown) { + LOG(("ignoring message b/c daemon is shutting down\n")); + return TRUE; + } + COPYDATASTRUCT *cd = (COPYDATASTRUCT *) lParam; + if (cd && cd->lpData) { + ipcMessage msg; + PRUint32 bytesRead; + PRBool complete; + // XXX avoid extra malloc + PRStatus rv = msg.ReadFrom((const char *) cd->lpData, cd->cbData, + &bytesRead, &complete); + if (rv == PR_SUCCESS && complete) { + // + // grab client PID and hwnd. + // + ProcessMsg((HWND) wParam, (PRUint32) cd->dwData, &msg); + } + else + LOG(("ignoring malformed message\n")); + } + return TRUE; + } + + if (uMsg == IPC_WM_SENDMSG) { + HWND hWndDest = (HWND) wParam; + ipcMessage *msg = (ipcMessage *) lParam; + + COPYDATASTRUCT cd; + cd.dwData = GetCurrentProcessId(); + cd.cbData = (DWORD) msg->MsgLen(); + cd.lpData = (PVOID) msg->MsgBuf(); + + LOG(("calling SendMessage...\n")); + SendMessage(hWndDest, WM_COPYDATA, (WPARAM) hWnd, (LPARAM) &cd); + LOG((" done.\n")); + + delete msg; + return 0; + } + + if (uMsg == WM_TIMER) { + PurgeStaleClients(); + return 0; + } + +#if 0 + if (uMsg == IPC_WM_SHUTDOWN) { + // + // since this message is handled asynchronously, it is possible + // that other clients may have come online since this was issued. + // in which case, we need to ignore this message. + // + if (ipcClientCount == 0) { + ipcShutdown = PR_TRUE; + PostQuitMessage(0); + } + return 0; + } +#endif + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +//----------------------------------------------------------------------------- +// daemon startup synchronization +//----------------------------------------------------------------------------- + +static HANDLE ipcSyncEvent; + +static PRBool +AcquireLock() +{ + ipcSyncEvent = CreateEvent(NULL, FALSE, FALSE, + IPC_SYNC_EVENT_NAME); + if (!ipcSyncEvent) { + LOG(("CreateEvent failed [%u]\n", GetLastError())); + return PR_FALSE; + } + + // check to see if event already existed prior to this call. + if (GetLastError() == ERROR_ALREADY_EXISTS) { + LOG((" lock already set; exiting...\n")); + return PR_FALSE; + } + + LOG((" acquired lock\n")); + return PR_TRUE; +} + +static void +ReleaseLock() +{ + if (ipcSyncEvent) { + LOG(("releasing lock...\n")); + CloseHandle(ipcSyncEvent); + ipcSyncEvent = NULL; + } +} + +//----------------------------------------------------------------------------- +// main +//----------------------------------------------------------------------------- + +#ifdef DEBUG +int +main() +#else +int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) +#endif +{ + IPC_InitLog("###"); + + LOG(("daemon started...\n")); + + if (!AcquireLock()) { + // unblock the parent; it should be able to find the IPC window of the + // other daemon process. + IPC_NotifyParent(); + return 0; + } + + // initialize global data + memset(ipcClientArray, 0, sizeof(ipcClientArray)); + ipcClients = ipcClientArray; + ipcClientCount = 0; + + // create message window up front... + WNDCLASS wc; + memset(&wc, 0, sizeof(wc)); + wc.lpfnWndProc = WindowProc; + wc.lpszClassName = IPC_WINDOW_CLASS; + + RegisterClass(&wc); + + ipcHwnd = CreateWindow(IPC_WINDOW_CLASS, IPC_WINDOW_NAME, + 0, 0, 0, 10, 10, NULL, NULL, NULL, NULL); + + // unblock the parent process; it should now look for the IPC window. + IPC_NotifyParent(); + + if (!ipcHwnd) + return -1; + + // load modules relative to the location of the executable... + { + char path[MAX_PATH]; + GetModuleFileName(NULL, path, sizeof(path)); + IPC_InitModuleReg(path); + } + + LOG(("entering message loop...\n")); + MSG msg; + while (GetMessage(&msg, ipcHwnd, 0, 0)) + DispatchMessage(&msg); + + // unload modules + IPC_ShutdownModuleReg(); + + // + // we release the daemon lock before destroying the window because the + // absence of our window is what will cause clients to try to spawn the + // daemon. + // + ReleaseLock(); + + //LOG(("sleeping 5 seconds...\n")); + //PR_Sleep(PR_SecondsToInterval(5)); + + LOG(("destroying message window...\n")); + DestroyWindow(ipcHwnd); + ipcHwnd = NULL; + + LOG(("exiting\n")); + return 0; +} |