From d34899750d576637787ee165af6749e247832b20 Mon Sep 17 00:00:00 2001 From: "darin%netscape.com" Date: Thu, 31 Oct 2002 08:19:27 +0000 Subject: [PATCH] adding IPC framework -- NOT PART OF THE BUILD --- modules/ipc/Makefile.in | 31 ++ modules/ipc/README | 12 + modules/ipc/build/Makefile.in | 75 ++++ modules/ipc/build/ipcCID.h | 63 +++ modules/ipc/build/ipcModule.cpp | 72 ++++ modules/ipc/common/Makefile.in | 66 +++ modules/ipc/common/ipcConfig.h | 71 ++++ modules/ipc/common/ipcMessage.cpp | 245 +++++++++++ modules/ipc/common/ipcMessage.h | 177 ++++++++ modules/ipc/common/ipcMessageQ.cpp | 76 ++++ modules/ipc/common/ipcMessageQ.h | 88 ++++ modules/ipc/common/ipcm.cpp | 248 +++++++++++ modules/ipc/common/ipcm.h | 174 ++++++++ modules/ipc/daemon/Makefile.in | 87 ++++ modules/ipc/daemon/ipcClient.cpp | 191 +++++++++ modules/ipc/daemon/ipcClient.h | 81 ++++ modules/ipc/daemon/ipcCommandModule.cpp | 117 ++++++ modules/ipc/daemon/ipcCommandModule.h | 45 ++ modules/ipc/daemon/ipcModule.h | 95 +++++ modules/ipc/daemon/ipcModuleReg.cpp | 173 ++++++++ modules/ipc/daemon/ipcModuleReg.h | 49 +++ modules/ipc/daemon/ipcd.cpp | 415 ++++++++++++++++++ modules/ipc/daemon/ipcd.h | 110 +++++ modules/ipc/public/Makefile.in | 52 +++ modules/ipc/public/ipcIService.idl | 209 +++++++++ modules/ipc/src/Makefile.in | 65 +++ modules/ipc/src/ipcService.cpp | 193 +++++++++ modules/ipc/src/ipcService.h | 75 ++++ modules/ipc/src/ipcSocketProvider.cpp | 64 +++ modules/ipc/src/ipcSocketProvider.h | 53 +++ modules/ipc/src/ipcTransport.cpp | 537 ++++++++++++++++++++++++ modules/ipc/src/ipcTransport.h | 177 ++++++++ modules/ipc/test/Makefile.in | 54 +++ modules/ipc/test/TestIPC.cpp | 207 +++++++++ modules/ipc/testmodule/Makefile.in | 84 ++++ modules/ipc/testmodule/TestModule.cpp | 51 +++ 36 files changed, 4582 insertions(+) create mode 100644 modules/ipc/Makefile.in create mode 100644 modules/ipc/README create mode 100644 modules/ipc/build/Makefile.in create mode 100644 modules/ipc/build/ipcCID.h create mode 100644 modules/ipc/build/ipcModule.cpp create mode 100644 modules/ipc/common/Makefile.in create mode 100644 modules/ipc/common/ipcConfig.h create mode 100644 modules/ipc/common/ipcMessage.cpp create mode 100644 modules/ipc/common/ipcMessage.h create mode 100644 modules/ipc/common/ipcMessageQ.cpp create mode 100644 modules/ipc/common/ipcMessageQ.h create mode 100644 modules/ipc/common/ipcm.cpp create mode 100644 modules/ipc/common/ipcm.h create mode 100644 modules/ipc/daemon/Makefile.in create mode 100644 modules/ipc/daemon/ipcClient.cpp create mode 100644 modules/ipc/daemon/ipcClient.h create mode 100644 modules/ipc/daemon/ipcCommandModule.cpp create mode 100644 modules/ipc/daemon/ipcCommandModule.h create mode 100644 modules/ipc/daemon/ipcModule.h create mode 100644 modules/ipc/daemon/ipcModuleReg.cpp create mode 100644 modules/ipc/daemon/ipcModuleReg.h create mode 100644 modules/ipc/daemon/ipcd.cpp create mode 100644 modules/ipc/daemon/ipcd.h create mode 100644 modules/ipc/public/Makefile.in create mode 100644 modules/ipc/public/ipcIService.idl create mode 100644 modules/ipc/src/Makefile.in create mode 100644 modules/ipc/src/ipcService.cpp create mode 100644 modules/ipc/src/ipcService.h create mode 100644 modules/ipc/src/ipcSocketProvider.cpp create mode 100644 modules/ipc/src/ipcSocketProvider.h create mode 100644 modules/ipc/src/ipcTransport.cpp create mode 100644 modules/ipc/src/ipcTransport.h create mode 100644 modules/ipc/test/Makefile.in create mode 100644 modules/ipc/test/TestIPC.cpp create mode 100644 modules/ipc/testmodule/Makefile.in create mode 100644 modules/ipc/testmodule/TestModule.cpp diff --git a/modules/ipc/Makefile.in b/modules/ipc/Makefile.in new file mode 100644 index 000000000000..1da79efbd2fc --- /dev/null +++ b/modules/ipc/Makefile.in @@ -0,0 +1,31 @@ +# +# 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.org code +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 2001 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +DIRS = common daemon testmodule public src build test + +include $(topsrcdir)/config/rules.mk diff --git a/modules/ipc/README b/modules/ipc/README new file mode 100644 index 000000000000..484f39174e75 --- /dev/null +++ b/modules/ipc/README @@ -0,0 +1,12 @@ +DAEMON ONLY DIRECTORIES: + daemon/ + testmodule/ + +CLIENT ONLY DIRECTORIES: + public/ + src/ + build/ + test/ + +SHARED CODE DIRECTORY: + common/ diff --git a/modules/ipc/build/Makefile.in b/modules/ipc/build/Makefile.in new file mode 100644 index 000000000000..9bef60b94231 --- /dev/null +++ b/modules/ipc/build/Makefile.in @@ -0,0 +1,75 @@ +# ***** 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 +# +# 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 = ipc +LIBRARY_NAME = ipc +EXPORT_LIBRARY = 1 +IS_COMPONENT = 1 +MODULE_NAME = ipc +REQUIRES = xpcom \ + string \ + necko \ + ipc \ + $(NULL) + +CPPSRCS = ipcModule.cpp +EXPORTS = ipcCID.h + +SHARED_LIBRARY_LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)ipc_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)ipccom_s.$(LIB_SUFFIX) \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../src \ + -I$(srcdir)/../util \ + $(NULL) + +EXTRA_DSO_LDOPTS = \ + $(LIBS_DIR) \ + $(EXTRA_DSO_LIBS) \ + $(MOZ_COMPONENT_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/modules/ipc/build/ipcCID.h b/modules/ipc/build/ipcCID.h new file mode 100644 index 000000000000..127a418f01a1 --- /dev/null +++ b/modules/ipc/build/ipcCID.h @@ -0,0 +1,63 @@ +/* ***** 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 + * + * 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 ipcCID_h__ +#define ipcCID_h__ + +#define IPC_SERVICE_CLASSNAME \ + "ipcService" +#define IPC_SERVICE_CONTRACTID \ + "@mozilla.org/ipc/service;1" +#define IPC_SERVICE_CID \ +{ /* 9f12676a-5168-4a08-beb8-edf8a593a1ca */ \ + 0x9f12676a, \ + 0x5168, \ + 0x4a08, \ + {0xbe, 0xb8, 0xed, 0xf8, 0xa5, 0x93, 0xa1, 0xca} \ +} + +#define IPC_SOCKETPROVIDER_CLASSNAME \ + "ipcSocketProvider" +#define IPC_SOCKETPROVIDER_CID \ +{ /* b888f500-ab5d-459c-aab0-bc61e844a503 */ \ + 0xb888f500, \ + 0xab5d, \ + 0x459c, \ + {0xaa, 0xb0, 0xbc, 0x61, 0xe8, 0x44, 0xa5, 0x03} \ +} + +#endif // !ipcCID_h__ diff --git a/modules/ipc/build/ipcModule.cpp b/modules/ipc/build/ipcModule.cpp new file mode 100644 index 000000000000..9527bd4f9fd3 --- /dev/null +++ b/modules/ipc/build/ipcModule.cpp @@ -0,0 +1,72 @@ +/* ***** 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 + * + * 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 "nsIGenericFactory.h" +#include "ipcService.h" +#include "ipcSocketProvider.h" +#include "ipcCID.h" + +//////////////////////////////////////////////////////////////////////// +// Define the contructor function for the objects +// +// NOTE: This creates an instance of objects by using the default constructor +// +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcService, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR(ipcSocketProvider) + +//////////////////////////////////////////////////////////////////////// +// Define a table of CIDs implemented by this module along with other +// information like the function to create an instance, contractid, and +// class name. +// +static const nsModuleComponentInfo components[] = { + { IPC_SERVICE_CLASSNAME, + IPC_SERVICE_CID, + IPC_SERVICE_CONTRACTID, + ipcServiceConstructor, }, + { IPC_SOCKETPROVIDER_CLASSNAME, + IPC_SOCKETPROVIDER_CID, + NS_NETWORK_SOCKET_CONTRACTID_PREFIX "ipc", + ipcSocketProviderConstructor, }, +}; + + +//////////////////////////////////////////////////////////////////////// +// Implement the NSGetModule() exported function for your module +// and the entire implementation of the module object. +// +NS_IMPL_NSGETMODULE(ipcModule, components) diff --git a/modules/ipc/common/Makefile.in b/modules/ipc/common/Makefile.in new file mode 100644 index 000000000000..bc9f3d9672ce --- /dev/null +++ b/modules/ipc/common/Makefile.in @@ -0,0 +1,66 @@ +# ***** 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 +# +# 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 = ipc +LIBRARY_NAME = ipccom_s +EXPORT_LIBRARY = 1 +FORCE_STATIC_LIB = 1 +MODULE_NAME = ipc + +REQUIRES = \ + xpcom \ + $(NULL) + +CPPSRCS = \ + ipcMessage.cpp \ + ipcMessageQ.cpp \ + ipcm.cpp + +EXPORTS = \ + ipcMessage.h \ + ipcMessageQ.h \ + ipcm.h \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/modules/ipc/common/ipcConfig.h b/modules/ipc/common/ipcConfig.h new file mode 100644 index 000000000000..6c235148b55f --- /dev/null +++ b/modules/ipc/common/ipcConfig.h @@ -0,0 +1,71 @@ +/* ***** 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 + * + * 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 ipcProto_h__ +#define ipcProto_h__ + +#if defined(XP_WIN) +// +// XXX since win9x/me doesn't support named pipes, we resort to using a +// localhost TCP/IP socket (for now). this is not a great solution for +// several reasons: +// (1) we have to agree on a port number. +// (2) opens up a big security hole that needs to be plugged somehow. +// +// we should probably use WM_COPYDATA instead. +// +#define IPC_USE_INET 1 +#define IPC_PORT 14400 +#define IPC_SOCKET_TYPE nsnull +#define IPC_DEFAULT_SOCKET_PATH "" +#define IPC_DAEMON_APP_NAME "mozipcd.exe" +#define IPC_PATH_SEP_CHAR '\\' +#define IPC_PATH_SEP_CHAR_S "\\" +#else +// +// use UNIX domain socket +// +#define IPC_PORT 0 +#define IPC_SOCKET_TYPE "ipc" +#define IPC_DEFAULT_SOCKET_PATH "/tmp/sock" +#define IPC_DAEMON_APP_NAME "mozipcd" +#define IPC_PATH_SEP_CHAR '/' +#define IPC_PATH_SEP_CHAR_S "/" +#endif + + +#endif // !ipcProto_h__ diff --git a/modules/ipc/common/ipcMessage.cpp b/modules/ipc/common/ipcMessage.cpp new file mode 100644 index 000000000000..e50ae92d7c40 --- /dev/null +++ b/modules/ipc/common/ipcMessage.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 + * + * 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 +#include +#include "prlog.h" +#include "ipcMessage.h" + +ipcMessage::~ipcMessage() +{ + if (mMsgHdr) + free(mMsgHdr); +} + +void +ipcMessage::Reset() +{ + if (mMsgHdr) { + free(mMsgHdr); + mMsgHdr = NULL; + } + + mMsgOffset = 0; + mMsgComplete = PR_FALSE; +} + +ipcMessage * +ipcMessage::Clone() +{ + ipcMessage *clone = new ipcMessage(); + if (!clone) + return NULL; + + // copy buf if non-null + if (mMsgHdr) { + clone->mMsgHdr = (ipcMessageHeader *) malloc(mMsgHdr->mLen); + memcpy(clone->mMsgHdr, mMsgHdr, mMsgHdr->mLen); + } + else + clone->mMsgHdr = NULL; + + clone->mMsgOffset = mMsgOffset; + clone->mMsgComplete = mMsgComplete; + + return clone; +} + +PRStatus +ipcMessage::Init(const nsID &target, const char *data, PRUint32 dataLen) +{ + if (mMsgHdr) + free(mMsgHdr); + mMsgComplete = PR_FALSE; + + // allocate message data + PRUint32 msgLen = IPC_MSG_HEADER_SIZE + dataLen; + mMsgHdr = (ipcMessageHeader *) malloc(msgLen); + if (!mMsgHdr) { + mMsgHdr = NULL; + return PR_FAILURE; + } + + // fill in message data + mMsgHdr->mLen = msgLen; + mMsgHdr->mVersion = IPC_MSG_VERSION; + mMsgHdr->mFlags = 0; + mMsgHdr->mTarget = target; + + if (data) + SetData(0, data, dataLen); + + mMsgComplete = PR_TRUE; + return PR_SUCCESS; +} + +PRStatus +ipcMessage::SetData(PRUint32 offset, const char *data, PRUint32 dataLen) +{ + PR_ASSERT(mMsgHdr != NULL); + + if (offset + dataLen > DataLen()) + return PR_FAILURE; + + memcpy((char *) Data() + offset, data, dataLen); + return PR_SUCCESS; +} + +PRBool +ipcMessage::Equals(const nsID &target, const char *data, PRUint32 dataLen) const +{ + return mMsgComplete && + mMsgHdr->mTarget.Equals(target) && + DataLen() == dataLen && + memcmp(Data(), data, dataLen) == 0; +} + +PRBool +ipcMessage::Equals(const ipcMessage *msg) const +{ + PRUint32 msgLen = MsgLen(); + return mMsgComplete && msg->mMsgComplete && + msgLen == msg->MsgLen() && + memcmp(MsgBuf(), msg->MsgBuf(), msgLen) == 0; +} + +PRStatus +ipcMessage::WriteTo(char *buf, + PRUint32 bufLen, + PRUint32 *bytesWritten, + PRBool *complete) +{ + if (!mMsgComplete) + return PR_FAILURE; + + if (mMsgOffset == MsgLen()) { + *bytesWritten = 0; + *complete = PR_TRUE; + return PR_SUCCESS; + } + + PRUint32 count = MsgLen() - mMsgOffset; + if (count > bufLen) + count = bufLen; + + memcpy(buf, MsgBuf() + mMsgOffset, count); + mMsgOffset += count; + + *bytesWritten = count; + *complete = (mMsgOffset == MsgLen()); + + return PR_SUCCESS; +} + +PRStatus +ipcMessage::ReadFrom(const char *buf, + PRUint32 bufLen, + PRUint32 *bytesRead, + PRBool *complete) +{ + *bytesRead = 0; + + if (mMsgComplete) { + *complete = PR_TRUE; + return PR_SUCCESS; + } + + if (mMsgHdr) { + // appending data to buffer + if (mMsgOffset < sizeof(PRUint32)) { + // we haven't learned the message length yet + if (mMsgOffset + bufLen < sizeof(PRUint32)) { + // we still don't know the length of the message! + memcpy((char *) mMsgHdr + mMsgOffset, buf, bufLen); + mMsgOffset += bufLen; + *bytesRead = bufLen; + *complete = PR_FALSE; + return PR_SUCCESS; + } + else { + // we now have enough data to determine the message length + PRUint32 count = sizeof(PRUint32) - mMsgOffset; + memcpy((char *) MsgBuf() + mMsgOffset, buf, count); + mMsgOffset += count; + buf += count; + bufLen -= count; + *bytesRead = count; + + if (MsgLen() > IPC_MSG_GUESSED_SIZE) { + // realloc message buffer to the correct size + mMsgHdr = (ipcMessageHeader *) realloc(mMsgHdr, MsgLen()); + } + } + } + } + else { + if (bufLen < sizeof(PRUint32)) { + // not enough data available in buffer to determine allocation size + // allocate a partial buffer + PRUint32 msgLen = IPC_MSG_GUESSED_SIZE; + mMsgHdr = (ipcMessageHeader *) malloc(msgLen); + if (!mMsgHdr) + return PR_FAILURE; + memcpy(mMsgHdr, buf, bufLen); + mMsgOffset = bufLen; + *bytesRead = bufLen; + *complete = PR_FALSE; + return PR_SUCCESS; + } + else { + PRUint32 msgLen = *(PRUint32 *) buf; + mMsgHdr = (ipcMessageHeader *) malloc(msgLen); + if (!mMsgHdr) + return PR_FAILURE; + mMsgHdr->mLen = msgLen; + mMsgOffset = 0; + } + } + + // have mMsgHdr at this point + + PRUint32 count = MsgLen() - mMsgOffset; + if (count > bufLen) + count = bufLen; + + memcpy((char *) mMsgHdr + mMsgOffset, buf, count); + mMsgOffset += count; + *bytesRead += count; + + *complete = mMsgComplete = (mMsgOffset == MsgLen()); + return PR_SUCCESS; +} diff --git a/modules/ipc/common/ipcMessage.h b/modules/ipc/common/ipcMessage.h new file mode 100644 index 000000000000..e2e6af535914 --- /dev/null +++ b/modules/ipc/common/ipcMessage.h @@ -0,0 +1,177 @@ +/* ***** 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 + * + * 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 ipcMessage_h__ +#define ipcMessage_h__ + +#include "nsID.h" + +// +// ipc message format: +// +// +------------------------------------+ +// | DWORD : length | +// +------------------+-----------------+ +// | WORD : version | WORD : flags | +// +------------------+-----------------+ +// | nsID : target | +// +------------------------------------+ +// | data | +// +------------------------------------+ +// +// header is 24 bytes. flags are for future use and must be zero in this +// version of the ipc message format. target is a 16 byte UUID indicating +// the intended receiver of this message. +// + +struct ipcMessageHeader +{ + PRUint32 mLen; + PRUint16 mVersion; + PRUint16 mFlags; + nsID mTarget; +}; + +#define IPC_MSG_VERSION (0x1) +#define IPC_MSG_HEADER_SIZE (sizeof(ipcMessageHeader)) +#define IPC_MSG_GUESSED_SIZE (IPC_MSG_HEADER_SIZE + 64) + +//----------------------------------------------------------------------------- +// ipcMessage +//----------------------------------------------------------------------------- + +class ipcMessage +{ +public: + ipcMessage() + : mNext(NULL) + , mMsgHdr(NULL) + , mMsgOffset(0) + , mMsgComplete(PR_FALSE) + { } + ~ipcMessage(); + + // + // reset message to uninitialized state + // + void Reset(); + + // + // create a copy of this message + // + ipcMessage *Clone(); + + // + // initialize message + // + // param: + // topic - message topic string + // data - message data (may be null to leave data uninitialized) + // dataLen - message data len + // + PRStatus Init(const nsID &target, const char *data, PRUint32 dataLen); + + // + // copy data into the message's data section, starting from offset. this + // function can be used to write only a portion of the message's data. + // + // param: + // offset - destination offset + // data - data to write + // dataLen - number of bytes to write + // + PRStatus SetData(PRUint32 offset, const char *data, PRUint32 dataLen); + + // + // if true, the message is complete and the members of the message + // can be accessed. + // + PRBool IsComplete() const { return mMsgComplete; } + + // + // readonly accessors + // + const ipcMessageHeader *Header() const { return mMsgHdr; } + const nsID &Target() const { return mMsgHdr->mTarget; } + const char *Data() const { return (char *) mMsgHdr + IPC_MSG_HEADER_SIZE; } + PRUint32 DataLen() const { return mMsgHdr->mLen - IPC_MSG_HEADER_SIZE; } + const char *MsgBuf() const { return (char *) mMsgHdr; } + PRUint32 MsgLen() const { return mMsgHdr->mLen; } + + // + // message comparison functions + // + // param: + // topic - message topic (may be null) + // data - message data (must not be null) + // dataLen - message data length + // + PRBool Equals(const nsID &target, const char *data, PRUint32 dataLen) const; + PRBool Equals(const ipcMessage *msg) const; + + // + // write the message to a buffer segment; segment need not be large + // enough to hold entire message. called repeatedly. + // + PRStatus WriteTo(char *buf, + PRUint32 bufLen, + PRUint32 *bytesWritten, + PRBool *complete); + + // + // read the message from a buffer segment; segment need not contain + // the entire messgae. called repeatedly. + // + PRStatus ReadFrom(const char *buf, + PRUint32 bufLen, + PRUint32 *bytesRead, + PRBool *complete); + + // + // a message can be added to a singly-linked list. + // + class ipcMessage *mNext; + +private: + ipcMessageHeader *mMsgHdr; + + // XXX document me + PRUint32 mMsgOffset; + PRPackedBool mMsgComplete; +}; + +#endif // !ipcMessage_h__ diff --git a/modules/ipc/common/ipcMessageQ.cpp b/modules/ipc/common/ipcMessageQ.cpp new file mode 100644 index 000000000000..7bad8d292ea8 --- /dev/null +++ b/modules/ipc/common/ipcMessageQ.cpp @@ -0,0 +1,76 @@ +/* ***** 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 + * + * 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 "ipcMessageQ.h" +#include "ipcMessage.h" + +void +ipcMessageQ::Append(ipcMessage *msg) +{ + msg->mNext = NULL; + if (mTail) { + mTail->mNext = msg; + mTail = msg; + } + else + mTail = mHead = msg; +} + +void +ipcMessageQ::AdvanceHead() +{ + mHead = mHead->mNext; + if (!mHead) + mTail = NULL; +} + +void +ipcMessageQ::DeleteFirst() +{ + ipcMessage *first = mHead; + if (first) { + AdvanceHead(); + delete first; + } +} + +void +ipcMessageQ::DeleteAll() +{ + while (mHead) + DeleteFirst(); +} diff --git a/modules/ipc/common/ipcMessageQ.h b/modules/ipc/common/ipcMessageQ.h new file mode 100644 index 000000000000..ec2ad7eacd34 --- /dev/null +++ b/modules/ipc/common/ipcMessageQ.h @@ -0,0 +1,88 @@ +/* ***** 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 + * + * 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 ipcMessageQ_h__ +#define ipcMessageQ_h__ + +#include "prtypes.h" + +class ipcMessage; + +//----------------------------------------------------------------------------- +// simple queue of ipcMessage objects +//----------------------------------------------------------------------------- + +class ipcMessageQ +{ +public: + ipcMessageQ() + : mHead(NULL) + , mTail(NULL) + { } + ~ipcMessageQ() { DeleteAll(); } + + // + // appends msg to the end of the queue. caller loses ownership of |msg|. + // + void Append(ipcMessage *msg); + + // + // removes first element w/o deleting it + // + void RemoveFirst() { if (mHead) AdvanceHead(); } + + // + // deletes first element + // + void DeleteFirst(); + + // + // deletes all elements + // + void DeleteAll(); + + ipcMessage *First() { return mHead; } + PRBool IsEmpty() { return mHead == NULL; } + +private: + void AdvanceHead(); + + ipcMessage *mHead; + ipcMessage *mTail; +}; + +#endif // !ipcMessageQ_h__ diff --git a/modules/ipc/common/ipcm.cpp b/modules/ipc/common/ipcm.cpp new file mode 100644 index 000000000000..d7c5fa910b04 --- /dev/null +++ b/modules/ipc/common/ipcm.cpp @@ -0,0 +1,248 @@ +/* ***** 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 + * + * 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 +#include "ipcm.h" +#include "prlog.h" + +const nsID IPCM_TARGET = +{ /* 753ca8ff-c8c2-4601-b115-8c2944da1150 */ + 0x753ca8ff, + 0xc8c2, + 0x4601, + {0xb1, 0x15, 0x8c, 0x29, 0x44, 0xda, 0x11, 0x50} +}; + +static const char IPCM_PING[] = { (char) IPCM_MSG_PING }; +static const PRUint32 IPCM_PING_LEN = sizeof(IPCM_PING); + +static const char IPCM_CNAME[] = { (char) IPCM_MSG_CNAME }; +static const PRUint32 IPCM_CNAME_LEN = sizeof(IPCM_CNAME); + +// +// +--------------------+ +// | BYTE : msgType | +// +--------------------+ +// | (variable) | +// +--------------------+ +// + +int +IPCM_GetMsgType(const ipcMessage *msg) +{ + // make sure message topic matches + if (msg->Target().Equals(IPCM_TARGET)) { + // the type is encoded as the first byte + char type = msg->Data()[0]; + if (type < IPCM_MSG_UNKNOWN) + return type; + } + return IPCM_MSG_UNKNOWN; +} + +// +// PING message +// +// +----------------------+ +// | BYTE - IPCM_MSG_PING | +// +----------------------+ +// + +const char ipcmMessagePING::MSG_TYPE = (char) IPCM_MSG_PING; + +ipcmMessagePING::ipcmMessagePING() +{ + Init(IPCM_TARGET, &MSG_TYPE, 1); +} + +// +// CNAME message +// +// +-----------------------+ +// | BYTE - IPCM_MSG_CNAME | +// +-----------------------+ +// | clientName | +// +-----------------------+ +// | null | +// +-----------------------+ +// + +const char ipcmMessageCNAME::MSG_TYPE = (char) IPCM_MSG_CNAME; + +ipcmMessageCNAME::ipcmMessageCNAME(const char *cName) +{ + int cLen = strlen(cName); + int dataLen = 1 + // msg_type + cLen + // cName + 1; // null + + Init(IPCM_TARGET, NULL, dataLen); + SetData(0, &MSG_TYPE, 1); + SetData(1, cName, cLen + 1); +} + +const char * +ipcmMessageCNAME::ClientName() const +{ + // make sure data is null terminated + const char *data = Data(); + if (data[DataLen() - 1] != '\0') + return NULL; + + return Data() + 1; +} + +// +// CENUM message +// +// +-----------------------+ +// | BYTE - IPCM_MSG_CENUM | +// +-----------------------+ +// + +const char ipcmMessageCENUM::MSG_TYPE = (char) IPCM_MSG_CENUM; + +ipcmMessageCENUM::ipcmMessageCENUM() +{ + Init(IPCM_TARGET, &MSG_TYPE, 1); +} + +// +// CLIST message +// +// +-----------------------+ +// | BYTE - IPCM_MSG_CLIST | +// +-----------------------+ +// | cname[0] | +// +-----------------------+ +// | null | +// +-----------------------+ +// . . +// . . +// +-----------------------+ +// | cname[num - 1] | +// +-----------------------+ +// | null | +// +-----------------------+ +// + +const char ipcmMessageCLIST::MSG_TYPE = (char) IPCM_MSG_CLIST; + +ipcmMessageCLIST::ipcmMessageCLIST(const char *cNames[], PRUint32 num) +{ + PRUint32 i, dataLen = 1; + + for (i = 0; i < num; ++i) { + dataLen += strlen(cNames[i]); + dataLen ++; + } + + Init(IPCM_TARGET, NULL, dataLen); + + PRUint32 offset = 1; + for (i = 0; i < num; ++i) { + PRUint32 len = strlen(cNames[i]); + SetData(offset, cNames[i], len + 1); + offset += len + 1; + } +} + +const char * +ipcmMessageCLIST::NextClientName(const char *cName) const +{ + if (!cName) + return Data() + 1; + + cName += strlen(cName) + 1; + if (cName == MsgBuf() + MsgLen()) + cName = NULL; + return cName; +} + +// +// FWD message +// +// +----------------------+ +// | BYTE - IPCM_MSG_FWD | +// +----------------------+ +// | dest_client | +// +----------------------+ +// | null | +// +----------------------+ +// | dest_msg | +// +----------------------+ +// + +const char ipcmMessageFWD::MSG_TYPE = (char) IPCM_MSG_FWD; + +ipcmMessageFWD::ipcmMessageFWD(const char *dClient, const ipcMessage *dMsg) +{ + int cLen = strlen(dClient); + int dataLen = 1 + // msg_type + cLen + // dest_client + 1 + // null + dMsg->MsgLen(); // dest_msg + + Init(IPCM_TARGET, NULL, dataLen); + SetData(0, &MSG_TYPE, 1); + SetData(1, dClient, cLen + 1); + SetData(1 + cLen + 1, dMsg->MsgBuf(), dMsg->MsgLen()); +} + +const char * +ipcmMessageFWD::DestClient() const +{ + return Data() + 1; +} + +PRStatus +ipcmMessageFWD::DestMessage(ipcMessage *msg) const +{ + const char *ptr = DestClient(); + + // XXX use a custom loop here to avoid walking off the end of the buffer + PRUint32 cLen = strlen(ptr); + PRUint32 dLen = MsgLen() - 1 - cLen - 1; + PRUint32 bytesRead; + PRBool complete; + + ptr += (cLen + 1); + if (msg->ReadFrom(ptr, dLen, &bytesRead, &complete) != PR_SUCCESS || !complete) + return PR_FAILURE; + + return PR_SUCCESS; +} diff --git a/modules/ipc/common/ipcm.h b/modules/ipc/common/ipcm.h new file mode 100644 index 000000000000..865ba614a06a --- /dev/null +++ b/modules/ipc/common/ipcm.h @@ -0,0 +1,174 @@ +/* ***** 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 + * + * 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 ipcm_h__ +#define ipcm_h__ + +#include "ipcMessage.h" + +// +// IPCM (IPC Manager) protocol support +// + +extern const nsID IPCM_TARGET; + +enum { + IPCM_MSG_PING, + IPCM_MSG_CNAME, + IPCM_MSG_CENUM, + IPCM_MSG_CLIST, + IPCM_MSG_FWD, + IPCM_MSG_UNKNOWN // unknown message type +}; + +// +// returns IPCM message type. +// +int IPCM_GetMsgType(const ipcMessage *msg); + +// +// NOTE: this file declares some helper classes that simplify construction +// and parsing of IPCM messages. each class subclasses ipcMessage, but +// adds no additional member variables. operator new should be used +// to allocate one of the IPCM helper classes, e.g.: +// +// ipcMessage *msg = new ipcmMessageCNAME("foo"); +// +// given an arbitrary ipcMessage, it can be parsed using logic similar +// to the following: +// +// ipcMessage *msg = ... +// if (strcmp(msg->Topic(), "ipcm") == 0) { +// if (IPCM_GetMsgType(msg) == IPCM_MSG_CNAME) { +// ipcmMessageCNAME *cnameMsg = (ipcmMessageCNAME *) msg; +// printf("client name: %s\n", cnameMsg->ClientName()); +// } +// } +// +// in other words, these classes are very very lightweight. +// + +// +// IPCM_MSG_PING +// +// this message may be sent from either the client or the daemon. +// +class ipcmMessagePING : public ipcMessage +{ +public: + static const char MSG_TYPE; + + ipcmMessagePING(); +}; + +// +// IPCM_MSG_CNAME +// +// this message is sent from a client to specify its name. +// +class ipcmMessageCNAME : public ipcMessage +{ +public: + static const char MSG_TYPE; + + ipcmMessageCNAME(const char *cName); + + // + // extracts the "client name" + // + const char *ClientName() const; +}; + +// +// IPCM_MSG_CENUM +// +// this message is sent from a client to request a CLIST response. +// +class ipcmMessageCENUM : public ipcMessage +{ +public: + static const char MSG_TYPE; + + ipcmMessageCENUM(); +}; + +// +// IPCM_MSG_CLIST +// +// this message is sent from the daemon in response to a CENUM request. the +// message contains the list of clients by name. +// +class ipcmMessageCLIST : public ipcMessage +{ +public: + static const char MSG_TYPE; + + ipcmMessageCLIST(const char *clientNames[], PRUint32 numClients); + + // + // extracts the next client name from the message. if null is passed in, then + // the first client name in the list is returned. null is returned if there + // aren't anymore client names. (the returned client name acts as an iterator.) + // + const char *NextClientName(const char *clientName = NULL) const; +}; + +// +// IPCM_MSG_FWD +// +// this message is only sent from the client to the daemon. the daemon +// will forward the contained message to the specified client. +// +class ipcmMessageFWD : public ipcMessage +{ +public: + static const char MSG_TYPE; + + ipcmMessageFWD(const char *destClient, const ipcMessage *destMsg); + + // + // extracts the "destination client name" + // + const char *DestClient() const; + + // + // extracts (a copy of) the "destination message" + // + PRStatus DestMessage(ipcMessage *destMsg) const; +}; + +#endif // !ipcm_h__ diff --git a/modules/ipc/daemon/Makefile.in b/modules/ipc/daemon/Makefile.in new file mode 100644 index 000000000000..1734fec40a0a --- /dev/null +++ b/modules/ipc/daemon/Makefile.in @@ -0,0 +1,87 @@ +# ***** 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 +# +# 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 = ipc +REQUIRES = \ + xpcom \ + $(NULL) + +CPPSRCS = \ + ipcd.cpp \ + ipcClient.cpp \ + ipcModuleReg.cpp \ + ipcCommandModule.cpp \ + $(NULL) + +PROGRAM = mozipcd$(BIN_SUFFIX) + +EXPORTS = \ + ipcModule.h \ + ipcd.h \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../common \ + $(NULL) + +include $(topsrcdir)/config/config.mk + +LIBS = \ + $(EXTRA_DSO_LIBS) \ + $(NSPR_LIBS) \ + $(DIST)/lib/$(LIB_PREFIX)ipccom_s.$(LIB_SUFFIX) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DIPC_DAEMON + +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +# +# need to install mozipcd.lib, which contains the symbols exported by the +# daemon that modules will need to import. +# +libs:: $(PROGRAM) + $(INSTALL) mozipcd.lib $(DIST)/lib +endif diff --git a/modules/ipc/daemon/ipcClient.cpp b/modules/ipc/daemon/ipcClient.cpp new file mode 100644 index 000000000000..0ae3ccbfcfd1 --- /dev/null +++ b/modules/ipc/daemon/ipcClient.cpp @@ -0,0 +1,191 @@ +/* ***** 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 + * + * 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 +#include "ipcClient.h" +#include "ipcMessage.h" +#include "ipcd.h" +#include "prio.h" +#include "plstr.h" + +int ipcClient::gLastID = 0; + +// +// called to initialize this client context +// +// return: +// 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::Init() +{ + mID = ++gLastID; + mName = NULL; + mInMsg = new ipcMessage(); + + mSendOffset = 0; + + // wait for the client to send us a command + return PR_POLL_READ; +} + +// +// called when this client context is going away +// +int +ipcClient::Finalize() +{ + if (mName) + PL_strfree(mName); + if (mInMsg) + delete mInMsg; + mOutMsgQ.DeleteAll(); + return 0; +} + +// +// 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 poll_flags) +{ + if ((poll_flags & PR_POLL_ERR) || + (poll_flags & PR_POLL_HUP) || + (poll_flags & PR_POLL_EXCEPT) || + (poll_flags & PR_POLL_NVAL)) { + // + // expect Finalize method to be called next. + // + printf("### client socket appears to have closed\n"); + return 0; + } + + // always wait for more data + int ret_flags = PR_POLL_READ; + + if (poll_flags & PR_POLL_READ) { + printf("### client socket is now readable\n"); + + char buf[1024]; + 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 + + char *ptr = buf; + while (n) { + PRUint32 nread; + PRBool complete; + + mInMsg->ReadFrom(ptr, PRUint32(n), &nread, &complete); + + if (complete) { + IPC_DispatchMsg(this, mInMsg); + mInMsg->Reset(); + } + + n -= nread; + ptr += nread; + } + } + + if (poll_flags & PR_POLL_WRITE) { + printf("### client socket is now writable\n"); + + if (mOutMsgQ.First()) + WriteMsgs(fd); + } + + if (mOutMsgQ.First()) + ret_flags |= PR_POLL_WRITE; + + return ret_flags; +} + +void +ipcClient::SetName(const char *name) +{ + printf("### setting client name to \"%s\"\n", name); + + if (mName) + PL_strfree(mName); + mName = PL_strdup(name); +} + +// +// 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; + + printf("### wrote %d bytes\n", nw); + + if (nw == bufLen) + mOutMsgQ.DeleteFirst(); + else + mSendOffset += nw; + } + + return 0; +} diff --git a/modules/ipc/daemon/ipcClient.h b/modules/ipc/daemon/ipcClient.h new file mode 100644 index 000000000000..f9122ab85741 --- /dev/null +++ b/modules/ipc/daemon/ipcClient.h @@ -0,0 +1,81 @@ +/* ***** 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 + * + * 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 ipcClient_h__ +#define ipcClient_h__ + +#include "ipcMessageQ.h" +#include "prio.h" + +class ipcMessage; + +//----------------------------------------------------------------------------- +// 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: + int Init(); + int Finalize(); + int Process(PRFileDesc *fd, int poll_flags); + + int ID() const { return mID; } + const char *Name() const { return mName; } + + void SetName(const char *name); + void EnqueueOutboundMsg(ipcMessage *msg) { mOutMsgQ.Append(msg); } + +private: + int WriteMsgs(PRFileDesc *fd); + + static int gLastID; + + int mID; + char *mName; + ipcMessage *mInMsg; // buffer for incoming message + ipcMessageQ mOutMsgQ; // outgoing message queue + + // keep track of the amount of the first message sent + PRUint32 mSendOffset; +}; + +#endif // !ipcClient_h__ diff --git a/modules/ipc/daemon/ipcCommandModule.cpp b/modules/ipc/daemon/ipcCommandModule.cpp new file mode 100644 index 000000000000..1891794f174d --- /dev/null +++ b/modules/ipc/daemon/ipcCommandModule.cpp @@ -0,0 +1,117 @@ +/* ***** 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 + * + * 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 +#include +#include "ipcCommandModule.h" +#include "ipcModule.h" +#include "ipcClient.h" +#include "ipcMessage.h" +#include "ipcd.h" +#include "ipcm.h" + +typedef const char * constCharPtr; + +class ipcCommandModule : public ipcModule +{ +public: + void Shutdown() + { + } + + const nsID &ID() + { + return IPCM_TARGET; + } + + void HandleMsg(ipcClient *client, const ipcMessage *msg) + { + // XXX replace w/ function table + switch (IPCM_GetMsgType(msg)) { + case IPCM_MSG_PING: + printf("### got ping\n"); + { + IPC_SendMsg(client, new ipcmMessagePING()); + } + break; + case IPCM_MSG_CNAME: + printf("### got cname\n"); + { + const char *name = ((const ipcmMessageCNAME *) msg)->ClientName(); + if (name) + client->SetName(name); + } + break; + case IPCM_MSG_CENUM: + printf("### got cenum\n"); + { + int len; + ipcClient *clients = IPC_GetClients(&len); + if (clients) { + constCharPtr *clist = new constCharPtr[len-1]; + if (clist) { + for (int i = 0; i < len; ++i) { + if (clients + i != client) + clist[i] = clients[i].Name(); + } + IPC_SendMsg(client, new ipcmMessageCLIST(clist, len-1)); + delete[] clist; + } + } + } + break; + case IPCM_MSG_FWD: + printf("### got fwd\n"); + { + const ipcmMessageFWD *fMsg = (const ipcmMessageFWD *) msg; + ipcClient *client = IPC_GetClientByName(fMsg->DestClient()); + ipcMessage *newMsg = new ipcMessage(); + if (fMsg->DestMessage(newMsg) == PR_SUCCESS) + IPC_SendMsg(client, newMsg); + } + break; + default: + printf("### got unknown message\n"); + } + } +}; + +ipcModule *IPC_GetCommandModule() +{ + static ipcCommandModule module; + return &module; +} diff --git a/modules/ipc/daemon/ipcCommandModule.h b/modules/ipc/daemon/ipcCommandModule.h new file mode 100644 index 000000000000..e2e9121e1a42 --- /dev/null +++ b/modules/ipc/daemon/ipcCommandModule.h @@ -0,0 +1,45 @@ +/* ***** 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 + * + * 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" + +class ipcModule *IPC_GetCommandModule(); + +#endif // !ipcCommandModule_h__ diff --git a/modules/ipc/daemon/ipcModule.h b/modules/ipc/daemon/ipcModule.h new file mode 100644 index 000000000000..e4479d685138 --- /dev/null +++ b/modules/ipc/daemon/ipcModule.h @@ -0,0 +1,95 @@ +/* ***** 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 + * + * 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" + +class ipcMessage; +class ipcClient; + +//----------------------------------------------------------------------------- +// abstract module class +//----------------------------------------------------------------------------- + +class ipcModule +{ +public: + // + // called when this module will no longer be accessed. if this module was + // allocated on the heap, then it can be free'd. + // + virtual void Shutdown() = 0; + + // + // called to determine the ID of this module. the ID of a module + // indicates the "message target" for which it will be registered + // as a handler. + // + virtual const nsID &ID() = 0; + + // + // 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). + // + // msg - the message sent from the client. the target of this message + // matches the ID of this module. + // + virtual void HandleMsg(ipcClient *client, const ipcMessage *msg) = 0; +}; + +// +// factory method signature for DLLs, which may define more than one ipcModule +// implementation. the DLL must export the following symbol: +// +// extern "C" ipcModule **IPC_GetModuleList(); +// +// return: +// null terminated array of modules. +// +typedef ipcModule ** (*ipcGetModuleListFunc)(void); + +#endif // !ipcModule_h__ diff --git a/modules/ipc/daemon/ipcModuleReg.cpp b/modules/ipc/daemon/ipcModuleReg.cpp new file mode 100644 index 000000000000..b15220be0fa3 --- /dev/null +++ b/modules/ipc/daemon/ipcModuleReg.cpp @@ -0,0 +1,173 @@ +/* ***** 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 + * + * 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 +#include +#include + +#include "prlink.h" +#include "prio.h" +#include "plstr.h" + +#include "ipcConfig.h" +#include "ipcModuleReg.h" +#include "ipcModule.h" +#include "ipcCommandModule.h" +#include "ipcd.h" + +struct ipcModuleRegEntry +{ + nsID id; + ipcModule *module; + PRLibrary *lib; +}; + +#define IPC_MAX_MODULE_COUNT 64 + +static ipcModuleRegEntry ipcModules[IPC_MAX_MODULE_COUNT]; +static int ipcModuleCount; + +static PRStatus +AddModule(const nsID &id, ipcModule *module, PRLibrary *lib) +{ + if (ipcModuleCount == IPC_MAX_MODULE_COUNT) { + printf("### too many modules!\n"); + return PR_FAILURE; + } + + ipcModules[ipcModuleCount].id = id; + ipcModules[ipcModuleCount].module = module; + ipcModules[ipcModuleCount].lib = lib; + + ++ipcModuleCount; + return PR_SUCCESS; +} + +static void +InitModuleFromLib(const char *modulesDir, const char *fileName) +{ + printf("### InitModuleFromLib [%s]\n", fileName); + + 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) { + ipcGetModuleListFunc func = + (ipcGetModuleListFunc) PR_FindFunctionSymbol(lib, "IPC_GetModuleList"); + if (func) { + ipcModule **modules = func(); + if (modules) { + while (*modules) { + AddModule((*modules)->ID(), *modules, PR_LoadLibrary(buf)); + ++modules; + } + } + } + PR_UnloadLibrary(lib); + } + + free(buf); +} + +//----------------------------------------------------------------------------- +// ipcModuleReg API +//----------------------------------------------------------------------------- + +// +// search for a module registered under the specified id +// +ipcModule * +IPC_GetModuleByID(const nsID &id) +{ + for (int i=0; iID(), module, NULL); + + if (modulesDir) { + printf("### 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 + // + char *p = strrchr(ent->name, '.'); + if (p && PL_strcasecmp(p, MOZ_DLL_SUFFIX) == 0) + InitModuleFromLib(modulesDir, ent->name); + } + PR_CloseDir(dir); + } + } +} + +void +IPC_ShutdownModuleReg() +{ + // + // shutdown modules in reverse order + // + for (int i = ipcModuleCount - 1; i >= 0; --i) { + ipcModuleRegEntry &entry = ipcModules[i]; + if (entry.module) + entry.module->Shutdown(); + if (entry.lib) + PR_UnloadLibrary(entry.lib); + } + // memset(ipcModules, 0, sizeof(ipcModules)); + ipcModuleCount = 0; +} diff --git a/modules/ipc/daemon/ipcModuleReg.h b/modules/ipc/daemon/ipcModuleReg.h new file mode 100644 index 000000000000..64940afa3465 --- /dev/null +++ b/modules/ipc/daemon/ipcModuleReg.h @@ -0,0 +1,49 @@ +/* ***** 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 + * + * 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/shutdown module registry. +// +void IPC_InitModuleReg(const char *moduleDir); +void IPC_ShutdownModuleReg(); + +#endif // !ipcModuleReg_h__ diff --git a/modules/ipc/daemon/ipcd.cpp b/modules/ipc/daemon/ipcd.cpp new file mode 100644 index 000000000000..4f9b31ad7e76 --- /dev/null +++ b/modules/ipc/daemon/ipcd.cpp @@ -0,0 +1,415 @@ +/* ***** 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 + * + * 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 +#include +#include + +#ifdef XP_UNIX +#include +#include +#endif + +#include "prio.h" +#include "prerror.h" +#include "prthread.h" +#include "prinrval.h" +#include "plstr.h" + +#include "ipcConfig.h" +#include "ipcMessage.h" +#include "ipcClient.h" +#include "ipcModuleReg.h" +#include "ipcModule.h" +#include "ipcd.h" + +#ifdef IPC_USE_INET +#include "prnetdb.h" +#endif + +//----------------------------------------------------------------------------- + +// upper limit on the number of active connections +// XXX may want to make this more dynamic +#define MAX_CLIENTS 100 + +// +// the first element of this array is always zero; this is done so that the +// n'th element of |clients| corresponds to the n'th element of |poll_fds|. +// +static ipcClient clients[MAX_CLIENTS + 1]; + +static PRPollDesc poll_fds[MAX_CLIENTS + 1]; +static int poll_fd_count; + +//----------------------------------------------------------------------------- + +static int AddClient(PRFileDesc *fd) +{ + if (poll_fd_count == MAX_CLIENTS + 1) { + printf("### reached maximum client limit\n"); + return -1; + } + + poll_fds[poll_fd_count].fd = fd; + poll_fds[poll_fd_count].in_flags = clients[poll_fd_count].Init(); + poll_fds[poll_fd_count].out_flags = 0; + + ++poll_fd_count; + return 0; +} + +static int RemoveClient(int client_index) +{ + PRPollDesc *pd = &poll_fds[client_index]; + + PR_Close(pd->fd); + + clients[client_index].Finalize(); + + // + // keep the clients and poll_fds contiguous; move the last one into + // the spot held by the one that is going away. + // + int to_idx = client_index; + int from_idx = poll_fd_count - 1; + if (from_idx != to_idx) { + memcpy(&clients[to_idx], &clients[from_idx], sizeof(ipcClient)); + memcpy(&poll_fds[to_idx], &poll_fds[from_idx], sizeof(PRPollDesc)); + } + + // + // zero out the old entries. + // + memset(&clients[from_idx], 0, sizeof(ipcClient)); + memset(&poll_fds[from_idx], 0, sizeof(PRPollDesc)); + + --poll_fd_count; + return 0; +} + +//----------------------------------------------------------------------------- + +static void Process(PRFileDesc *listen_fd) +{ + poll_fd_count = 1; + + poll_fds[0].fd = listen_fd; + poll_fds[0].in_flags = PR_POLL_EXCEPT | PR_POLL_READ; + + while (1) { + PRInt32 rv; + PRIntn i; + + poll_fds[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. + // + rv = PR_Poll(poll_fds, poll_fd_count, PR_SecondsToInterval(60 * 5)); + if (rv == -1) { + printf("### PR_Poll failed [%d]\n", PR_GetError()); + return; + } + + if (rv > 0) { + // + // process clients that are ready + // + for (i = 1; i < poll_fd_count; ++i) { + if (poll_fds[i].out_flags != 0) { + poll_fds[i].in_flags = clients[i].Process(poll_fds[i].fd, poll_fds[i].out_flags); + poll_fds[i].out_flags = 0; + } + } + + // + // cleanup any dead clients (indicated by a zero in_flags) + // + for (i = poll_fd_count - 1; i >= 1; --i) { + if (poll_fds[i].in_flags == 0) + RemoveClient(i); + } + + // + // check for new connection + // + if (poll_fds[0].out_flags & PR_POLL_READ) { + printf("### got new connection\n"); + + PRNetAddr client_addr; + memset(&client_addr, 0, sizeof(client_addr)); + PRFileDesc *client_fd; + + client_fd = PR_Accept(listen_fd, &client_addr, PR_INTERVAL_NO_WAIT); + if (client_fd == NULL) { + printf("### PR_Accept failed [%d]\n", PR_GetError()); + return; + } + + // make socket non-blocking + PRSocketOptionData opt; + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_TRUE; + PR_SetSocketOption(client_fd, &opt); + + if (AddClient(client_fd) != 0) + PR_Close(client_fd); + } + } + + // + // shutdown if no clients + // + if (poll_fd_count == 1) { + printf("### shutting down\n"); + break; + } + } +} + +//----------------------------------------------------------------------------- + +static void InitModuleReg(const char *exePath) +{ + static const char modDir[] = "ipc/modules"; + + char *p = PL_strrchr(exePath, IPC_PATH_SEP_CHAR); + if (p == NULL) { + printf("### unexpected exe path\n"); + return; + } + + int baseLen = p - exePath; + int finalLen = baseLen + 1 + sizeof(modDir); + + // build full path to ipc modules + char *buf = (char*) malloc(finalLen); + memcpy(buf, exePath, baseLen); + buf[baseLen] = IPC_PATH_SEP_CHAR; + memcpy(buf + baseLen + 1, modDir, sizeof(modDir)); + + IPC_InitModuleReg(buf); + free(buf); +} + +#ifdef XP_UNIX +#include +#endif + +int main(int argc, char **argv) +{ + PRFileDesc *listen_fd; + PRNetAddr addr; + +#ifdef XP_UNIX + signal(SIGINT, SIG_IGN); + umask(0077); // ensure strict file permissions +#endif + +start: +#ifdef IPC_USE_INET + listen_fd = PR_OpenTCPSocket(PR_AF_INET); + if (!listen_fd) { + printf("### PR_OpenUDPSocket failed [%d]\n", PR_GetError()); + return -1; + } + + PR_InitializeNetAddr(PR_IpAddrLoopback, IPC_PORT, &addr); + +#else + const char *socket_path; + if (argc < 2) + socket_path = IPC_DEFAULT_SOCKET_PATH; + else + socket_path = argv[1]; + + listen_fd = PR_OpenTCPSocket(PR_AF_LOCAL); + if (!listen_fd) { + printf("### PR_OpenUDPSocket failed [%d]\n", PR_GetError()); + return -1; + } + + addr.local.family = PR_AF_LOCAL; + PL_strncpyz(addr.local.path, socket_path, sizeof(addr.local.path)); +#endif + + if (PR_Bind(listen_fd, &addr) != PR_SUCCESS) { + printf("### PR_Bind failed [%d]\n", PR_GetError()); + // + // failure here indicates that another process may be bound + // to the socket already. let's try connecting to that socket. + // if connect fails, then the socket is probably stale. + // + if (PR_Connect(listen_fd, &addr, PR_SecondsToInterval(2)) == PR_SUCCESS) { + // + // looks like another process is active. silently exit. + // + printf("### looks like another instance of the daemon is active; sleeping...\n"); + // + // sleep here to avoid triggering the shutdown procedure in the + // other daemon. 10 seconds should be long enough for the client + // to have established a connection. + // + PR_Sleep(PR_SecondsToInterval(10)); + printf("### exiting\n"); + PR_Close(listen_fd); + return 0; + } + // + // OK, the socket is probably stale. + // + printf("### socket appears to be stale\n"); +#ifdef IPC_USE_INET + printf("### waiting for TIMEWAIT period to expire...\n"); + PR_Sleep(PR_SecondsToInterval(60)); +#else + printf("### deleting socket at %s\n", socket_path); + PR_Delete(socket_path); +#endif + PR_Close(listen_fd); + goto start; + } + + InitModuleReg(argv[0]); + + if (PR_Listen(listen_fd, 5) != PR_SUCCESS) { + printf("### PR_Listen failed [%d]\n", PR_GetError()); + return -1; + } + + Process(listen_fd); + + IPC_ShutdownModuleReg(); + + // + // XXX enable this delay for startup testing + // + //printf("### sleeping for 5 seconds...\n"); + //PR_Sleep(PR_SecondsToInterval(5)); + +#ifndef IPC_USE_INET + printf("### deleting socket at %s\n", socket_path); + // + // we delete the file itself first to avoid a race between shutting + // ourselves down and another instance of the daemon starting up. + // + if (PR_Delete(socket_path) != PR_SUCCESS) { + printf("### PR_Delete failed [%d]\n", PR_GetError()); + return -1; + } +#endif + + printf("### closing socket\n"); + + if (PR_Close(listen_fd) != PR_SUCCESS) { + printf("### PR_Close failed [%d]\n", PR_GetError()); + return -1; + } + + return 0; +} + +//----------------------------------------------------------------------------- +// IPC API +//----------------------------------------------------------------------------- + +int IPC_DispatchMsg(ipcClient *client, const ipcMessage *msg) +{ + // lookup handler for this message's topic and forward message to it. + ipcModule *module = IPC_GetModuleByID(msg->Target()); + if (module) + module->HandleMsg(client, msg); + else + printf("### no registered module; ignoring message\n"); + return 0; +} + +int IPC_SendMsg(ipcClient *client, ipcMessage *msg) +{ + if (client == NULL) { + int i; + // + // walk clients array + // + for (i = 1; i < poll_fd_count - 1; ++i) + IPC_SendMsg(&clients[i], msg->Clone()); + + // send to last client w/o cloning to avoid extra malloc + IPC_SendMsg(&clients[i], msg); + } + else { + client->EnqueueOutboundMsg(msg); + // + // since this client's Process method may have already been + // called, we need to explicitly set the PR_POLL_WRITE flag. + // + int client_index = client - clients; + poll_fds[client_index].in_flags |= PR_POLL_WRITE; + } + return 0; +} + +ipcClient *IPC_GetClientByID(int clientID) +{ + // linear search OK since number of clients should be small + for (int i = 1; i < poll_fd_count; ++i) { + if (clients[i].ID() == clientID) + return &clients[i]; + } + return NULL; +} + +ipcClient *IPC_GetClientByName(const char *name) +{ + // linear search OK since number of clients should be small + for (int i = 1; i < poll_fd_count; ++i) { + if (strcmp(clients[i].Name(), name) == 0) + return &clients[i]; + } + return NULL; +} + +ipcClient *IPC_GetClients(int *count) +{ + *count = poll_fd_count - 1; + return &clients[1]; +} diff --git a/modules/ipc/daemon/ipcd.h b/modules/ipc/daemon/ipcd.h new file mode 100644 index 000000000000..82e0e7c75c62 --- /dev/null +++ b/modules/ipc/daemon/ipcd.h @@ -0,0 +1,110 @@ +/* ***** 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 + * + * 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" + +#ifdef IPC_DAEMON +#define IPC_METHOD _declspec(dllexport) +#else +#define IPC_METHOD _declspec(dllimport) +#endif + +class ipcClient; +class ipcMessage; + +//----------------------------------------------------------------------------- +// IPC daemon API +//----------------------------------------------------------------------------- + +extern "C" { + +// +// IPC_DispatchMsg +// +// params: +// client - identifies the client from which this message originated. +// msg - the message received. this function does not modify |msg|, +// and ownership stays with the caller. +// +int IPC_DispatchMsg(ipcClient *client, const ipcMessage *msg); + +// +// IPC_SendMsg +// +// params: +// client - identifies the client that should receive the message. +// if null, then the message is broadcast to all clients. +// msg - the message to be sent. this function subsumes +// ownership of the message. the caller must not attempt +// to access |msg| after this function returns. +// return: +// 0 - on success +// +IPC_METHOD int IPC_SendMsg(ipcClient *client, ipcMessage *msg); + +// +// returns the client ID dynamically generated for the given client. +// +int IPC_GetClientID(ipcClient *client); + +// +// returns the client name (NULL if the client did not specify a name). +// +const char *IPC_GetClientName(ipcClient *client); + +// +// client lookup functions +// +ipcClient *IPC_GetClientByID(int clientID); +ipcClient *IPC_GetClientByName(const char *clientName); + +// +// return array of all clients, length equal to |count|. +// +ipcClient *IPC_GetClients(int *count); + +// +// returns the ipcModule object registered under the given module ID. +// +ipcModule *IPC_GetModuleByID(const nsID &moduleID); + +} // extern "C" + +#endif // !IPCD_H__ diff --git a/modules/ipc/public/Makefile.in b/modules/ipc/public/Makefile.in new file mode 100644 index 000000000000..5df1b3f7ba04 --- /dev/null +++ b/modules/ipc/public/Makefile.in @@ -0,0 +1,52 @@ +# ***** 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 +# +# 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 = ipc + +XPIDLSRCS = \ + ipcIService.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/modules/ipc/public/ipcIService.idl b/modules/ipc/public/ipcIService.idl new file mode 100644 index 000000000000..b747f579479f --- /dev/null +++ b/modules/ipc/public/ipcIService.idl @@ -0,0 +1,209 @@ +/* ***** 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 + * + * 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 "nsISupports.idl" + +interface nsISimpleEnumerator; +interface ipcIMessageObserver; +interface ipcIClientObserver; + +/** + * the IPC service provides the means to communicate with an external IPC + * daemon and/or other mozilla-based applications sharing the same user + * profile. the IPC daemon hosts modules (some builtin and others dynamically + * loaded) with which applications may interact. + * + * at application startup, the IPC service will attempt to establish a + * connection with the IPC daemon for the current profile. (there is one IPC + * daemon per profile.) the IPC daemon will be automatically started if + * necessary. when a connection has been established, the IPC service will + * broadcast an "ipc-startup" notification using the observer service. + * + * when the connection to the IPC daemon is closed (due to error, profile + * change, or normal shutdown), an "ipc-shutdown" notification will be + * broadcast. + * + * each client has a name. the client name need not be unique across all + * clients, but it is usually good if it is. this IPC service does not require + * unique names. instead, the IPC daemon assigns each client a unique ID that + * is good for the current "session." clients can query other clients by name + * or by ID. the IPC service supports forwarding messages from one client to + * another via the IPC daemon. + * + * for performance reasons, this system should not be used to transfer large + * amounts of data. instead, applications may choose to utilize shared memory, + * and rely on the IPC service for synchronization and small message transfer + * only. + */ +[scriptable, uuid(53d3e3a7-528f-4b09-9eab-9416272568c0)] +interface ipcIService : nsISupports +{ + /** + * returns the "client ID" assigned to this application by the IPC daemon. + * this number is the name given to our application for the current + * session. after a profile change, our client ID will change. + * + * @throws NS_ERROR_NOT_AVAILABLE if no connection to the IPC daemon. + */ + readonly attribute unsigned long clientID; + + /** + * client aliases give the client a way to register itself under multiple + * names. for example, the mozilla browser might register itself under + * the name "mozilla", but it could also register itself under the aliases + * "browser", "mail", "news", "addrbook", and so on. aliases provide a + * simple mechanism for clients to discover other clients. + */ + void addClientAlias(in ACString aAlias); + void removeClientAlias(in ACString aAlias); + + /** + * query info about a particular client given its client name. + * + * @param aNameOrAlias name or alias of the client being queried. + * @param aObserver client observer to be notified. + * + * @return integer token identifying this request. + */ + unsigned long queryClientByName(in ACString aNameOrAlias, + in ipcIClientObserver aObserver); + + /** + * query info about a particular client given its client ID. + * + * @return integer token identifying this request. + */ + unsigned long queryClientByID(in unsigned long aClientID, + in ipcIClientObserver aObserver); + + /** + * set client observer. observer is notified whenever the status of + * a client changes. + * + * @param aClientID the ID of the client to observe. + * @param aObserver the client observer. + */ + void setClientObserver(in unsigned long aClientID, + in ipcIClientObserver aObserver); + + /** + * set a message observer for a particular message target. + * + * @param aTarget the message target being observed. any existing + * observer will be replaced. + * @param aObserver the message observer to receive incoming messages + * for the specified target. pass null to remove the + * existing observer. + */ + void setMessageObserver(in nsIDRef aTarget, in ipcIMessageObserver aObserver); + + /** + * send message asynchronously to the IPC daemon. there is no guarantee + * that the message will be delivered. + * + * @param aTarget the target of the message. this is the ID of the + * daemon module that should receive this message. + * @param aData the data of the message. + * @param aDataLen the data length of the message. + */ + [noscript] void sendMessage(in nsIDRef aTarget, + in string aData, + in unsigned long aDataLen); + + /** + * forward message asynchronously via the IPC daemon to another application + * process. there is no guarantee that the message will be delivered. + * + * @param aClientID the client ID of the foreign application that should + * receive this message. + * + * other parameters are identical to those for sendMessage. + */ + [noscript] void forwardMessage(in unsigned long aClientID, + in nsIDRef aTarget, + in string aData, + in unsigned long aDataLen); +}; + +[scriptable, uuid(e40a4a3c-2dc1-470e-ab7f-5675fe1f1384)] +interface ipcIMessageObserver : nsISupports +{ + /** + * @param aTarget the target of the message, corresponding to the target + * this observer was registered under. this parameter is + * passed to allow an observer instance to receive + * messages for more than one target. + * @param aData the data of the message. + * @param aDataLen the data length of the message. + */ + [noscript] void onMessageAvailable(in nsIDRef aTarget, + in string aData, + in unsigned long aDataLen); +}; + +[scriptable, uuid(e858d450-62b2-482d-99bb-3b5425aa28cc)] +interface ipcIClientInfo : nsISupports +{ + readonly attribute unsigned long ID; + readonly attribute ACString name; + readonly attribute nsISimpleEnumerator aliases; + readonly attribute nsISimpleEnumerator targets; +}; + +[scriptable, uuid(42283079-030c-4b13-b069-a08b7ad5eab2)] +interface ipcIClientObserver : nsISupports +{ + /** + * client status values + */ + const unsigned long CLIENT_UP = 1; + const unsigned long CLIENT_DOWN = 2; + + /** + * @param aRequestToken the request token returned from the call that + * initiated this observation. 0 if initiated + * from a setClientObserver call. + * @param aClientInfo client info. + * @param aStatus client status (e.g. CLIENT_UP). + */ + void onClientStatus(in unsigned long aRequestToken, + in ipcIClientInfo aClientInfo, + in unsigned long aStatus); + + // XXX do we care about changes to the aliases and targets supported + // by a client? if so, how should we pass this information up? +}; diff --git a/modules/ipc/src/Makefile.in b/modules/ipc/src/Makefile.in new file mode 100644 index 000000000000..c68838323eed --- /dev/null +++ b/modules/ipc/src/Makefile.in @@ -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 +# +# 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 = ipc +LIBRARY_NAME = ipc_s +EXPORT_LIBRARY = 1 +FORCE_STATIC_LIB = 1 +MODULE_NAME = ipc + +REQUIRES = xpcom \ + string \ + necko \ + $(NULL) + +CPPSRCS = \ + ipcService.cpp \ + ipcTransport.cpp \ + ipcSocketProvider.cpp + +LOCAL_INCLUDES = \ + -I$(srcdir)/../common \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/modules/ipc/src/ipcService.cpp b/modules/ipc/src/ipcService.cpp new file mode 100644 index 000000000000..d931cd6c628f --- /dev/null +++ b/modules/ipc/src/ipcService.cpp @@ -0,0 +1,193 @@ +/* ***** 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 + * + * 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 "ipcConfig.h" +#include "ipcService.h" +#include "plstr.h" + +static PRBool PR_CALLBACK +ipcReleaseMessageObserver(nsHashKey *aKey, void *aData, void* aClosure) +{ + ipcIMessageObserver *obs = (ipcIMessageObserver *) aData; + NS_RELEASE(obs); + return PR_TRUE; +} + +//----------------------------------------------------------------------------- +// ipcService +//----------------------------------------------------------------------------- + +ipcService::ipcService() +{ + NS_INIT_ISUPPORTS(); +} + +ipcService::~ipcService() +{ + if (mTransport) { + mTransport->Shutdown(); + NS_RELEASE(mTransport); + } + + mObserverDB.Reset(ipcReleaseMessageObserver, nsnull); +} + +nsresult +ipcService::Init() +{ + nsresult rv; + + mTransport = new ipcTransport(); + if (!mTransport) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(mTransport); + + // XXX use directory service to locate socket + rv = mTransport->Init(NS_LITERAL_CSTRING(IPC_DEFAULT_SOCKET_PATH), this); + if (NS_FAILED(rv)) return rv; + + return NS_OK; +} + +//----------------------------------------------------------------------------- +// interface impl +//----------------------------------------------------------------------------- + +NS_IMPL_ISUPPORTS1(ipcService, ipcIService) + +NS_IMETHODIMP +ipcService::GetClientID(PRUint32 *clientID) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +ipcService::AddClientAlias(const nsACString &alias) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +ipcService::RemoveClientAlias(const nsACString &alias) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +ipcService::QueryClientByName(const nsACString &name, + ipcIClientObserver *observer, + PRUint32 *token) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +ipcService::QueryClientByID(PRUint32 clientID, + ipcIClientObserver *observer, + PRUint32 *token) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +ipcService::SetClientObserver(PRUint32 clientID, + ipcIClientObserver *observer) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +ipcService::SetMessageObserver(const nsID &target, ipcIMessageObserver *observer) +{ + nsIDKey key(target); + + ipcIMessageObserver *cobs = (ipcIMessageObserver *) mObserverDB.Get(&key); + if (cobs) { + NS_RELEASE(cobs); + if (!observer) { + mObserverDB.Remove(&key); + return NS_OK; + } + } + if (observer) { + NS_ADDREF(observer); + mObserverDB.Put(&key, observer); + } + return NS_OK; +} + +NS_IMETHODIMP +ipcService::SendMessage(const nsID &target, + const char *data, + PRUint32 dataLen) +{ + NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED); + + ipcMessage *msg = new ipcMessage(); + if (!msg) + return NS_ERROR_OUT_OF_MEMORY; + + msg->Init(target, data, dataLen); + + mTransport->SendMsg(msg); + return NS_OK; +} + +NS_IMETHODIMP +ipcService::ForwardMessage(PRUint32 clientID, + const nsID &target, + const char *data, + PRUint32 dataLen) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +//----------------------------------------------------------------------------- +// ipcTransportObserver impl +//----------------------------------------------------------------------------- + +void +ipcService::OnMsgAvailable(const ipcMessage *msg) +{ + nsIDKey key(msg->Target()); + + ipcIMessageObserver *observer = (ipcIMessageObserver *) mObserverDB.Get(&key); + if (observer) + observer->OnMessageAvailable(msg->Target(), + msg->Data(), + msg->DataLen()); +} diff --git a/modules/ipc/src/ipcService.h b/modules/ipc/src/ipcService.h new file mode 100644 index 000000000000..bdabd3296b5d --- /dev/null +++ b/modules/ipc/src/ipcService.h @@ -0,0 +1,75 @@ +/* ***** 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 + * + * 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 ipcService_h__ +#define ipcService_h__ + +#include "ipcIService.h" +#include "ipcTransport.h" +#include "ipcMessage.h" +#include "ipcMessageQ.h" +#include "nsIRequest.h" +#include "nsIStreamListener.h" +#include "nsIStreamProvider.h" +#include "nsCOMPtr.h" +#include "nsHashtable.h" + +//---------------------------------------------------------------------------- +// ipcService +//---------------------------------------------------------------------------- + +class ipcService : public ipcIService + , public ipcTransportObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_IPCISERVICE + + ipcService(); + virtual ~ipcService(); + + nsresult Init(); + +private: + // ipcTransportObserver: + void OnMsgAvailable(const ipcMessage *); + + nsHashtable mObserverDB; + ipcTransport *mTransport; +}; + +#endif // !ipcService_h__ diff --git a/modules/ipc/src/ipcSocketProvider.cpp b/modules/ipc/src/ipcSocketProvider.cpp new file mode 100644 index 000000000000..2132fb170328 --- /dev/null +++ b/modules/ipc/src/ipcSocketProvider.cpp @@ -0,0 +1,64 @@ +/* ***** 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 + * + * 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 "ipcSocketProvider.h" + +NS_IMETHODIMP +ipcSocketProvider::NewSocket(const char *host, + PRInt32 port, + const char *proxyHost, + PRInt32 proxyPort, + PRFileDesc **fd, + nsISupports **securityInfo) +{ + *fd = PR_OpenTCPSocket(PR_AF_LOCAL); + return NS_OK; +} + +NS_IMETHODIMP +ipcSocketProvider::AddToSocket(const char *host, + PRInt32 port, + const char *proxyHost, + PRInt32 proxyPort, + PRFileDesc *fd, + nsISupports **securityInfo) +{ + NS_NOTREACHED("unexpected"); + return NS_ERROR_UNEXPECTED; +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(ipcSocketProvider, nsISocketProvider) diff --git a/modules/ipc/src/ipcSocketProvider.h b/modules/ipc/src/ipcSocketProvider.h new file mode 100644 index 000000000000..824418c95221 --- /dev/null +++ b/modules/ipc/src/ipcSocketProvider.h @@ -0,0 +1,53 @@ +/* ***** 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 + * + * 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 ipcSocketProvider_h__ +#define ipcSocketProvider_h__ + +#include "nsISocketProvider.h" + +class ipcSocketProvider : public nsISocketProvider +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISOCKETPROVIDER + + ipcSocketProvider() { NS_INIT_ISUPPORTS(); } + virtual ~ipcSocketProvider() { } +}; + +#endif // !ipcSocketProvider_h__ diff --git a/modules/ipc/src/ipcTransport.cpp b/modules/ipc/src/ipcTransport.cpp new file mode 100644 index 000000000000..67e08cac308a --- /dev/null +++ b/modules/ipc/src/ipcTransport.cpp @@ -0,0 +1,537 @@ +/* ***** 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 + * + * 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 "nsIServiceManager.h" +#include "nsIObserverService.h" +#include "nsISocketTransportService.h" +#include "nsISocketTransport.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsIFile.h" +#include "nsIProcess.h" +#include "nsDirectoryServiceDefs.h" +#include "nsDirectoryServiceUtils.h" +#include "nsNetCID.h" +#include "netCore.h" +#include "prerror.h" +#include "plstr.h" + +#include "ipcConfig.h" +#include "ipcTransport.h" +#include "ipcm.h" + +#define LOG(args) printf args + +static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); + +//----------------------------------------------------------------------------- +// ipcTransport +//----------------------------------------------------------------------------- + +ipcTransport::~ipcTransport() +{ + if (mFD) + PR_Close(mFD); +} + +nsresult +ipcTransport::Init(const nsACString &socketPath, ipcTransportObserver *obs) +{ + LOG((">>> ipcTransport::Init\n")); + + mSocketPath = socketPath; + mObserver = obs; + + nsCOMPtr observ(do_GetService("@mozilla.org/observer-service;1")); + if (observ) { + observ->AddObserver(this, "xpcom-shutdown", PR_FALSE); + observ->AddObserver(this, "profile-change-net-teardown", PR_FALSE); + } + + return Connect(); +} + +nsresult +ipcTransport::Shutdown() +{ + LOG((">>> ipcTransport::Shutdown\n")); + + mHaveConnection = PR_FALSE; + + if (mReadRequest) { + mReadRequest->Cancel(NS_BINDING_ABORTED); + mReadRequest = nsnull; + } + if (mWriteRequest) { + mWriteRequest->Cancel(NS_BINDING_ABORTED); + mWriteRequest = nsnull; + mWriteSuspended = PR_FALSE; + } + mTransport = nsnull; + return NS_OK; +} + +nsresult +ipcTransport::SendMsg(ipcMessage *msg) +{ + NS_ENSURE_ARG_POINTER(msg); + + LOG((">>> ipcTransport::SendMsg [dataLen=%u]\n", msg->DataLen())); + + if (!mHaveConnection) { + LOG((">>> delaying message until connected\n")); + mDelayedQ.Append(msg); + return NS_OK; + } + + return SendMsg_Internal(msg); +} + +nsresult +ipcTransport::SendMsg_Internal(ipcMessage *msg) +{ + LOG((">>> ipcTransport::SendMsg_Internal [dataLen=%u]\n", msg->DataLen())); + + mSendQ.EnqueueMsg(msg); + + if (!mWriteRequest) { + if (!mTransport) + return NS_ERROR_FAILURE; + + nsresult rv = mTransport->AsyncWrite(&mSendQ, nsnull, 0, PRUint32(-1), 0, + getter_AddRefs(mWriteRequest)); + if (NS_FAILED(rv)) return rv; + } + if (mWriteSuspended) { + mWriteRequest->Resume(); + mWriteSuspended = PR_FALSE; + } + return NS_OK; +} + +nsresult +ipcTransport::Connect() +{ + nsresult rv; + + LOG((">>> ipcTransport::Connect\n")); + + if (++mConnectionAttemptCount > 20) { + LOG((">>> giving up after 20 unsuccessful connection attempts\n")); + return NS_ERROR_ABORT; + } + + rv = CreateTransport(); + if (NS_FAILED(rv)) return rv; + + rv = mTransport->AsyncRead(&mReceiver, nsnull, 0, PRUint32(-1), 0, + getter_AddRefs(mReadRequest)); + return rv; +} + +void +ipcTransport::OnMsgAvailable(const ipcMessage *msg) +{ + LOG((">>> ipcTransport::OnMsgAvailable [dataLen=%u]\n", msg->DataLen())); + + // + // all IPCM messages stop here. + // + if (msg->Target().Equals(IPCM_TARGET)) { + // + // check for startup PING + // + if (!mHaveConnection) { + if (IPCM_GetMsgType(msg) == IPCM_MSG_PING) { + LOG((">>> connection established!\n")); + mHaveConnection = PR_TRUE; + // + // move messages off the delayed queue + // + while (!mDelayedQ.IsEmpty()) { + ipcMessage *msg = mDelayedQ.First(); + mDelayedQ.RemoveFirst(); + SendMsg_Internal(msg); + } + } + else + LOG((">>> received bogus response to our ping!\n")); + } + } + else if (mObserver) + mObserver->OnMsgAvailable(msg); +} + +void +ipcTransport::OnStartRequest(nsIRequest *req) +{ + nsresult status; + req->GetStatus(&status); + + if (NS_SUCCEEDED(status) && !mHaveConnection && !mSentInitialMsgs) { + // + // send "startup messages" + // + // PING - expect a PING in response to this message + // CNAME - expect nothing in response to this message + // + SendMsg_Internal(new ipcmMessagePING()); + SendMsg_Internal(new ipcmMessageCNAME("test-app")); // XXX need real client name + + mSentInitialMsgs = PR_TRUE; + } +} + +void +ipcTransport::OnStopRequest(nsIRequest *req, nsresult status) +{ + LOG((">>> ipcTransport::OnStopRequest [status=%x]\n", status)); + + if (status == NS_BINDING_ABORTED) + return; + + if (NS_FAILED(status) && !mTimer) { + nsresult rv; + // + // connection failure + // + rv = SpawnDaemon(); + if (NS_FAILED(rv)) { + LOG((">>> failed to spawn daemon [rv=%x]\n", rv)); + return; + } + + // + // re-initialize connection after timeout + // + mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + LOG((">>> failed to create timer [rv=%x]\n", rv)); + return; + } + + // use a simple exponential growth algorithm n*2^(n-1) + PRUint32 ms = 1000 * (1 << (mConnectionAttemptCount - 1)); + + LOG((">>> waiting %u milliseconds\n", ms)); + + rv = mTimer->Init(this, ms, nsITimer::TYPE_ONE_SHOT); + if (NS_FAILED(rv)) { + LOG((">>> failed to initialize timer [rv=%x]\n", rv)); + return; + } + } + + if (req == mReadRequest) + mReadRequest = nsnull; + else if (req == mWriteRequest) { + mWriteRequest = nsnull; + mWriteSuspended = PR_FALSE; + } +} + +nsresult +ipcTransport::CreateTransport() +{ + nsresult rv; + + nsCOMPtr sts( + do_GetService(kSocketTransportServiceCID, &rv)); + if (NS_FAILED(rv)) return rv; + + rv = sts->CreateTransportOfType(IPC_SOCKET_TYPE, + "127.0.0.1", + IPC_PORT, + nsnull, + 1024, + 1024*16, + getter_AddRefs(mTransport)); + if (NS_FAILED(rv)) return rv; + +#ifndef IPC_USE_INET + nsCOMPtr st(do_QueryInterface(mTransport, &rv)); + if (NS_FAILED(rv)) return rv; + + PRNetAddr addr; + addr.local.family = PR_AF_LOCAL; + PL_strncpyz(addr.local.path, mSocketPath.get(), sizeof(addr.local.path)); + + rv = st->SetAddress(&addr); +#endif + return rv; +} + +nsresult +ipcTransport::SpawnDaemon() +{ + LOG((">>> ipcTransport::SpawnDaemon\n")); + + nsresult rv; + nsCOMPtr file; + + rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, getter_AddRefs(file)); + if (NS_FAILED(rv)) return rv; + + rv = file->AppendNative(NS_LITERAL_CSTRING(IPC_DAEMON_APP_NAME)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr proc(do_CreateInstance(NS_PROCESS_CONTRACTID,&rv)); + if (NS_FAILED(rv)) return rv; + + rv = proc->Init(file); + if (NS_FAILED(rv)) return rv; + + PRUint32 pid; + return proc->Run(PR_FALSE, nsnull, 0, &pid); +} + +NS_IMPL_THREADSAFE_ISUPPORTS0(ipcTransport) + +NS_IMETHODIMP +ipcTransport::Observe(nsISupports *subject, const char *topic, const PRUnichar *data) +{ + LOG((">>> ipcTransport::Observe [topic=%s]\n", topic)); + + if (strcmp(topic, "timer-callback") == 0) { + // + // try reconnecting to the daemon + // + Shutdown(); + Connect(); + + mTimer = nsnull; + } + else if (strcmp(topic, "xpcom-shutdown") == 0 || + strcmp(topic, "profile-change-net-teardown") == 0) + Shutdown(); + + return NS_OK; +} + +//----------------------------------------------------------------------------- +// ipcSendQueue +//----------------------------------------------------------------------------- + +NS_IMETHODIMP_(nsrefcnt) +ipcSendQueue::AddRef() +{ + return mTransport->AddRef(); +} + +NS_IMETHODIMP_(nsrefcnt) +ipcSendQueue::Release() +{ + return mTransport->Release(); +} + +NS_IMPL_QUERY_INTERFACE2(ipcSendQueue, nsIStreamProvider, nsIRequestObserver) + +NS_IMETHODIMP +ipcSendQueue::OnStartRequest(nsIRequest *request, + nsISupports *context) +{ + LOG((">>> ipcSendQueue::OnStartRequest\n")); + + if (mTransport) + mTransport->OnStartRequest(request); + + return NS_OK; +} + +NS_IMETHODIMP +ipcSendQueue::OnStopRequest(nsIRequest *request, + nsISupports *context, + nsresult status) +{ + LOG((">>> ipcSendQueue::OnStopRequest [status=%x]\n", status)); + + if (mTransport) + mTransport->OnStopRequest(request, status); + + return NS_OK; +} + +struct ipcWriteState +{ + ipcMessage *msg; + PRBool complete; +}; + +static NS_METHOD ipcWriteMessage(nsIOutputStream *stream, + void *closure, + char *segment, + PRUint32 offset, + PRUint32 count, + PRUint32 *countWritten) +{ + ipcWriteState *state = (ipcWriteState *) closure; + + if (state->msg->WriteTo(segment, count, + countWritten, &state->complete) != PR_SUCCESS) + return NS_ERROR_UNEXPECTED; + + return NS_OK; +} + +NS_IMETHODIMP +ipcSendQueue::OnDataWritable(nsIRequest *request, + nsISupports *context, + nsIOutputStream *stream, + PRUint32 offset, + PRUint32 count) +{ + PRUint32 n; + nsresult rv; + ipcWriteState state; + PRBool wroteSomething = PR_FALSE; + + LOG((">>> ipcSendQueue::OnDataWritable\n")); + + while (!mQueue.IsEmpty()) { + state.msg = mQueue.First(); + state.complete = PR_FALSE; + + rv = stream->WriteSegments(ipcWriteMessage, &state, count, &n); + if (NS_FAILED(rv)) + break; + + if (state.complete) { + LOG((">>> wrote message %u bytes\n", mQueue.First()->MsgLen())); + mQueue.DeleteFirst(); + } + + wroteSomething = PR_TRUE; + } + + if (wroteSomething) + return NS_OK; + + LOG((">>> suspending write request\n")); + + mTransport->SetWriteSuspended(PR_TRUE); + return NS_BASE_STREAM_WOULD_BLOCK; +} + +//---------------------------------------------------------------------------- +// ipcReceiver +//---------------------------------------------------------------------------- + +NS_IMETHODIMP_(nsrefcnt) +ipcReceiver::AddRef() +{ + return mTransport->AddRef(); +} + +NS_IMETHODIMP_(nsrefcnt) +ipcReceiver::Release() +{ + return mTransport->Release(); +} + +NS_IMPL_QUERY_INTERFACE2(ipcReceiver, nsIStreamListener, nsIRequestObserver) + +NS_IMETHODIMP +ipcReceiver::OnStartRequest(nsIRequest *request, + nsISupports *context) +{ + LOG((">>> ipcReceiver::OnStartRequest\n")); + + if (mTransport) + mTransport->OnStartRequest(request); + + return NS_OK; +} + +NS_IMETHODIMP +ipcReceiver::OnStopRequest(nsIRequest *request, + nsISupports *context, + nsresult status) +{ + LOG((">>> ipcReceiver::OnStopRequest [status=%x]\n", status)); + + if (mTransport) + mTransport->OnStopRequest(request, status); + + return NS_OK; +} + +static NS_METHOD ipcReadMessage(nsIInputStream *stream, + void *closure, + const char *segment, + PRUint32 offset, + PRUint32 count, + PRUint32 *countRead) +{ + ipcReceiver *receiver = (ipcReceiver *) closure; + return receiver->ReadSegment(segment, count, countRead); +} + +NS_IMETHODIMP +ipcReceiver::OnDataAvailable(nsIRequest *request, + nsISupports *context, + nsIInputStream *stream, + PRUint32 offset, + PRUint32 count) +{ + LOG((">>> ipcReceiver::OnDataAvailable [count=%u]\n", count)); + + PRUint32 countRead; + return stream->ReadSegments(ipcReadMessage, this, count, &countRead); +} + +nsresult +ipcReceiver::ReadSegment(const char *ptr, PRUint32 count, PRUint32 *countRead) +{ + *countRead = 0; + while (count) { + PRUint32 nread; + PRBool complete; + + mMsg.ReadFrom(ptr, count, &nread, &complete); + + if (complete) { + mTransport->OnMsgAvailable(&mMsg); + mMsg.Reset(); + } + + count -= nread; + ptr += nread; + *countRead += nread; + } + + return NS_OK; +} diff --git a/modules/ipc/src/ipcTransport.h b/modules/ipc/src/ipcTransport.h new file mode 100644 index 000000000000..e9ac2ef0de05 --- /dev/null +++ b/modules/ipc/src/ipcTransport.h @@ -0,0 +1,177 @@ +/* ***** 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 + * + * 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 ipcTransport_h__ +#define ipcTransport_h__ + +#include "nsIObserver.h" +#include "nsIStreamListener.h" +#include "nsIStreamProvider.h" +#include "nsITransport.h" +#include "nsITimer.h" +#include "nsString.h" +#include "nsCOMPtr.h" +#include "prio.h" + +#include "ipcMessage.h" +#include "ipcMessageQ.h" + +class ipcTransport; + +//---------------------------------------------------------------------------- +// ipcTransportObserver interface +//---------------------------------------------------------------------------- + +class ipcTransportObserver +{ +public: + virtual void OnMsgAvailable(const ipcMessage *) = 0; +}; + +//---------------------------------------------------------------------------- +// ipcSendQueue +//---------------------------------------------------------------------------- + +class ipcSendQueue : public nsIStreamProvider +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMPROVIDER + + ipcSendQueue(ipcTransport *transport) + : mTransport(transport) + { } + virtual ~ipcSendQueue() { } + + void EnqueueMsg(ipcMessage *msg) { mQueue.Append(msg); } + + PRBool IsEmpty() { return mQueue.IsEmpty(); } + +private: + ipcTransport *mTransport; + ipcMessageQ mQueue; +}; + +//----------------------------------------------------------------------------- +// ipcReceiver +//----------------------------------------------------------------------------- + +class ipcReceiver : public nsIStreamListener +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + + ipcReceiver(ipcTransport *transport) + : mTransport(transport) + { } + virtual ~ipcReceiver() { } + + nsresult ReadSegment(const char *, PRUint32 count, PRUint32 *countRead); + +private: + ipcTransport *mTransport; + ipcMessage mMsg; // message in progress +}; + +//----------------------------------------------------------------------------- +// ipcTransport +//----------------------------------------------------------------------------- + +class ipcTransport : public nsIObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + ipcTransport() + : mSendQ(this) + , mReceiver(this) + , mObserver(nsnull) + , mFD(nsnull) + , mWriteSuspended(PR_FALSE) + , mSentInitialMsgs(PR_FALSE) + , mHaveConnection(PR_FALSE) + , mConnectionAttemptCount(0) + { } + virtual ~ipcTransport(); + + nsresult Init(const nsACString &socketPath, ipcTransportObserver *); + nsresult Shutdown(); + + // takes ownership of |msg| + nsresult SendMsg(ipcMessage *msg); + +public: + // internal to implementation + void OnMsgAvailable(const ipcMessage *); + void SetWriteSuspended(PRBool val) { mWriteSuspended = val; } + void OnStartRequest(nsIRequest *req); + void OnStopRequest(nsIRequest *req, nsresult status); + PRFileDesc *FD() { return mFD; } + +private: + // + // helpers + // + nsresult Connect(); + nsresult SendMsg_Internal(ipcMessage *msg); + nsresult CreateTransport(); + nsresult SpawnDaemon(); + + // + // data + // + ipcSendQueue mSendQ; + ipcReceiver mReceiver; + ipcMessageQ mDelayedQ; + ipcTransportObserver *mObserver; + nsCOMPtr mTransport; + nsCOMPtr mReadRequest; + nsCOMPtr mWriteRequest; + nsCOMPtr mTimer; + nsCString mSocketPath; + PRFileDesc *mFD; + PRPackedBool mWriteSuspended; + PRPackedBool mSentInitialMsgs; + PRPackedBool mHaveConnection; + PRUint8 mConnectionAttemptCount; +}; + +#endif // !ipcTransport_h__ diff --git a/modules/ipc/test/Makefile.in b/modules/ipc/test/Makefile.in new file mode 100644 index 000000000000..0710315ca4f8 --- /dev/null +++ b/modules/ipc/test/Makefile.in @@ -0,0 +1,54 @@ +# +# The contents of this file are subject to the Netscape 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/NPL/ +# +# 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.org code. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = test_ipc +REQUIRES = xpcom \ + string \ + ipc \ + $(NULL) + +CPPSRCS = \ + TestIPC.cpp \ + $(NULL) + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +LIBS = \ + $(EXTRA_DSO_LIBS) \ + $(MOZ_JS_LIBS) \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../util \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/modules/ipc/test/TestIPC.cpp b/modules/ipc/test/TestIPC.cpp new file mode 100644 index 000000000000..d24432ba24f8 --- /dev/null +++ b/modules/ipc/test/TestIPC.cpp @@ -0,0 +1,207 @@ +/* ***** 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 + * + * 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 "ipcIService.h" +#include "nsIEventQueueService.h" +#include "nsIServiceManager.h" +#include "nsIComponentRegistrar.h" +#include "nsLiteralString.h" + +static const nsID TestTargetID = +{ /* e628fc6e-a6a7-48c7-adba-f241d1128fb8 */ + 0xe628fc6e, + 0xa6a7, + 0x48c7, + {0xad, 0xba, 0xf2, 0x41, 0xd1, 0x12, 0x8f, 0xb8} +}; + +#define RETURN_IF_FAILED(rv, step) \ + PR_BEGIN_MACRO \ + if (NS_FAILED(rv)) { \ + printf("*** %s failed: rv=%x\n", step, rv); \ + return rv;\ + } \ + PR_END_MACRO + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); +static nsIEventQueue* gEventQ = nsnull; +static PRBool gKeepRunning = PR_TRUE; +static PRInt32 gMsgCount = 0; + +class myIpcMessageObserver : public ipcIMessageObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_IPCIMESSAGEOBSERVER + + myIpcMessageObserver() + { + NS_INIT_ISUPPORTS(); + } +}; + +NS_IMPL_ISUPPORTS1(myIpcMessageObserver, ipcIMessageObserver) + +NS_IMETHODIMP +myIpcMessageObserver::OnMessageAvailable(const nsID &target, const char *data, PRUint32 dataLen) +{ + printf("*** got message: [%s]\n", data); + + if (--gMsgCount == 0) + gKeepRunning = PR_FALSE; + + return NS_OK; +} + +void SendMsg(ipcIService *ipc, const nsID &target, const char *data, PRUint32 dataLen) +{ + printf("*** sending message: [dataLen=%u]\n", dataLen); + + ipc->SendMessage(target, data, dataLen); + gMsgCount++; +} + +int main(int argc, char **argv) +{ + nsresult rv; + + { + nsCOMPtr servMan; + NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + if (registrar) + registrar->AutoRegister(nsnull); + + // Create the Event Queue for this thread... + nsCOMPtr eqs = + do_GetService(kEventQueueServiceCID, &rv); + RETURN_IF_FAILED(rv, "do_GetService(EventQueueService)"); + + rv = eqs->CreateMonitoredThreadEventQueue(); + RETURN_IF_FAILED(rv, "CreateMonitoredThreadEventQueue"); + + rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); + RETURN_IF_FAILED(rv, "GetThreadEventQueue"); + + nsCOMPtr ipcServ(do_GetService("@mozilla.org/ipc/service;1", &rv)); + RETURN_IF_FAILED(rv, "do_GetService(ipcServ)"); + + ipcServ->SetMessageObserver(TestTargetID, new myIpcMessageObserver()); + + const char *data = + "01 this is a really long message.\n" + "02 this is a really long message.\n" + "03 this is a really long message.\n" + "04 this is a really long message.\n" + "05 this is a really long message.\n" + "06 this is a really long message.\n" + "07 this is a really long message.\n" + "08 this is a really long message.\n" + "09 this is a really long message.\n" + "10 this is a really long message.\n" + "11 this is a really long message.\n" + "12 this is a really long message.\n" + "13 this is a really long message.\n" + "14 this is a really long message.\n" + "15 this is a really long message.\n" + "16 this is a really long message.\n" + "17 this is a really long message.\n" + "18 this is a really long message.\n" + "19 this is a really long message.\n" + "20 this is a really long message.\n" + "21 this is a really long message.\n" + "22 this is a really long message.\n" + "23 this is a really long message.\n" + "24 this is a really long message.\n" + "25 this is a really long message.\n" + "26 this is a really long message.\n" + "27 this is a really long message.\n" + "28 this is a really long message.\n" + "29 this is a really long message.\n" + "30 this is a really long message.\n" + "31 this is a really long message.\n" + "32 this is a really long message.\n" + "33 this is a really long message.\n" + "34 this is a really long message.\n" + "35 this is a really long message.\n" + "36 this is a really long message.\n" + "37 this is a really long message.\n" + "38 this is a really long message.\n" + "39 this is a really long message.\n" + "40 this is a really long message.\n" + "41 this is a really long message.\n" + "42 this is a really long message.\n" + "43 this is a really long message.\n" + "44 this is a really long message.\n" + "45 this is a really long message.\n" + "46 this is a really long message.\n" + "47 this is a really long message.\n" + "48 this is a really long message.\n" + "49 this is a really long message.\n" + "50 this is a really long message.\n" + "51 this is a really long message.\n" + "52 this is a really long message.\n" + "53 this is a really long message.\n" + "54 this is a really long message.\n" + "55 this is a really long message.\n" + "56 this is a really long message.\n" + "57 this is a really long message.\n" + "58 this is a really long message.\n" + "59 this is a really long message.\n" + "60 this is a really long message.\n"; + SendMsg(ipcServ, TestTargetID, data, strlen(data)+1); + + while (gKeepRunning) + gEventQ->ProcessPendingEvents(); + + printf("*** processing remaining events\n"); + + // process any remaining events + PLEvent *ev; + while (NS_SUCCEEDED(gEventQ->GetEvent(&ev)) && ev) + gEventQ->HandleEvent(ev); + + printf("*** done\n"); + } // this scopes the nsCOMPtrs + + // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM + rv = NS_ShutdownXPCOM(nsnull); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); + + return 0; +} diff --git a/modules/ipc/testmodule/Makefile.in b/modules/ipc/testmodule/Makefile.in new file mode 100644 index 000000000000..2145079e264d --- /dev/null +++ b/modules/ipc/testmodule/Makefile.in @@ -0,0 +1,84 @@ +# ***** 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 +# +# 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 = testmodule +LIBRARY_NAME = testmodule +EXPORT_LIBRARY = 1 +IS_COMPONENT = 1 +MODULE_NAME = testmodule +REQUIRES = xpcom \ + ipc \ + $(NULL) + +CPPSRCS = TestModule.cpp + +SHARED_LIBRARY_LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)ipccom_s.$(LIB_SUFFIX) \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../common \ + $(NULL) + +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +EXTRA_DSO_LIBS = mozipcd +endif + +EXTRA_DSO_LDOPTS = \ + $(LIBS_DIR) \ + $(NSPR_LIBS) \ + $(EXTRA_DSO_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +_IPC_FILES = \ + $(LIB_PREFIX)$(LIBRARY_NAME)$(DLL_SUFFIX) \ + $(NULL) + +libs:: $(_IPC_FILES) + $(INSTALL) $^ $(DIST)/bin/ipc/modules + +install:: $(_IPC_FILES) + $(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/ipc/modules diff --git a/modules/ipc/testmodule/TestModule.cpp b/modules/ipc/testmodule/TestModule.cpp new file mode 100644 index 000000000000..521bf3f2d979 --- /dev/null +++ b/modules/ipc/testmodule/TestModule.cpp @@ -0,0 +1,51 @@ +#include +#include "nscore.h" +#include "ipcModule.h" +#include "ipcMessage.h" +#include "ipcd.h" + +extern "C" NS_EXPORT ipcModule **IPC_GetModuleList(); + +static const nsID TestModuleID = +{ /* e628fc6e-a6a7-48c7-adba-f241d1128fb8 */ + 0xe628fc6e, + 0xa6a7, + 0x48c7, + {0xad, 0xba, 0xf2, 0x41, 0xd1, 0x12, 0x8f, 0xb8} +}; + +class TestModule : public ipcModule +{ +public: + void Shutdown() + { + printf("*** TestModule::Shutdown\n"); + } + + const nsID &ID() + { + printf("*** TestModule::ID\n"); + return TestModuleID; + } + + void HandleMsg(ipcClient *client, const ipcMessage *msg) + { + printf("*** TestModule::HandleMsg [%s]\n", msg->Data()); + ipcMessage *outMsg = new ipcMessage(); + static const char buf[] = "pong"; + outMsg->Init(TestModuleID, buf, sizeof(buf)); + IPC_SendMsg(client, outMsg); + } +}; + +ipcModule ** +IPC_GetModuleList() +{ + static TestModule testMod; + static ipcModule *modules[2]; + + modules[0] = &testMod; + modules[1] = NULL; + + return modules; +}